TXT SDK For iOS(1.2.0.0)说明

1. 简介

最新版下载地址:http://www./download/pages/txtsdk/ios.html

TXTSDK.framwork是优看科技出品的iOS平台下TXT阅读器底层程序库,提供TXT阅读器最基础的功能,适合需要高级定制功能的开发者。如果无需高级定制功能,可使用本公司另一款快速开发阅读器的产品:ReaderSDK for iOS。

  • 支持翻页动画:滑动,仿真,简洁。

  • 支持设置字体。

  • 支持设置行间距。

  • 支持设置文字颜色,背景色。

  • 支持夜间模式。

  • 支持搜索。

  • 支持文字选择,添加笔记,显示书签等操作。

  • 支持目录提取(可自定义)。

  • 支持页面缩放。

  • 支持其他基本阅读功能。

  • 支持文件格式:TXT。

  • 支持语言:Objective-c。

  • 支持最低系统:ios 8.0。

  • 开发工具:xcode 8.2.1。

  • 接口主要分2类:TextViewController类接口和TextViewControllerDelegate回调接口。

2. 在xcode中集成:

  1. 选择要集成的 targets,切换到 Build Phases 标签。

  2. Link Binary With Libaraies 中添加 TXTSDK.frameworkSecurity.framework

  3. Copy Bundle Resources 中添加 SDKResource.bundle

3. 具体接口调用流程(Objective-c代码为例)

调用sdk接口前,需要在app启动时注册sdk,否则sdk不可用。可以通过在线注册开发者账号,获取appKey和appSecret,详情请参考registerSDKWithAppKey函数的注意部分。注册示例代码:

// AppDelegate 回调函数
- (BOOL)application:(UIApplication *)application 
          didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [YCANPDFViewController registerSDKWithAppKey:@"5E2FADFEAE365427FFFF041412FE8C5"
        appSecret:@"13C49F0807DF56809E492DEF0CDCD"
        completeHandler:^(NSDictionary *info, NSError *error)
    {
        NSLog(@"info=%@, error=%@", info, error);
    }];
    return YES;
}

下面的示例程序以在UIViewController中的使用方式为来说明。首先读取TXT文件,得到TXT文本,然后创建TextViewController对象,最后显示TXT页面。由于TextViewController是UIViewController子类,可以像使用普通的UIViewController对象使用TextViewController实例对象。TextViewController包含了阅读TXT的所有基础功能,开发者需要自己设计使用这些功能的界面(如果无需高级定制功能,可使用本公司另一款快速开发阅读器的产品:ReaderSDK for iOS)。

注意: 需要引入头文件 <TXTSDK/TXTSDK.h>。

NSString *path = // txt file path
            NSData *data = [NSData dataWithContentsOfFile:path];
            // 打开一般中文txt文件时用到的编码
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *text = [[NSString alloc] initWithData:data encoding:encoding];
if( text == nil ){
    NSLog( @"text 编码未知" );
    return nil;
}

TextViewController *txt = [TextViewController instanceWithText:text];
txt.delegate = self;
txt.bookName = path.lastPathComponent.stringByDeletingPathExtension;
// 此处添加其他初始化代码...

[self addChildViewController:txt];
UIView *textView = _txt.view;
[self.view addSubview:textView];
[self.view sendSubviewToBack:textView];
[txt didMoveToParentViewController:self];

...

// txt 对象不再使用时,需要调用close接口,可能导致程序崩溃。
[txt close];

在用户阅读过程中,开发者可能需要知道用户的某些阅读行为。为此,开发者可以指定TextViewController对象的delegate 并实现TextViewControllerDelegate协议即可。细节请参考TextViewControllerDelegate说明

4. 接口说明

1.TextViewController类接口

TextViewController 定义如下:(摘自TXTSDK.h)

@interface TextViewController : UIViewController
                    // register sdk api
+(void)registerSDKWithAppKey:(NSString*)appKey
    appSecret:(NSString*)appSecret
    completeHandler:(void(^)(NSDictionary* info, NSError *error))completeHandler;
