iOS SDK开发

内容概述

SDK定义上是指软件开发包,对应iOS端来说就包含了库文件、头文件、资源文件等文件的集合。SDK开发就是在保证sdk源代码安全的情况,给开发者一个可方便快速接入的,兼容多个iOS系统、便于真机模拟器调试、可以上线AppStore的库。这句话包含的几个重要的信息将在本文中逐步详解。

本文将从iOS系统中SDK开发过程中需要考虑和注意这两方面入手,讲述SDK的设计:

1. 工程设置

2. 接口设计

3. SDK需要考虑的方面

4. checklist


工程设置

创建一个SDK工程通常通过下面方式:

目前SDK主流开发方式是第一种,即工程的产物提供framework,因为可以将库和头文件、资源都放在其中,当然可以选择第二种,工程的产物是静态库,如果分发需要将头文件与库一并提供。

对于framework来说,需要注意xcode6以后framework在Xcode默认配置的是动态库:

“Frameworks for iOS. iOS developers can now create dynamic frameworks. Frameworks are a collection of code and resources to encapsulate functionality that is valuable across multiple projects. Frameworks work perfectly with extensions, sharing logic that can be used by both the main application, and the bundled extensions.”

大意是xcode6(iOS8)后开发者可以创建自己的动态framework,其中包含可以跨工程使用的代码、资源。动态framework只能用于企业证书分发的ipa包中,对于上传appstore的所有产品必须使用静态framework,否则会被拒绝。但是系统提供的动态库dylib和framework是可以使用的,  更正为:iOS8开始,apple放开了动态库的使用,用户可以通过xcode创建动态库的framework,并且集成到app中,提交到appstore已经不会被拒绝。动态库和静态库的区别可参考之前的文章,  下图是静态framework的使用:

所以注意工程需要配置一下:


对于动态framework的使用稍有区别,需要单独将framework嵌入到ipa安装包中,因为动态库的特点就是运行时加载,所以app的可执行程序中并不会链接其使用的动态库,需要将动态库和可执行程序同时放在安装包中:


此工程编译打包出来的app文件中,如下图所示,会增加一个Frameworks文件夹,里面存放的正式嵌入的动态库:


接口设计

总体来说SDK接口设计和类的设计相似:

1. 首先需要根据SDK中模块划分根据“单一职责原则”、代码的依赖性分为不同的类;

所谓单一职责其实就是高内聚,保证一个类、一个接口只完成一个职责,不贪大贪全。

2. 接口设计也要满足“单一职责原则”;

例如即时通信的群组消息中一个群大概有群名称、群成员、群主、群头像、群主题等几个信息要素,我们设计接口时不能因为简便而用一个或两个接口提供所有这些信息,而是应该根据常见业务将上面信息分为以下接口: 获取群信息(群主、名称、头像), 获取群成员、获取群主题 这三个接口,或者根据情况将获取群信息分解为三个独立的接口。

这样设计的好处就是业务调用方可以根据实际情况某些case只调用其中一个接口,等到其他case再调用其他接口,这样可以保证每个接口的信息量没那么大,保证请求的及时响应和信息的及时展示。

3. 接口命名可读性强,拼写正确; 

要避免以下几种形式的接口命名:

`createGroup:(NSString *)title`

`GroupWithTitle:(NSString *)title`

`creatGroupWithTitle:(NSString *)title`

三种命名分别的问题是: 第一种命名没有对参数进行描述, 第二种命名没有对接口的动作进行描述,第三种命名create单词拼写错误。

所以一个正确的命名应该是保证拼写正确的情况下,按照(省略主语)谓宾这样的格式:

`createGroupWithTitle:(NSString *)title`

4. 接口参数校验:考虑用户使用情况,给予充分提示,减少问答

有些接口图方便可能设置成这样:

- (void)queryGroupMasterViaGroupId:(NSString *)groupId  requestSucess:(RequestGroupMasterSucess)success requestError:(void(^)(NSString *errorType)) error;

可以看出对于错误的反馈是通过参数error的block回调出来,block中的errorType对应错误信息,但这样的接口设计可能无法满足开发者的需求:只有错误描述字符串,实际开发者可能使用一个int型code用于判断错误性能更高,代码更清晰,即使直接将errorType字符串的错误以toast形式展示出来,这个字符串也有可能不是开发者实际想要的提示语。


所以最好的错误回调应该是至少包含错误码,最好包含错误描述(中英文两种),如下面例子:

