如何設(shè)計一款穩(wěn)定、好用、安全的推送SDK?
一款穩(wěn)定、易用、安全、小巧靈活的推送SDK是怎么樣的?本文將從“小”、“穩(wěn)”、“好用”以及“安全”四個角度來具體闡述。
對于非技術(shù)出身的產(chǎn)品經(jīng)理來說,如果突然接到一個要“設(shè)計SDK”的活兒,其實并不容易。畢竟,SDK是主要面向開發(fā)者的,更像一個toD產(chǎn)品。那么,產(chǎn)品經(jīng)理在設(shè)計SDK時,需要注意哪些點呢?換句話說,一款好的SDK應(yīng)該具備哪些特性?本文將從“小”、“穩(wěn)”、“好用”以及“安全”四個角度來具體闡述。
1. 小
1.1 65535限制
我們以一款好的推送SDK為例,那么首要需考慮到SDK包體的小巧靈活性。
為什么選擇更小體積的包體?
對于商務(wù)人員來說,包體體積小,他們更容易接受。對于技術(shù)人員來說,他們在開發(fā)產(chǎn)品時,普遍追求“代碼少、功能全”,這是來自程序員的代碼潔癖。
那么從代碼層面來看,是因為系統(tǒng)有“65535限制”。
如上圖(左)所示,程序最終會生成dex文件,dex文件主要由以下幾部分組成:header(標(biāo)頭)、一連串的ids(標(biāo)識符列表)、data(數(shù)據(jù)區(qū))以及l(fā)ink_data(靜態(tài)鏈接文件中使用的數(shù)據(jù))。
細(xì)看上圖(右),它包含了一個method_ids_size字段,該字段的主要作用是定義個數(shù)。根據(jù)谷歌的定義,uint是一個16位的short類型,最長長度是65535。如果將dex工程反編譯,會生成很多smali的文件,再去看smali里的函數(shù)調(diào)用(比如invoke direct {***} 函數(shù)名@BBB),會發(fā)現(xiàn)調(diào)用的地址其實就是剛才unit里定義的偏移量計算得出的。因此,這個函數(shù)地址最多也只能有65535個。
1.2 如何使包體體積變小
如何減小包體的體積,建議從以下幾個方面考慮:
(1)自研,不嵌套
在設(shè)計研發(fā)SDK時,不建議在SDK內(nèi)嵌套一系列框架,例如三方網(wǎng)絡(luò)框架、db框架或任務(wù)調(diào)度框架等。我們主張選擇最核心的一部分進(jìn)行自主研發(fā)。
(2)代碼優(yōu)化
從算法層面,在效果相同的情況下,可適當(dāng)減少代碼的行數(shù);對于有默認(rèn)賦值的變量不需要進(jìn)行初始化賦值;選擇合適的字符串拼接方式,建議使用StringBuilder方法拼接字符串,可以解決字符串頻繁修改帶來的內(nèi)存消耗,也有利于減少包體體積大小。
(3)追求實用,放棄完美
SDK包體應(yīng)當(dāng)追求實用性,以完善主功能為主,其他相對次要的部分可以適當(dāng)減少時間或精力投入,放棄完美主義思維。
(4)代碼混淆
借助代碼混淆實現(xiàn)更小體積的包體,且不易被逆向。
1.3 省電省流量
省電省流量是“小”的另一個方面。SDK如果沒有對流量和電量有嚴(yán)格的限制,否則會出現(xiàn)手機(jī)發(fā)燙、高耗電提醒、流量浪費、內(nèi)置SDK APP難以上架等問題。
針對上述問題,我們可以設(shè)置通過Lock殺手,智能心跳、自定義協(xié)議、鏈路合并、按需活躍等方式盡可能地降低SDK對電量以及流量造成的消耗。
(1)Lock殺手:代碼中WiFiLock、WakeLock等會強(qiáng)制喚醒APP,導(dǎo)致APP產(chǎn)生較大耗電量。在不影響功能的前提下,我們應(yīng)盡量減少或者不用該類鎖。
(2)智能心跳:應(yīng)根據(jù)不同的運營商、網(wǎng)絡(luò)狀態(tài)等,選擇不同的心跳策略,并且根據(jù)不同的應(yīng)用場景探索心跳的最大邊界,盡量延長心跳周期,減少電量和網(wǎng)絡(luò)的消耗。
(3)自定義協(xié)議:市場上常用的json、xml、甚至PB協(xié)議,都有比較好的兼容擴(kuò)展性,但同樣也帶來了空間浪費的問題,自定義協(xié)議可以充分利用空間,精確利用每一個byte甚至bit,極簡化封裝,承載最大的信息量,減少流量和電量浪費。
(4)鏈路合并:當(dāng)一個設(shè)備有多個APP的推送鏈路同時活躍時,我們會運用合并鏈路技術(shù),將使用同一款SDK的 APP 之間的長連接鏈路進(jìn)行合并,減少流量電量的浪費。
2. 穩(wěn)
2.1 提升穩(wěn)定性
在設(shè)計SDK時,還要考慮到SDK的使用穩(wěn)定性。否則在實際應(yīng)用中,可能會遇到ANR、OOM、Crash、內(nèi)存泄露、閃退等棘手的問題,我們需要通過持續(xù)的迭代和優(yōu)化來將錯誤最小化。
(1)做好代碼管理
除了借助SVN、GIT等工具做好代碼托管外,還需遵循一定的代碼規(guī)范,借助類似gerrit等工具進(jìn)行代碼review,使用verify流程。在保證機(jī)器找不到問題的前提下,再用人眼去辨別是否符合業(yè)務(wù)邏輯。
(2)自動化測試
自動化測試可以大幅提升回歸測試的效率,非常適合敏捷的開發(fā)過程。此外,自動化測試可以替代大量的手工機(jī)械重復(fù)性操作,測試工程師可以把更多的時間花在更全面的用例設(shè)計和新功能測試上。
(3)運用代碼模塊化等小技巧
代碼模塊化能以最少的模塊、零部件,更快速地滿足更多的個性化需求。異常處理可以提高系統(tǒng)的容錯性,讓程序更加穩(wěn)定。代碼檢測能及時發(fā)現(xiàn)程序中的缺陷和錯誤,比如檢測內(nèi)存是否泄露,是否有安全漏洞等,保證代碼質(zhì)量。
(4)線上灰度
實際場景中,我們很難去覆蓋所有的環(huán)境,例如機(jī)型、網(wǎng)絡(luò)等,需要通過線上用戶的反饋去驗證代碼的健壯性。因此在產(chǎn)品大規(guī)模推向用戶之前,我們需要進(jìn)行少量的真實用戶測試,即灰度上線來幫助減少風(fēng)險。
(5)日志系統(tǒng)
系統(tǒng)有問題是必然的,在盡量保持系統(tǒng)穩(wěn)定的前提下,要考慮容錯性。當(dāng)問題發(fā)生時,需要第一時間以最快的速度排查,因此需要有一套完整的日志系統(tǒng)。此外,平時我們也可以通過日志系統(tǒng)的撥測檢測系統(tǒng)的健壯性,可以在用戶反饋之前及時發(fā)現(xiàn)并解決問題。
2.2 兼容性
兼容性也是保證SDK穩(wěn)定性的一個重要條件,主要考慮以下幾個方面:???
(1)接口兼容
每次版本更新后,對外接口要盡可能保持不變。對于改動較大的接口,可以使用 @Deprecated 注解對老接口進(jìn)行標(biāo)記,并且做新接口調(diào)用的兼容,而不是直接刪除老接口。
(2)主鍵兼容
當(dāng)主鍵發(fā)生變更(例如去掉service、provider)時,部分老的安卓系統(tǒng)會有組件緩存,運行時直接告知“類”找不到。建議在AndroidManifest中保留聲明,且對應(yīng)“類”進(jìn)行代碼空實現(xiàn),以減少發(fā)生crash的概率。
(3)安卓系統(tǒng)兼容
可使用Build.VERSION.SDK_INT做API區(qū)分。
(4)真機(jī)兼容
可以借助云測等平臺進(jìn)行兼容性測試。
3. 好用
SDK的易用性可以從下面幾個方面考慮:
(1)接入簡單
接入SDK時有集成demo直接可以運行,且接入文檔清晰、步驟簡單,最好能實現(xiàn)一鍵集成。
(2)保持核心優(yōu)勢
一款好的消息推送SDK,我們主要考慮及時性、到達(dá)率、穩(wěn)定性和準(zhǔn)確性。
例如:新聞媒體類APP對推送的及時性要求較高;通知類推送(如轉(zhuǎn)賬信息)會特別注重消息的到達(dá)率;穩(wěn)定性指的是要保證推送SDK在不同環(huán)境下的正常運行,尤其是11.11等高并發(fā)場景;準(zhǔn)確性主要針對廣告營銷類推送,需要在合適的時間、合適的地點和合適的場景把合適的內(nèi)容推送給合適的人。其中,關(guān)于如何保證穩(wěn)定性,可以從多線路、多IDC、熱備份等角度考慮。
①多線路調(diào)整:例如預(yù)埋三線域名,做一些輪詢策略,防止域名被劫持。
②多IDC設(shè)置:除了域名被劫持外,還可能遇到網(wǎng)絡(luò)攻擊,物理性損壞的情況。設(shè)置多IDC一方面是為了實現(xiàn)分流,另一方面也降低了風(fēng)險。
③熱備份:系統(tǒng)處于正常運轉(zhuǎn)狀態(tài)下的備份,一旦系統(tǒng)出現(xiàn)問題,可以快速恢復(fù)。
(3)多樣化需求
通過豐富的畫像標(biāo)簽,對用戶進(jìn)行場景化的智能推送,滿足用戶的多樣化需求。
(4)策略可控
我們還提供靜默時間、推送控量、短信補(bǔ)量、定時展示等附加功能,滿足客戶的實際使用場景。
4. 安全
SDK設(shè)計開發(fā)過程中,我們還需要注意安全性。安全性不僅僅代表網(wǎng)絡(luò)數(shù)據(jù)交互的安全、本地數(shù)據(jù)存儲的安全,也涉及到 SDK 的加固、混淆、第三方安全軟件審核等。
其中,我們重點講解SDK的加固。目前安卓平臺SDK絕大部分都是Java語言編寫,容易被反編譯。SDK如果只是進(jìn)行了簡單的混淆,很容易被窺探到內(nèi)部實現(xiàn)細(xì)節(jié),此外還可能存在SDK被二次打包、植入惡意廣告等現(xiàn)象。因此,我們需要對SDK進(jìn)行加固,以提升安全性。
如上圖所示,SDK的加固主要是Java層面和so層面的操作。Java層面可以進(jìn)行SSR IR指令轉(zhuǎn)換或者做Java2C處理,把實現(xiàn)細(xì)節(jié)放入native中;so層面可以做一些扁平化、虛假控制等來混淆代碼,也可以通過指令替換、指令跳轉(zhuǎn)邏輯來增加逆向難度。此外,也可以通過常量字符串加密加固SDK,這是目前較為簡單實用的一種方式。
現(xiàn)在看來,要設(shè)計開發(fā)一款好的SDK最難的還是如何讓自己設(shè)計的SDK在復(fù)雜的環(huán)境下穩(wěn)定運行,這需要我們對 SDK 的架構(gòu)有比較清晰的認(rèn)知,并不斷迭代和優(yōu)化。
那么以上提到的四點,也是各位產(chǎn)品經(jīng)理和開發(fā)者需要注意的,希望對大家有所幫助。
本文由 @個推 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自?Unsplash,基于 CC0 協(xié)議
- 目前還沒評論,等你發(fā)揮!