+(instancetype)instanceWithText:(NSString*)text;
+(NSString*)version;
-(void)close;
-(void)gotoOffest:(NSUInteger)offset animate:(BOOL)animate;
-(void)update;
-(void)searchWithKeyword:(NSString*)keyword;
-(void)searchMoreResules;
-(void)showSearResultWithSearchItem:(TextSearchItem*)searchItem;
-(void)searchNext;-(void)searchPrev;
-(void)cancelSearchWithFinishHandle:(void(^)(NSString* keyword))finishHandle;
@property (nonatomic, strong, readonly) NSArray<TextSearchItem*>* searchResultArray;
@property (nonatomic, assign, readonly) BOOL isSearching;
@property (nonatomic, assign) id<TextViewControllerDelegate> delegate;
@property (nonatomic, strong) NSString *bookName;
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, strong) UIColor *textColor;
@property (nonatomic, strong) UIColor *textBkgndColor;
@property (nonatomic, assign) CGFloat lineSpacing;
@property (nonatomic, assign) BOOL isNightMode;
@property (nonatomic, assign) TxtPageFlipMode pageFlipMode;
@property (nonatomic, strong) NSMutableArray<TextAnnotItem*> *annotArray;
@property (nonatomic, strong, readonly) NSString *text;
@property (nonatomic, strong, readonly) NSArray<TextOutlineItem*>* outlineArray;
@property (nonatomic, assign, readonly) NSRange currentPageRange;
@property (nonatomic, assign, readonly) NSUInteger currentPageNum;
@property (nonatomic, assign, readonly) NSUInteger pageCount;
@end

