James Yu


写了那么多的if else 依然未能参透其精髓。。。


SDK开发经验分享

入职以来一直负责SDK的开发工作。从第一个版本一直到现在,期间遇到了不少问题,踩过不少坑,也对接过不少集团内部SDK,对SDK开发也算有点微薄经验。本篇文章没啥干货,都是我在闲扯,平常上厕所时看看就可以扔了。。。

门面篇

SDK提供给别人使用的时候,第一印象很重要,直接影响到接入者对它的印象和心情。比如,我们经常听到周围同学接入一些SDK时候各种吐槽:包名和类前缀不一致,里面API命名怎么这么反人类,注释和方法对不上,回调怎么这么奇葩,怎么这么多参数设置等等。如果,我们真的接出现上面问题的SDK,我们心里肯定要咯噔下,大家第一反应不外乎以下几个单词:不靠谱不专业坑多。如果接入过程中,真的遇到个坑,那正好验证了之前的印象,顺便也加强下!

所以,不管里面质量咋样,这个门面很重要,一定要让接入方感觉很专业的样子。以下几个点,可以供大家参考:

  • 文件组织方式清晰明了

给别人的SDK,解压下来后第一眼就能够分辨出每个文件夹是什么作用。资源文件,文档,demo,库,应该很容易进行区分。特别是资源文件,能统一用bundle进行管理的,就不要出现bundle里面有,外面也有这种情况。

  • 类名前缀和包命名或者缩写要一致

接了一些SDK发现包名是xxx.framework, 类名前缀是bbbb, 无论是缩写还是正常思考方式都对不上。这个可以参考下系统如:UIKit类名前缀UICoreFoundation,类名前缀CF等等。建议包名大写字母开头,以驼峰命名方式。

  • 代码风格一定要一致

SDK接入者看不到你实现上屌炸天的代码,但是接口API暴露无遗。所以,在头文件中风格一定要统一!空格,回车,函数参数大小写等细节一定要去关注。曾经接入过一个SDK,感觉每一行代码都是不同人操刀的,让我这种代码强迫症者很崩溃(好吧,不要脸一把)。

  • 函数命名遵循共性,不要出现歧义或者违背大家的共识

命名这个问题,每个人都有自己的一套,个人认为只要自己保证一致,看起来也挺工整。但是一些共识大家还是需要去遵循的。比如init是用来生成对象的,不是用来设置生成好的对象属性的,这个是苹果和iOS开发一致认可的,就不要出现这种函数命名了。

  • 代码注释要规范和清楚

虽然SDK提供了文档,但是接入者不一定每次都仔细去看,所以接口里面的注释还是要认认真真写。对于注释的格式,以前是喵神的VVDocumenter,现在Xocde原生自带,正常用就好了。对于接口的入参,一定要说清楚,千万别出现说了一半,然后加了个链接:详细请参考XXXX

  • SDK功能正确,编译无警告和错误,支持最新的特性

发出去的SDK一定要经过完整测试,当然,这是废话!提供出去的SDK,应该做到无警告,配置好依赖的库后编译无错误。谁也不想见到接入SDK后工程一下子多了一堆警告。对于新的特性比如iOS的bitcode,iOS8之后开放的动态库,都应该积极去支持。

设计篇

一、易用性

SDK本身就是一些公用代码或者业务的整合,已经帮我们做了很多工作和隐藏了细节。如何让SDK易用,我觉得可以从以下几个点进行考虑:

  • SDK集成成本

接入SDK步骤都是添加SDK到工程,配置好依赖库和编译设置。对于一些复杂功能的SDK或者核心部分是C或者C++实现来说配置可能更多点。还好我们有cocoapods可以帮助我自动配置!如果能够支持cocoapods尽量都支持吧。

  • API调用简单

SDK好用不好用,看调用API就感受出来了。如果说接入方为了接一个功能,发现接入代码侵入了他们很多业务代码,那显然就是使用起来比较复杂的。开发最喜欢说的一句就是我都弄好了,你只要接下就好了,真的很简单!只要一行代码!理想情况下每个人喜欢这样的代码[PayManager payWithOrderId:@"xx"]

  • 功能可以定制

上面刚说只要一行代码,这边就要写好几行代码了!实际上,我们接入SDK,可能因为API完成的功能不能细分,UI不符合项目风格和要求,某些业务流程所限等原因,我们需要对SDK进行定制来达到要求。所以,对于这点,在SDK开发的时候,SDK架构设计上要考虑这个需求。如果让接入者考虑奇淫巧技来实现这个目的,那就gg了!

  • 便于调试

接入SDK肯定会遇到问题,因为SDK不是源码,所以接入者无法方便的进行调试。这个时候我们应该提供API,打印出SDK debug日志,给出一些提示性的信息,方便排查问题。

  • API回调参数明确

SDK调用完,我们需要处理结果。对于回调的参数类型model还是dictionary。个人还是比较偏向model,为什么呢?因为model编译的时候就可以检查而dictionary不行。并且modeldictionary更清楚,知道具体的参数。这点大家可以感受下微信支付和支付宝支付的回调参数。

  • API稳定

说实话,要做到这点还是有点难度的!SDK在开发前期,谁也不能保证未来API不会发生大的变动。特别是SDK业务初期快速迭代,可能每一版都会发生变化。但是,在SDK整体稳定后,大的功能API应该追求稳定。每次让接入者更新SDK和重新接入一个成本一样大,那估计得被吐槽死,以后都不想升级了。

二、API设计