-(void)requestGroupMasterViaGroupId:(NSString *)groupId  requestSucess:(RequestGroupMasterSucess)success requestError:(RequestGroupMasterError) error;

其中回调的枚举定义如下:

typedef void (^RequestGroupMasterError) (CMIMError * error);//获取群主详情失败回调

回调的参数是一个CMIMError实例:

@interface CMIMError : NSObject

@property (nonatomic, assign) CMIMErrorCode code;

@property (nonatomic, readwrite, copy) NSString *codeDescription;

@property (nonatomic, readwrite, copy) NSString *detailDescription;

+ (instancetype)errorWithCode:(CMIMErrorCode)aCode;

- (instancetype)initWithCode:(CMIMErrorCode)aCode;

从该实例的定义可知道,实例中包含错误码和错误简单描述、详细描述。


需要考虑的方面:

SDK开发就是在保证sdk源代码安全的情况,给开发者一个可方便快速接入的,兼容多个iOS系统、便于真机模拟器调试、可以上线AppStore的库。这句话包含的几个重要的信息将在本文中逐步详解。

还记得开篇时说的这个定义? 这个定义对应了下面几个需要注意的地方:

1. 必要调试信息

对于我们提供给别人的库,默认应该是关闭log选项的,但是有些时候为了协助客户或者开发者定位SDK中问题,可能需要log信息,这样我们在设计时需要在代码中配置log,可以参考大牛的框架,有整个log的各个级别的开关,控制log的总量和详细程度。

2. category、第三方库、类的命名、宏定义命名需要独一无二

我们xcode编译链接时经常会报出这样的错误:盗个图:

这类问题都是由于重复的定义导致,包括类名的同名、宏定义的同名、category的同名等,解决方法最简单的就是将同名之一改成其他名字,如果无法修改则需要通过lipo指令来解决。

3. 头文件、属性暴露合理

保证代码安全就是保证头文件暴露合理,并且头文件中只暴露开发者需要用到的属性(定义好readonly属性)和接口,这样可以保证开发者不会错误调用其他接口或属性使SDK内部状态或逻辑错乱。

4. 支持的最低系统

通过app可能根据用户群体有不同的最低系统支持,例如目前很多app已经不再支持ios8以下系统,但是SDK作为app的内核,需要保证不同客户的需求都能满足,所以SDK应该尽可能保证支持最低系统,一般到iOS6.

5. 支持模拟器调试

为了便于开发者调试,需要支持模拟器调试,所以在打包framework时需要有x86和i386版本,并通过lipo指令将二者合并到armv7 v7s arm64中去。

6. crash跟踪

为了及时定位客户使用SDK导致的crash,SDK中也要处理crash信息,并及时上报给我们。不建议使用友盟或bugly等商用SDK来收集crash,因为开发者一般也会集成这类SDK,所以很容易冲突,最好是自己写代码实现,原理首先是收集到程序的exception或signal,这时将相应的堆栈信息打印输出上传到服务器或者我们的邮箱中。


发布前checklist

为了保证每次上线的准确无误,必须制定一个完备的checklist,每次发布之前对照checklist来逐个检查,才能保证各项准备达到。下面列出几个基本的检查项:

1. 系统架构是否覆盖完全,

使用lipo指令查看支持的架构,模拟器是否支持? arm64必须支持,否则无法上架

2. 版本号及发布日志 

确定准确的版本号,并根据当前版本详细描述此次发布的更新点,这样方便开发者熟知改动的地方,便于评估对以前版本影响和使用新版本的成本,也便于我们定位问题。

3. log系统

关闭log输出,并屏蔽一些开发的调试代码或者提示框。对于一些尚不稳定的初始几个版本,由于问题比较多,开发者可以暂时打开log开关,这样在出现问题的时候便于定位,等一些版本后相对稳定之后,关闭log。

注意:日志需要制定相应的清除策略,最基本的包含每个log文件多大,最多几个log文件,log文件总大小达到多少时开始覆盖之前的文件等,其实这些方面大神的源码都考虑好了,直接用轮子更省心。

4. 冒烟测试

发布之前需对预发布版本进行主流程的测试,例如对于一个即时通信SDK需要测试普通消息互通、文件类消息互通、离线消息收取、apns推送正常、群消息正常等。


p.s. 本文提到的一些[命令]将在后面文章中单独讲一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容