接口详细说明:。

  • 注册开发者账号时请注意:填写的 Bundle ID 必须要与 app 的 Bundle ID 一致。

  • app Bundle ID 获取方法:

  • 调用方式和时机,请参考:注册SDK代码示例

    1. 选中app target

    2. 切换到 General标签。

    3. 展开IdentifyBundle Identifier 的值就是要填的 Bundle ID

    2. +(instancetype)instanceWithText:(NSString*)text;

    • 功能:

      获取TextViewController类对象。

    • 参数:

      text txt文本。

    • 返回值:

      成功返回TextViewController对象,失败返回 nil。只要text.length不为0,返回值将不为nil。

    • 注意:

      此接口是唯一获取TextViewController对象的接口,请不要使用其他UIVeiewController类获取对象的接口,否则得到的对象的所有行为是未定义的。

    3. +(NSString*)version;

    • 功能:

      返回SDK版本号。

    • 参数:

      无。

    • 返回值:

      SDK版本号, 如:1.0.0.0。

    4. -(void)close;

    • 功能:

      停止所有可能的后台异步计算。

    • 参数:

      无。

    • 返回值:

      无。

    • 注意:

      如果TextViewController对象不再使用,请调用close接口,以停止可能存在的后台异步计算,否则可能引起程序崩溃。

    5. -(void)gotoOffest:(NSUInteger)offset animate:(BOOL)animate;

    • 功能:

      跳转到某页页面。

    • 参数:

      offset 指定跳转到某页面偏移量,起始页偏移量为0。

      animate 是否有翻页动画,YES为有,反之为无。

    • 返回值:

      无。

    • 注意:

      txt没有页码的概念,随着txt字体大小,行间距等的动态改变,相同的页码中的文字内容可能完全不同,比如说同样是第10页,文字变小后,新的第10页的内容可能是原来第15-16页的内容,使用偏移量可避免这种情况。

    6. -(void)update;

    • 功能:

      刷新页面。

    • 参数:

      无。

    • 返回值:

      无。

    • 注意:

      此接口将强制SDK调用某些delegate回掉函数。

    7. -(void)searchWithKeyword:(NSString*)keyword;

    8. -(void)searchMoreResules;

    • 功能:

      通知后台搜索更多的结果。

    • 参数:

      无。

    • 返回值:

    • 注意:

      调用后,后台会从最后一次暂停的位置开始,继续执行搜索,如果到了结果,将引发txt:hasSearchedMoreResultsByKeyword:接口回调,结果会追加到searchResultArray中,后台搜索暂停;若需要得到更多的结果,请调用searchMoreResules接口;如果搜索完所有页面,将引发txt:canNotSearchMoreResultsByKeyWord:接口回调, 后台搜索结束;若已经搜到了文件尾,TextViewController不会执行任何操作。

    9. -(void)showSearResultWithSearchItem:(TextSearchItem*)searchItem;

    • 功能:

      显示搜到的某一项结果。

    • 参数:

      searchItem searchResultArray中的对象。

    • 返回值:

      无。

    • 注意:

      调用后,TextViewController对象将会以图形方式显示搜索结果所在页面的具体位置,然后 searchNext 或 searchPrev 才可用。

    10. -(void)searchNext;

    11. -(void)searchPrev;

    12. -(void)cancelSearchWithFinishHandle:(void(^)(NSString* keyword))finishHandle;

    • 功能:

      取消搜索,调用后页面搜索结果标将消失,后台搜索将停止,并清空searchResultArray。

    • 参数:

      finishHandle 后台搜索停止时,将会执行,可以为nil。

    • 返回值:

      无。

    • 注意:

      cancelSearchWithFinishHandle: 接口调用后,后台搜索不会立即停止,是异步的,为了某些避免意外情况,后台搜索在停止时,会调用finishHandle代码块。

    13. @property (nonatomic, strong, readonly) NSArray&ltTextSearchItem&gt searchResultArray;

    14. @property (nonatomic, assign, readonly) BOOL isSearching;

    • 功能:

      指示后台搜索是否正在执行。

    • 注意:

      后台搜索只能一次执行一个关键字搜索,而不能同时执行多个关键字搜索。

    15. @property (nonatomic, assign) id&ltTextViewControllerDelegate&gt delegate;

    • 功能:

      指定委托对象。

    • 注意:

      TextViewController对象的所有通知,都是通过此对象通知的,遵循TextViewControllerDelegate协议,详情请参考:TextViewControllerDelegate说明,                    可以为nil。

    16. @property (nonatomic, strong) NSString *bookName;

    • 功能:

      指定TXT书名。

    • 注意:

      TextViewController在显示TXT页面时,页面的左上角可能会用到。 可以为nil。

    17. @property (nonatomic, strong) UIFont *font;

    • 功能:

      获取/设定TXT字体。

    • 注意:

      font发生改时,页面会立刻自动显示所作的更改。

    18. @property (nonatomic, strong) UIColor *textColor;

    • 功能:

      获取/设定TXT文字颜色。

    • 注意:

      textColor发生改时,页面会立刻自动显示所作的更改。

    19. @property (nonatomic, strong) UIColor *textBkgndColor;

    • 功能:

      获取/设定TXT背景色。

    • 注意:

      textBkgndColor发生改时,页面会立刻自动显示所作的更改。

    20. @property (nonatomic, assign) CGFloat lineSpacing;

    • 功能:

      获取/设定TXT行间距,取值0-50。

    • 注意:

      lineSpacing发生改时,页面会立刻自动显示所作的更改。

    21. @property (nonatomic, assign) BOOL isNightMode;

    • 功能:

      设置页面是否为夜间模式。

    • 注意:

      isNightMode值为YES时,页面会立刻以夜间模式显示;为NO时,页面会立刻以非夜间模式显示。

    22. @property (nonatomic, assign) TxtPageFlipMode pageFlipMode;

    • 功能:

      设置/获取翻页方式。

    • 注意:

      支持的翻页方式,请参考:TxtPageFlipMode

    23. @property (nonatomic, strong) NSMutableArray&ltTextAnnotItem*&gt *annotArray;

    24. @property (nonatomic, strong, readonly) NSString *text

    • 功能:

      获取整个txt文本。

    • 注意:

      内容与instanceWithText:接口传入的内容相同。

    25. -(NSArray&ltTextOutlineItem&gt)outlineArray;

    • 功能:

      获取TXT目录。

    • 注意:

      TextOutlineItem数组,详情请参考:TextOutlineItem。 由于TXT目录是非标准的,不同的TXT文件,提取的规则可能有很大差异,如果内置的提取算法,无法满足开发着的要求,开发者可通过TextViewControllerDelegate自己实现,详情请参考:outlineArrayForTextViewController:

    26. @property (nonatomic, assign, readonly) NSRange currentPageRange;

    • 功能:

      获取当前正在显示的TXT页面范围。

    • 注意:

      currentPageRange是唯一精确确定TXT页面位置的方法。

    27. @property (nonatomic, assign, readonly) NSUInteger currentPageNum;

    • 功能:

      获取当前页的页码。

    • 注意: currentPageNum 是一个临时值,TXT刚打开时TextViewController进行后台分页,在没分页完成之前,currentPageNum 一直是0。在阅读期间,如果用户改变了字体大小,行间距等,都会引起后台分页动作,在未完成分页前,currentPageNum一直是0。后台分页的执行情况可通过TextViewControllerDelegate获得。详情请参考:txtPreparePaging:txtStartPaging:txt:pagingAtRange:txtEndPaging:txtPagingIsCanceled:

    28. @property (nonatomic, assign, readonly) NSUInteger pageCount;

    2. TextViewControllerDelegate

    TextViewControllerDelegate 定义如下:(摘自TXTSDK.h)。

    @class TextViewController;
    @protocol TextViewControllerDelegate &ltNSObject&gt
    @optional
    // page delegate
    // 当pageNum==0 表示pageNum无效,原因是后台还未完成分页。
    -(void)txtMayDoTransition:(TextViewController*)txt;
    -(void)txt:(TextViewController*)txt didTransitionToPageNum:(NSUInteger)pageNum pageRange:(NSRange)r;
    -(BOOL)txt:(TextViewController*)txt canShowBookmarkAtRange:(NSRange)r;
    -(void)txt:(TextViewController *)txt bookmarkDidClickedAtPageRange:(NSRange)r;
    -(NSUInteger)textOffsetForInitTxt:(TextViewController*)txt;
    
    // 若默认的目录提取算法无法满足你的需求,可通过定义此函数来自定义txt目录提取算法
    -(NSArray&ltTextOutlineItem*&gt*)outlineArrayForTextViewController:(TextViewController*)txt;
    
    // search list
    -(void)txt:(TextViewController*)txt hasSearchedMoreResultsByKeyword:(NSString*)keyword;
    -(void)txt:(TextViewController*)txt canNotSearchMoreResultsByKeyWord:(NSString *)keyword;
    
    // search delegate
    -(void)txt:(TextViewController*)txt searchKeyword:(NSString*)keyword willEnterBackgroundAtPageRange:(NSRange)r;
    -(void)txt:(TextViewController*)txt searchKeyword:(NSString*)keyword atPageRange:(NSRange)r;
    -(void)txt:(TextViewController*)txt searchKeyword:(NSString*)keyword isSearched:(BOOL)isSearched;
    
    // paging delegate
    // prepare->start->[n*paging]->end/cancel
    -(void)txtPreparePaging:(TextViewController *)txt;
    -(void)txtStartPaging:(TextViewController *)txt;
    -(void)txt:(TextViewController *)txt pagingAtRange:(NSRange)r;
    -(void)txtEndPaging:(TextViewController *)txt;
    -(void)txtPagingIsCanceled:(TextViewController *)txt;
    
    // annot delegate
    -(BOOL)txt:(TextViewController*)txt canCopyRange:(NSRange)r;
    -(BOOL)txt:(TextViewController*)txt canAddTextAnnotType:(TextAnnotType)type atRange:(NSRange)r;
    -(BOOL)txt:(TextViewController*)txt canRemoveTextAnnotItem:(TextAnnotItem*)annotItem;
    -(BOOL)txt:(TextViewController*)txt canShareTextAnnotItem:(TextAnnotItem*)annotItem;
    -(void)txt:(TextViewController*)txt shareTextAnnotItem:(TextAnnotItem*)annotItem;
    -(void)txt:(TextViewController*)txt didAddTextAnnotItem:(TextAnnotItem*)annotItem;
    -(void)txt:(TextViewController*)txt didRemoveTextAnnotItem:(TextAnnotItem*)annotItem;
    -(void)txt:(TextViewController*)txt didTextAnnotNoteChange:(TextAnnotItem*)annotItem;
    -(void)txt:(TextViewController *)txt didTextAnnotItemColorChange:(TextAnnotItem *)annotItem;@end

    协议接口详细说明:

    1. -(void)txtMayDoTransition:(TextViewController*)txt;

    • 说明:

      用户有翻页动作时触发调用。

    2. -(void)txt:(TextViewController*)txt didTransitionToPageNum:(NSUInteger)pageNum pageRange:(NSRange)r;

    • 说明:

      用户翻页后触发调用,如果分页未完成,pageNum的值一直为0。

    3. (BOOL)txt:(TextViewController*)txt canShowBookmarkAtRange:(NSRange)r;

    • 说明:

      渲染页面时会调用,若返回YES,r范围所在页将会显示书签,若返回NO,则不会显示书签。

    4. -(void)txt:(TextViewController *)txt bookmarkDidClickedAtPageRange:(NSRange)r;

    • 说明:

      用户点到页面上的书签时调用。

    5. -(NSUInteger)textOffsetForInitTxt:(TextViewController*)txt;

    • 说明:

      打开TXT文件时调用,询问最先显示TXT偏移位置。例如返回1000,TextViewController最先渲染并显示包含1000位置字符的页面;可以不实现,从而默认最先显示包含0位置字符的页面。

    6. -(NSArray<TextOutlineItem>)outlineArrayForTextViewController:(TextViewController*)txt;

    • 说明:

      用于自定义提取txt目录的方法。如果实现此接口,TextViewController将不执行默认的目录提取算法。outlineArray返回此接口返回的结果;如果不实现,TextViewController将执行默认的目录提取算法,outlineArray会返回默认算法的结果。

    7. -(void)txt:(TextViewController)txt hasSearchedMoreResultsByKeyword:(NSString)keyword;

    8. -(void)txt:(TextViewController*)txt canNotSearchMoreResultsByKeyWord:(NSString *)keyword;

    9. -(void)txt:(TextViewController)txt searchKeyword:(NSString)keyword willEnterBackgroundAtPageRange:(NSRange)r;

    • 说明:

      进入后台搜索时调用。可以不实现,详情请参考:searchNextsearchPrev

    10. -(void)txt:(TextViewController)txt searchKeyword:(NSString)keyword atPageRange:(NSRange)r;

    • 说明:

      后台搜索过程中会调用。可以不实现,详情请参考:searchNextsearchPrev

    11. -(void)txt:(TextViewController)txt searchKeyword:(NSString)keyword isSearched:(BOOL)isSearched;

    • 说明:

      后台搜索暂停时调用,参数isSearched指示出搜索暂停的原因,若为YES,表示搜到了结果。若为NO,表示已经搜到了文件头或文件尾,无法继续执行搜索了。可以不实现,详情请参考:searchNext 和 searchPrev

    12. -(void)txtPreparePaging:(TextViewController *)txt;

    • 说明:

      后台分页时,触发调用。提示后台线程开始准备分页。

    13. -(void)txtStartPaging:(TextViewController *)txt;

    • 说明:

      提示后台线程已经完成准备工作,开始分页了。

    14. -(void)txt:(TextViewController *)txt pagingAtRange:(NSRange)r;

    • 说明:

      提示后台线程分页的位置。每分完一页,调用一次。

    15. -(void)txtEndPaging:(TextViewController *)txt;

    • 说明:

      提示后台线程分页完成。

    16. -(void)txtPagingIsCanceled:(TextViewController *)txt;

    • 说明:

      提示后台线程分页被取消,取消的原因是,新的分页被触发,当前分页已无意义;TextViewController对象一次只能执行一个分页任务,不能同时执行多个分页任务。

    17. -(BOOL)txt:(TextViewController*)txt canCopyRange:(NSRange)r;

    • 说明:

      弹出菜单前调用,若返回NO,弹出的菜单将没有复制选项,反之则有。r范围是相对text的。

    • -(BOOL)txt:(TextViewController*)txt canAddTextAnnotType:(TextAnnotType)type atRange:(NSRange)r;

    • 说明:

      弹出菜单前调用,若返回NO,弹出的菜单将没有对应的注释类型选项,反之则有。r范围是相对text的。

    • -(BOOL)txt:(TextViewController)txt canRemoveTextAnnotItem:(TextAnnotItem)annotItem;

    • 说明:

      弹出菜单前调用,若返回NO,弹出的菜单将没有删除注释的选项,反之则有。

    20. -(BOOL)txt:(TextViewController)txt canShareTextAnnotItem:(TextAnnotItem)annotItem;

    • 说明:

      弹出菜单前调用,若返回NO,弹出的菜单将没有分享注释的选项。反之则有。

    21. -(void)txt:(TextViewController)txt shareTextAnnotItem:(TextAnnotItem)annotItem;

    • 说明:

      用户点击了分享菜单命令时调用,通知执行分享注释操作。

    22. -(void)txt:(TextViewController)txt didAddTextAnnotItem:(TextAnnotItem)annotItem;

    • 说明:

      用户添加注释时调用,通知删除注释操作。注意:TextViewController会自动维护annotArray

    23. -(void)txt:(TextViewController)txt didRemoveTextAnnotItem:(TextAnnotItem)annotItem;

    • 说明:

      用户删除注释时调用,通知删除注释操作。注意:TextViewController会自动维护annotArray

    24. -(void)txt:(TextViewController)txt didTextAnnotNoteChange:(TextAnnotItem)annotItem;

    • 说明:

      用户修改注释笔记时调用,通知修改注释操作。注意:TextViewController会自动维护annotArray

    25. -(void)txt:(TextViewController *)txt didTextAnnotItemColorChange:(TextAnnotItem *)annotItem;

    • 说明:

      用户修改注释颜色时调用,通知修改注释操作。注意:TextViewController会自动维护annotArray

    5. 结构定义

    1. TxtPageFlipMode(摘自TXTSDK.h)

    typedef NS_ENUM(NSUInteger, TxtPageFlipMode) {
        txt_page_flip_mode_none,           // 简洁(无)
        txt_page_flip_mode_simulation,     // 仿真
        txt_page_flip_mode_slide           // 滑动
    };

    2. TextAnnotType(摘自TXTSDK.h)

    typedef NS_ENUM(NSUInteger, TextAnnotType) {
        TextAnnotTypeSolidUnderline, // 实线下划线
        TextAnnotTypeWaveUnderline,  // 波浪下划线
        TextAnnotTypeDashUnderline,  // 虚线下划线
        TextAnnotTypeHeighlight      // 高亮
    };

    3. TextAnnotItem(摘自TXTSDK.h)

    // TextAnnotItem
    // 用于表示一个注释对象
    ///////////////////////////////////////////////////
    ///////////////////////////////////////////////////
    @interface TextAnnotItem : NSObject
    @property (nonatomic, assign) TextAnnotType type;    // 注释类型,支持高亮和下划线
    @property (nonatomic, assign) NSInteger ID;        // 本地注释id
    @property (nonatomic, assign) NSInteger annotID;   // 服务器注释id
    @property (nonatomic, strong) NSDate *addTime;      // 注释添加时间
    @property (nonatomic, strong) NSString *userNote;   // 用户笔记
    @property (nonatomic, strong) NSString *text;       // 注释包涵的文字
    @property (nonatomic, assign) NSInteger startIndex; // 起始文字索引
    @property (nonatomic, assign) NSInteger endIndex;   // 结束文字索引
    @property (nonatomic, assign) NSInteger argbAlpha;  // argb alpha(0-255)
    @property (nonatomic, assign) NSInteger argbRed;    // argb red(0-255)
    @property (nonatomic, assign) NSInteger argbGreen;  // argb green(0-255)
    @property (nonatomic, assign) NSInteger argbBlue;   // argb blue(0-255)
    // 以下属性在(type=下划线)下才有效
    @property (nonatomic, assign) NSInteger lineWidth;  // 线条宽
    @end

    4. TextOutlineItem(摘自TXTSDK.h)

    @interface TextOutlineItem : NSObject
    @property (nonatomic, strong) NSString *title;      // 目录标题
    @property (nonatomic, assign) NSRange range;        // 目录项所代表的范围
    @property (nonatomic, assign) NSUInteger level;     // 目录项的层次,从0开始
    @end

    5. TextSearchItem(摘自TXTSDK.h)

    //TextSearchItem
    ////////////////////////////////////////////////////
    ////////////////////////////////////////////////////
    @interface TextSearchItem : NSObject
    @property (nonatomic, strong) NSString *text;           // 包含搜索关键字的文本
    @property (nonatomic, assign) NSRange keywordRange;     // text中,关键字所在的位置
    @property (nonatomic, assign) NSUInteger page;          // 搜索所在页
    @property (nonatomic, assign) NSRange pageRange;        // 所在页的范围
    @property (nonatomic, strong) id context;               // 与搜索有关的内部信息,请勿做任何改动
    @end