个人觉得这个是SDK开发最纠结和最困难的环节!虽然我们每次都进行讨论和斟酌,有时候还是跟不上需求的变动。理想中的API设计,应该有种魔力,引导接入者去接入。或者能够和接入者开发经验或者接入其他SDK的经验产生共鸣,让他接入感觉很愉快。

下面就分享几点API设计踩过的坑和经验:

  • 参数命名一定要明确无歧义

参数的命名写长点,没关系!比如platformIdappPlatformId。当两个参数一起传的时候,就凌乱了。这个是我们SDK初期命名踩的最坑的一个地方!接入我们SDK很多人都不懂这两个参数有啥区别。这个设计之初是没问题的,只是后来需求变了!platfomrId真实含义是orderPlatformId!所以一个好的命名省不少事。

  • 自给自足,丰衣足食

SDK经常会采集一些接入方的数据,比如bundleID,appName,appVersion等信息。如果需要的信息能够自己获取,那就请珍惜接口每一个宝贵的入参位置。

  • SDK配置参数和接口入参分开

很多SDK在使用之前,可能需要设置基本参数,比如”key“,”productId“等。基本大家都是在appDelegate中调用类似[xx registerAPP:"appid"], [xx configSDKKey:"key"]进行初始化的。那这点为什么要说下呢?在设计SDK的初期,可能由于业务接口简单,需要的参数并不多,有时候直接当入参带进接口。如果未来入参更多,或者开放的API更多,又都用到了这个参数,并且在APP生命周期里面只要设置一次,那么可以考虑将其列为配置参数。

  • SDK参数:拼接的字符串

如果入参依赖后端的配置,那么直接使用类似URL query部分格式的字符串。比如支付宝支付的orderString: orderId=123&sign=28fhfh&sign_type=RSA 这类格式。未来扩展性比较高,而且所有版本都可以支持。

  • 同一类参数,封装成model,隐藏属性,通过方法构造

如果API参数过多,可以考虑将一类参数归为一类,减少入参个数,也便于以后进行扩展,保持主API稳定。对于归类好的参数,建议不要让接入者通过[[xxx alloc] init]生成对象,然后通过setter进行参数赋值。直接隐藏掉类属性,通过提供的便捷构造方法进行创建和赋值。这样做的好处是,在API参数升级的时候,如果新增的参数必传,可以在接入方升级的时候,只要需要改动参数构造的API。

  • API功能单一,减少类似enum的入参设计

一个API应该单一,入参中除特殊情况外,都不应该出现类似type,enum等入参形式。这类信息最好对接入者屏蔽。一个API承担的功能越多,未来改动的可能性越大。

  • 用于查询的属性,绝对不能直接设置

SDK会提供一些方法和属性,让接入者知道SDK的当前状态。常见的比如- (BOOL)islogin;@property(nonatomic, assign, readonly) BOOL isLogin;。方法可以隐藏属性,保证不被修改,如果是属性,一定要加readonly

  • API 回调设计

回调设计其实没啥好说的,delegate和block比较常见。根据场景自己决定一种。

开发篇

一、开发工具

对于iOS来说,就是个Xcode,但是考虑成工程搭建和打包的方便建议使用cocoapods和cocoapods-packager

搭建开发工程:

pod lib create xxx  

打包:

pod package xxx.spec  

完美配合!

二、开发和测试工程

SDK寄生在APP中,开发者需要搭建测试工程,去开发和模拟接入的真实情况。这边想说的就是开发一个测试工程,方便的进行测试和开发,工作量其实并不小。SDK里面能不写测试代码的都不要去写,写得越多,越容易出现发版没有关闭测试代码的情况。得益于OC是门动态语言,很多工具都可以以AOP的形式进行集成。

分享下我们SDK主要开发了哪些功能:

  • 网络环境自由切换,本地MOCK和远程一键切换
  • 日志系统,自由筛选不同日志
  • 测试账号一键切换
  • crash日志本地收集
  • 第三方调试工具:FLEX
  • 测试环境数据一键录入
  • 单元测试BDD,UI自动化

以上这些功能不仅可以方便开发和调试,也提高了测试同学的效率。

三、开发注意事项

由于SDK开发,很多东西没有开发APP那么爽,缺少了优秀的第三方,很多东西都要自己去造轮子!而且运行环境很恶劣!你不知道外面有多少黑科技在搞着你。

开发SDK的人可以注意下以下几个点:

  • 能用系统的API解决的,就不要使用第三方,减少对其他库的依赖
  • OC没有命名空间,类命名和类别方法加上前缀
  • 黑科技虽然好,但是能不用的就不要用
  • 多考虑第三方带来的影响,比如键盘处理,UIKit的UIAppearance等
  • 依赖其他SDK的,别打包在一起,不然出现符号表重复
  • 使用了OC类别打包的时候记得加上-ObjC
  • 能不用单例的就尽量少的使用
  • 核心代码的安全性
  • 资源文件使用bundle进行管理,能不用xib的就别用了吧

发货篇

万事俱备,就差包装好发货了。

  • SDK打包形式

    • Static Library
    • Dynamic Framework
    • Universal Framework
  • 版本控制

(major).(minor).(patch) 如3.8.1

  • 发布渠道

    • cocoapods
    • 邮件
    • 网站
  • 文档

    • 千万别word!!!
    • 图文并茂,依赖配置一定要注明清楚
  • demo

    • 复制demo代码,就可以完成接入了!!
  • 接入帮助

    • 技术支持联系方式
    • 接入群
    • GitHub issues
comments powered by Disqus