入職以來一直負責(zé)SDK的開發(fā)工作。從第一個版本一直到現(xiàn)在,期間遇到了不少問題,踩過不少坑,也對接過不少集團內(nèi)部SDK,對SDK開發(fā)也算有點微薄經(jīng)驗。本篇文章沒啥干貨,都是我在閑扯,平常上廁所時看看就可以扔了。。。
門面篇
SDK提供給別人使用的時候,第一印象很重要,直接影響到接入者對它的印象和心情。比如,我們經(jīng)常聽到周圍同學(xué)接入一些SDK時候各種吐槽:包名和類前綴不一致,里面API命名怎么這么反人類,注釋和方法對不上,回調(diào)怎么這么奇葩,怎么這么多參數(shù)設(shè)置等等。如果,我們真的接出現(xiàn)上面問題的SDK,我們心里肯定要咯噔下,大家第一反應(yīng)不外乎以下幾個單詞:不靠譜,不專業(yè),坑多。如果接入過程中,真的遇到個坑,那正好驗證了之前的印象,順便也加強下!
所以,不管里面質(zhì)量咋樣,這個門面很重要,一定要讓接入方感覺很專業(yè)的樣子。以下幾個點,可以供大家參考:
- 文件組織方式清晰明了
給別人的SDK,解壓下來后第一眼就能夠分辨出每個文件夾是什么作用。資源文件,文檔,demo,庫,應(yīng)該很容易進行區(qū)分。特別是資源文件,能統(tǒng)一用bundle進行管理的,就不要出現(xiàn)bundle里面有,外面也有這種情況。
- 類名前綴和包命名或者縮寫要一致
接了一些SDK發(fā)現(xiàn)包名是xxx.framework
, 類名前綴是bbbb
, 無論是縮寫還是正常思考方式都對不上。這個可以參考下系統(tǒng)如:UIKit
類名前綴UI
,CoreFoundation
,類名前綴CF
等等。建議包名大寫字母開頭,以駝峰命名方式。
- 代碼風(fēng)格一定要一致
SDK接入者看不到你實現(xiàn)上屌炸天的代碼,但是接口API暴露無遺。所以,在頭文件中風(fēng)格一定要統(tǒng)一!空格,回車,函數(shù)參數(shù)大小寫等細節(jié)一定要去關(guān)注。曾經(jīng)接入過一個SDK,感覺每一行代碼都是不同人操刀的,讓我這種代碼強迫癥者很崩潰(好吧,不要臉一把)。
- 函數(shù)命名遵循共性,不要出現(xiàn)歧義或者違背大家的共識
命名這個問題,每個人都有自己的一套,個人認為只要自己保證一致,看起來也挺工整。但是一些共識大家還是需要去遵循的。比如init是用來生成對象的,不是用來設(shè)置生成好的對象屬性的,這個是蘋果和iOS開發(fā)一致認可的,就不要出現(xiàn)這種函數(shù)命名了。
- 代碼注釋要規(guī)范和清楚
雖然SDK提供了文檔,但是接入者不一定每次都仔細去看,所以接口里面的注釋還是要認認真真寫。對于注釋的格式,以前是喵神的VVDocumenter
,現(xiàn)在Xocde原生自帶,正常用就好了。對于接口的入?yún)ⅲ欢ㄒf清楚,千萬別出現(xiàn)說了一半,然后加了個鏈接:詳細請參考XXXX。
- SDK功能正確,編譯無警告和錯誤,支持最新的特性
發(fā)出去的SDK一定要經(jīng)過完整測試,當(dāng)然,這是廢話!提供出去的SDK,應(yīng)該做到無警告,配置好依賴的庫后編譯無錯誤。誰也不想見到接入SDK后工程一下子多了一堆警告。對于新的特性比如iOS的bitcode,iOS8之后開放的動態(tài)庫,都應(yīng)該積極去支持。
設(shè)計篇
一、易用性
SDK本身就是一些公用代碼或者業(yè)務(wù)的整合,已經(jīng)幫我們做了很多工作和隱藏了細節(jié)。如何讓SDK易用,我覺得可以從以下幾個點進行考慮:
- SDK集成成本
接入SDK步驟都是添加SDK到工程,配置好依賴庫和編譯設(shè)置。對于一些復(fù)雜功能的SDK或者核心部分是C或者C++實現(xiàn)來說配置可能更多點。還好我們有cocoapods
可以幫助我自動配置!如果能夠支持cocoapods
盡量都支持吧。
- API調(diào)用簡單
SDK好用不好用,看調(diào)用API就感受出來了。如果說接入方為了接一個功能,發(fā)現(xiàn)接入代碼侵入了他們很多業(yè)務(wù)代碼,那顯然就是使用起來比較復(fù)雜的。開發(fā)最喜歡說的一句就是我都弄好了,你只要接下就好了,真的很簡單!只要一行代碼!理想情況下每個人喜歡這樣的代碼[PayManager payWithOrderId:@"xx"]
- 功能可以定制
上面剛說只要一行代碼,這邊就要寫好幾行代碼了!實際上,我們接入SDK,可能因為API完成的功能不能細分,UI不符合項目風(fēng)格和要求,某些業(yè)務(wù)流程所限等原因,我們需要對SDK進行定制來達到要求。所以,對于這點,在SDK開發(fā)的時候,SDK架構(gòu)設(shè)計上要考慮這個需求。如果讓接入者考慮奇淫巧技來實現(xiàn)這個目的,那就gg了!
- 便于調(diào)試
接入SDK肯定會遇到問題,因為SDK不是源碼,所以接入者無法方便的進行調(diào)試。這個時候我們應(yīng)該提供API,打印出SDK debug日志,給出一些提示性的信息,方便排查問題。
- API回調(diào)參數(shù)明確
SDK調(diào)用完,我們需要處理結(jié)果。對于回調(diào)的參數(shù)類型model
還是dictionary
。個人還是比較偏向model,為什么呢?因為model
編譯的時候就可以檢查而dictionary
不行。并且model
比dictionary
更清楚,知道具體的參數(shù)。這點大家可以感受下微信支付和支付寶支付的回調(diào)參數(shù)。
- API穩(wěn)定
說實話,要做到這點還是有點難度的!SDK在開發(fā)前期,誰也不能保證未來API不會發(fā)生大的變動。特別是SDK業(yè)務(wù)初期快速迭代,可能每一版都會發(fā)生變化。但是,在SDK整體穩(wěn)定后,大的功能API應(yīng)該追求穩(wěn)定。每次讓接入者更新SDK和重新接入一個成本一樣大,那估計得被吐槽死,以后都不想升級了。
二、API設(shè)計
個人覺得這個是SDK開發(fā)最糾結(jié)和最困難的環(huán)節(jié)!雖然我們每次都進行討論和斟酌,有時候還是跟不上需求的變動。理想中的API設(shè)計,應(yīng)該有種魔力,引導(dǎo)接入者去接入。或者能夠和接入者開發(fā)經(jīng)驗或者接入其他SDK的經(jīng)驗產(chǎn)生共鳴,讓他接入感覺很愉快。
下面就分享幾點API設(shè)計踩過的坑和經(jīng)驗:
- 參數(shù)命名一定要明確無歧義
參數(shù)的命名寫長點,沒關(guān)系!比如platformId
和appPlatformId
。當(dāng)兩個參數(shù)一起傳的時候,就凌亂了。這個是我們SDK初期命名踩的最坑的一個地方!接入我們SDK很多人都不懂這兩個參數(shù)有啥區(qū)別。這個設(shè)計之初是沒問題的,只是后來需求變了!platfomrId
真實含義是orderPlatformId
!所以一個好的命名省不少事。
- 自給自足,豐衣足食
SDK經(jīng)常會采集一些接入方的數(shù)據(jù),比如bundleID,appName,appVersion等信息。如果需要的信息能夠自己獲取,那就請珍惜接口每一個寶貴的入?yún)⑽恢谩?/p>
- SDK配置參數(shù)和接口入?yún)⒎珠_
很多SDK在使用之前,可能需要設(shè)置基本參數(shù),比如”key“,”productId“等。基本大家都是在appDelegate中調(diào)用類似[xx registerAPP:"appid"], [xx configSDKKey:"key"]
進行初始化的。那這點為什么要說下呢?在設(shè)計SDK的初期,可能由于業(yè)務(wù)接口簡單,需要的參數(shù)并不多,有時候直接當(dāng)入?yún)нM接口。如果未來入?yún)⒏啵蛘唛_放的API更多,又都用到了這個參數(shù),并且在APP生命周期里面只要設(shè)置一次,那么可以考慮將其列為配置參數(shù)。
- SDK參數(shù):拼接的字符串
如果入?yún)⒁蕾嚭蠖说呐渲茫敲粗苯邮褂妙愃?code>URL query部分格式的字符串。比如支付寶支付的orderString: orderId=123&sign=28fhfh&sign_type=RSA
這類格式。未來擴展性比較高,而且所有版本都可以支持。
- 同一類參數(shù),封裝成
model
,隱藏屬性,通過方法構(gòu)造
如果API參數(shù)過多,可以考慮將一類參數(shù)歸為一類,減少入?yún)€數(shù),也便于以后進行擴展,保持主API穩(wěn)定。對于歸類好的參數(shù),建議不要讓接入者通過[[xxx alloc] init]
生成對象,然后通過setter
進行參數(shù)賦值。直接隱藏掉類屬性,通過提供的便捷構(gòu)造方法進行創(chuàng)建和賦值。這樣做的好處是,在API參數(shù)升級的時候,如果新增的參數(shù)必傳,可以在接入方升級的時候,只要需要改動參數(shù)構(gòu)造的API。
- API功能單一,減少類似
enum
的入?yún)⒃O(shè)計
一個API應(yīng)該單一,入?yún)⒅谐厥馇闆r外,都不應(yīng)該出現(xiàn)類似type
,enum
等入?yún)⑿问健_@類信息最好對接入者屏蔽。一個API承擔(dān)的功能越多,未來改動的可能性越大。
- 用于查詢的屬性,絕對不能直接設(shè)置
SDK會提供一些方法和屬性,讓接入者知道SDK的當(dāng)前狀態(tài)。常見的比如- (BOOL)islogin;
,@property(nonatomic, assign, readonly) BOOL isLogin;
。方法可以隱藏屬性,保證不被修改,如果是屬性,一定要加readonly
。
- API 回調(diào)設(shè)計
回調(diào)設(shè)計其實沒啥好說的,delegate和block比較常見。根據(jù)場景自己決定一種。
開發(fā)篇
一、開發(fā)工具
對于iOS來說,就是個Xcode,但是考慮成工程搭建和打包的方便建議使用cocoapods和cocoapods-packager。
搭建開發(fā)工程:
pod lib create xxx
打包:
pod package xxx.spec
完美配合!
二、開發(fā)和測試工程
SDK寄生在APP中,開發(fā)者需要搭建測試工程,去開發(fā)和模擬接入的真實情況。這邊想說的就是開發(fā)一個測試工程,方便的進行測試和開發(fā),工作量其實并不小。SDK里面能不寫測試代碼的都不要去寫,寫得越多,越容易出現(xiàn)發(fā)版沒有關(guān)閉測試代碼的情況。得益于OC是門動態(tài)語言,很多工具都可以以AOP的形式進行集成。
分享下我們SDK主要開發(fā)了哪些功能:
- 網(wǎng)絡(luò)環(huán)境自由切換,本地MOCK和遠程一鍵切換
- 日志系統(tǒng),自由篩選不同日志
- 測試賬號一鍵切換
- crash日志本地收集
- 第三方調(diào)試工具:FLEX
- 測試環(huán)境數(shù)據(jù)一鍵錄入
- 單元測試BDD,UI自動化
以上這些功能不僅可以方便開發(fā)和調(diào)試,也提高了測試同學(xué)的效率。
三、開發(fā)注意事項
由于SDK開發(fā),很多東西沒有開發(fā)APP那么爽,缺少了優(yōu)秀的第三方,很多東西都要自己去造輪子!而且運行環(huán)境很惡劣!你不知道外面有多少黑科技在搞著你。
開發(fā)SDK的人可以注意下以下幾個點:
- 能用系統(tǒng)的API解決的,就不要使用第三方,減少對其他庫的依賴
- OC沒有命名空間,類命名和類別方法加上前綴
- 黑科技雖然好,但是能不用的就不要用
- 多考慮第三方帶來的影響,比如鍵盤處理,UIKit的UIAppearance等
- 依賴其他SDK的,別打包在一起,不然出現(xiàn)符號表重復(fù)
- 使用了OC類別打包的時候記得加上-ObjC
- 能不用單例的就盡量少的使用
- 核心代碼的安全性
- 資源文件使用bundle進行管理,能不用xib的就別用了吧
發(fā)貨篇
萬事俱備,就差包裝好發(fā)貨了。
-
SDK打包形式
- Static Library
- Dynamic Framework
- Universal Framework
版本控制
(major).(minor).(patch) 如3.8.1
-
發(fā)布渠道
- cocoapods
- 郵件
- 網(wǎng)站
-
文檔
- 千萬別word!!!
- 圖文并茂,依賴配置一定要注明清楚
-
demo
- 復(fù)制demo代碼,就可以完成接入了!!
-
接入幫助
- 技術(shù)支持聯(lián)系方式
- 接入群
- GitHub issues