本篇內(nèi)容介紹了“如何開發(fā)Android SDK”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)公司專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、東莞網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁面制作、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為東莞等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
相信做 Android 開發(fā)的朋友,一定使用過第三方的 SDK,比如推送 SDK、分享 SDK 等。SDK 的全稱是 Software Development Kit,翻譯為“軟件開發(fā)工具包”。SDK 通常是為輔助開發(fā)某類軟件而編寫的特定軟件包、框架集合等。
SDK 可以分為系統(tǒng) SDK 和應(yīng)用 SDK。所謂系統(tǒng) SDK 是為使用特定的軟件框架、硬件平臺(tái)等所開發(fā)的工具集合。而應(yīng)用 SDK 則是基于系統(tǒng) SDK 開發(fā)的獨(dú)立于具體業(yè)務(wù)、擁有特定功能的工具集合。
SDK 的使用者主要是 B 端客戶,最終交付產(chǎn)品是代碼、示例和文檔,客戶接入 SDK 也是和 SDK 提供方交流的過程,對(duì)外溝通的成本比對(duì)內(nèi)更高,遇到的問題也會(huì)更多。所以 SDK 開發(fā)對(duì)開發(fā)者的要求比對(duì)應(yīng)用開發(fā)更高。能開發(fā)好 SDK 一定能開發(fā)好應(yīng)用,但能開發(fā)好應(yīng)用,未必能開發(fā)好 SDK。
SDK 的實(shí)現(xiàn)目標(biāo),概括來說:簡潔、穩(wěn)定、高效。
簡潔
對(duì)于用戶而言,一款好的產(chǎn)品應(yīng)該是簡潔易用的,不該讓他們花費(fèi)太長的時(shí)間學(xué)習(xí)。SDK 也當(dāng)如此,它不該出現(xiàn)復(fù)雜繁瑣的對(duì)接工作,使用者通過閱讀代碼和文檔,花費(fèi)很少的時(shí)間就能做好 SDK 的對(duì)接。
比如當(dāng)開發(fā)者需要使用 SDK 的服務(wù)時(shí),只需要在代碼中新增一行即可。在項(xiàng)目中初始化 SDK 只要一行代碼,開發(fā)者不用關(guān)心 GLContext,內(nèi)部已做好處理,也不用關(guān)心同步或異步問題。
public class FURenderer { // 定義 public static void setup(Context context) { //... } } // 一行代碼調(diào)用 FURenderer.setup(context);
穩(wěn)定
站在 SDK 使用者角度來看,我們期望第三方 SDK 的服務(wù)是穩(wěn)定高效的,體現(xiàn)在提供穩(wěn)定可靠的服務(wù),同時(shí)運(yùn)行時(shí)性能要高效。這就要求我們?cè)谠O(shè)計(jì)實(shí)現(xiàn) SDK 時(shí)要盡可能做到以下幾點(diǎn):
對(duì)外提供穩(wěn)定的 API。SDK 的 API 一旦確定,除非特殊情況不可更改,提供方變更 API 的成本非常大。
對(duì)外提供穩(wěn)定的業(yè)務(wù)。在提供了穩(wěn)定的 API 后,必須要有穩(wěn)定的業(yè)務(wù)作為支撐。
運(yùn)行時(shí)的穩(wěn)定。確保 SDK 自身穩(wěn)定運(yùn)行,不能出現(xiàn)因?yàn)榻尤肓?SDK 而導(dǎo)致宿主應(yīng)用不穩(wěn)定的情況。
版本穩(wěn)定更新。SDK 版本迭代非常緩慢,要盡可能對(duì)使用者屏蔽迭代過程,避免帶來不必要的適配成本。
高效
無論是普通的應(yīng)用開發(fā)還是 SDK 開發(fā),都應(yīng)該考慮到性能問題,SDK 設(shè)計(jì)者要著重考慮以下問題:
更少的內(nèi)存占用。一般 SDK 和 App 運(yùn)行在同一進(jìn)程,此時(shí) SDK 要管理好自己占用的內(nèi)存,合理分配,注意釋放。
更少的內(nèi)存抖動(dòng)。在占用更少內(nèi)存的前提下,SDK 設(shè)計(jì)者必須減少頻繁 GC 造成的內(nèi)存抖動(dòng)問題。
更少的電量消耗。低電量消耗和高性能表現(xiàn)之間很難做到權(quán)衡,可以從 CPU 計(jì)算量、屏幕刷新幀率等角度考量。
SDK 的架構(gòu)實(shí)現(xiàn)決定了后續(xù)的維護(hù)難度,所以最好能夠結(jié)合實(shí)際業(yè)務(wù)確定合適的方案。以項(xiàng)目中的模塊化開發(fā)為例,講講架構(gòu)設(shè)計(jì)的原則。
遵循面向?qū)ο箝_發(fā)的幾大原則,目的是達(dá)到三個(gè)目標(biāo):可維護(hù)性、可重用性和可擴(kuò)展性。具體來講:
根據(jù)單一職責(zé)原則,將系統(tǒng)拆分為多個(gè)小模塊,每個(gè)模塊保持相對(duì)獨(dú)立,降低實(shí)現(xiàn)類的復(fù)雜度。
根據(jù)接口隔離原則,為每個(gè)模塊定義契約接口,接口的粒度要小,功能要細(xì),越細(xì)小越易維護(hù)。
模塊之間通過協(xié)議或接口通信,避免直接相互依賴,以降低耦合,互相了解最少,體現(xiàn)了迪米特法則。
根據(jù)開閉原則,定義各個(gè)模塊的公共行為,通過模版方法設(shè)計(jì)模式提供骨架實(shí)現(xiàn),易于功能擴(kuò)展。
根據(jù)組合優(yōu)于繼承的原則,當(dāng)多個(gè)模塊功能疊加時(shí),使用類的組合保證設(shè)計(jì)的靈活性。
比如項(xiàng)目第三方 demo 的功能模塊借鑒了 Java 集合框架的架構(gòu),分為契約接口、抽象類和具體實(shí)現(xiàn)三部分。
首先定義 IEffectModule 作為特效的契約接口,包括創(chuàng)建、設(shè)置參數(shù)、銷毀等各個(gè)功能模塊的公共操作。
AbstractEffectModule 作為 IEffectModule 的骨架實(shí)現(xiàn),實(shí)現(xiàn)了共同使用的方法,定義了公共的成員變量。
定義美顏 IFaceBeautyModule 接口,其繼承 IEffectModule 接口,包括額外的設(shè)置參數(shù)操作,F(xiàn)aceBeautyModule 作為其實(shí)現(xiàn)類,同時(shí)繼承 AbstractEffectModule,復(fù)用基類的代碼。
美妝美體模塊類似,先定義契約接口,然后定義具體實(shí)現(xiàn),接口間相互隔離,接口內(nèi)高度內(nèi)聚。
FURenderer 實(shí)現(xiàn) IFURenderer 渲染接口和 IModuleManager 模塊管理接口,組合各個(gè)功能模塊。
API 設(shè)計(jì)在任何開發(fā)中都非常重要,許多時(shí)候軟件的質(zhì)量好壞體現(xiàn)在 API 的設(shè)計(jì)上。在普通的應(yīng)用開發(fā)中,API 只會(huì)在開發(fā)人員間流通,不會(huì)暴露給非本應(yīng)用開發(fā)的其他人員。但是 SDK 作為一種服務(wù),需要向開發(fā)者暴露一部分 API,這樣才能使用 SDK 的服務(wù)。
下面列出一些應(yīng)該重點(diǎn)關(guān)注的原則。
方法名表明其用途
好的方法名最直觀表明它的功能,名字是自解釋的,不需要額外的文檔,這樣做會(huì)減少不必要的溝通成本。對(duì)于開發(fā)者而言,還有什么比直接讀代碼更直觀呢?《重構(gòu)》一書中講到,要像給自己孩子起名一樣給每個(gè)變量命名,這個(gè)要求不算過分吧。
參數(shù)的合法性檢驗(yàn)
如果程序運(yùn)行時(shí)出現(xiàn)異常,會(huì)破壞使用者的體驗(yàn),影響非常不好。我們采用“防御式編程”的思想,能夠避免非法輸入對(duì)系統(tǒng)的破壞性。
當(dāng)合法性校驗(yàn)不通過時(shí),針對(duì)方法權(quán)限不同分別對(duì)應(yīng)不同不同的處理策略:
對(duì)于公開方法顯式檢查拋出異常,并使用 @throw 來說明拋出異常的原因
對(duì)于私有方法通過斷言的方式來檢查參數(shù)的合法。
檢查構(gòu)造方法的參數(shù)的合法性,以使對(duì)象處在統(tǒng)一狀態(tài)。
需要注意的是,如果檢查的代價(jià)太大,那就需要綜合考量。
方法只實(shí)現(xiàn)單一功能
一個(gè)方法應(yīng)該具有單一的功能,盡可能做更少、更專的事情,這也是單一職責(zé)原則的體現(xiàn)。“阿里巴巴代碼規(guī)約”規(guī)定一個(gè)方法最好不要超過 80 行,對(duì)龐大的方法要拆分成更小的。
另外注意,寧可提供小而美的方法也不要提供大而全的方法,大而全的方法往往經(jīng)常發(fā)生變動(dòng),產(chǎn)生風(fēng)險(xiǎn)的可能性更高。因此不如提供更小的方法以便組合使用,小而美的方法更易做到代碼復(fù)用。
訪問權(quán)限控制
包括類方法的權(quán)限和變量的權(quán)限,能聲明私有的不要公開,外部知道得越少越好。能聲明靜態(tài)的方法就用靜態(tài),靜態(tài)方法天然線程安全,體現(xiàn)繼承關(guān)系的用 protected 修飾,確保公開的方法和變量是安全可靠的。
避免過長參數(shù)
過長的參數(shù)會(huì)造成記憶上困難,還有調(diào)用傳參容易出錯(cuò),應(yīng)當(dāng)盡力避免。在無法避免過長參數(shù)的情況下,考慮其他的方法進(jìn)行解決:
通過使用 Builder 模式來實(shí)現(xiàn)
通過將多個(gè)參數(shù)封裝成類對(duì)象
例如,項(xiàng)目里有個(gè)方法,參數(shù)非常多。
int onDrawFrameSingleInput(byte[] img, int w, int h, int format, byte[] readBackImg, int readBackW, int readBackH);
重構(gòu)后,把參數(shù)封裝成對(duì)象,調(diào)用方法只用構(gòu)造一個(gè)對(duì)象傳入,避免大量參數(shù)帶來不好的體驗(yàn)感。
public class VideoFrame { private int width; private int height; private byte[] data; private byte[] readback; private int readbackWidth; private int readbackHeight; private int pixelFormat; // ... } int onDrawFrameSingleInput(VideoFrame videoFrame);
慎用方法重載
濫用重載容易讓開發(fā)者感到疑惑,在需要重載方法的時(shí)候,可以使用不同方法名來代替。對(duì)于構(gòu)造函數(shù),可以通過靜態(tài)工廠來代替重載。
Java 中提供的 ObjectOutputStream 類就是個(gè)很好的示范:它的 write 對(duì)于每個(gè)基本類型都有一個(gè)變形,比如寫出字符、寫出 boolean 等操作。設(shè)計(jì)者并沒有使用重載將其設(shè)計(jì)成 write(Long l)、write(Boolean b),而是將其設(shè)計(jì)為 writeLong(l)、writeBoolean(b)。
例如,項(xiàng)目對(duì)外的處理方法全部是重載,只能根據(jù)參數(shù)區(qū)分,迷惑性非常大。修改為不同的方法名后,看到名字就知道要調(diào)用的方法,清楚了不少。
// 重構(gòu)前 int onDrawFrame(byte[] img, int tex, int w, int h); int onDrawFrame(byte[] img, int w, int h); // 重構(gòu)后 int onDrawFrameDualInput(byte[] img, int tex, int w, int h); int onDrawFrameSingleInput(byte[] img, int w, int h, int format);
避免方法直接返回 null
對(duì)于需要返回?cái)?shù)組或集合的方法,不要返回null。比如我們?nèi)ベI糕點(diǎn)店買面包,面包沒了是一種正常狀態(tài),就不應(yīng)該返回 null,而是返回長度為 0 的數(shù)組或集合。Java 提供了 Collections.emptyXXX() 表示空集合。
避免引入第三方庫
GitHub有許多開源的第三方庫,比如網(wǎng)絡(luò)請(qǐng)求 OkHttp、圖片加載 Glide 等,但在 SDK 開發(fā)中,遵循的基本的原則是:
最小可用性原則,即用最少的代碼,如無必要勿增實(shí)體。
最少依賴性原則,即用最低限度的外部依賴,如無必要勿增依賴。
引入第三方庫可能帶來下面幾個(gè)問題:
宿主應(yīng)用的第三方庫和 SDK 依賴的版本不一致,容易引起沖突,增加對(duì)接的成本。
開源庫不斷更新,SDK 也要及時(shí)更新,增加額外的維護(hù)工作量。
由于引入開源庫,出現(xiàn)問題難以排查。
保證兼容性
SDK 是不斷迭代的,每次發(fā)布都會(huì)有新功能和 bug 修復(fù)。對(duì)于使用者來說,升級(jí)版本不該有太大的改動(dòng),一般直接替換庫文件或者修改遠(yuǎn)程依賴庫的版本號(hào)就夠了。避免直接對(duì)公開接口的重命名,如果舊接口廢棄,要通過 @Deprecated 關(guān)鍵字標(biāo)明,并給出替代方案和廢棄的時(shí)間。
減少入侵性
要保證較少的代碼侵入主要在對(duì)外提供服務(wù)時(shí),充分考慮開發(fā)者的使用場(chǎng)景來設(shè)計(jì)優(yōu)良的 API。一套優(yōu)良的 API 在定義時(shí)要滿足絕大數(shù)開發(fā)者預(yù)期的方式——語義上要求通俗易懂,使用上要求簡單可靠。具體的表現(xiàn)是,在正常情況下能夠穩(wěn)定可靠地運(yùn)行,在異常情況下及時(shí)地反饋錯(cuò)誤信息。
比如使用 Gradle 下載依賴庫,AAR 包中有不必要的 bundle 資源,我們提供了打包 apk 時(shí)的構(gòu)建配置,自由選擇要打包的 bundle,減少了對(duì)宿主應(yīng)用的侵入性。
applicationVariants.all { variant -> variant.mergeAssetsProvider.configure { doLast { delete(fileTree(dir: outputDir, // 刪除不必要的 bundle 文件 includes: ['model/ai_face_processor_lite.bundle', 'model/ai_gesture.bundle', 'graphics/controller.bundle', 'graphics/tongue.bundle'])) } } }
封裝包
Android 平臺(tái)通常使用 jar 和 aar 發(fā)布 SDK,區(qū)別是 jar 只包含代碼,aar 可以包含代碼、資源和動(dòng)態(tài)庫。一般而言 aar 是最合適的交付方式,把它上傳到 maven 服務(wù)器,使用者就可以一行代碼集成。對(duì)于需要靈活定制的客戶,我們也會(huì)提供 SDK 的源碼,弊端就是升級(jí)困難,要改動(dòng)很多的代碼。
對(duì)于代碼混淆,公開接口和 native 使用的接口不要混,內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)可以混淆,以減少 SDK 包的大小。
接入文檔
接入文檔用來告訴 SDK 使用者,如何使用 SDK、詳細(xì)步使用驟和可能發(fā)生的問題。文檔內(nèi)容包括:更新記錄、基本信息、API 說明、集成步驟、FAQ等。好文檔的標(biāo)準(zhǔn)就是清晰明了,通俗易懂。一個(gè)完全不懂 SDK 的開發(fā)者看著文檔就能對(duì)接,對(duì)于經(jīng)常遇到的問題要逐條列出,專業(yè)名詞要有對(duì)應(yīng)的解釋。
Demo 示例
集成 Demo 通常是一個(gè)簡單的 App,用來展示如何快速地接入 SDK。Demo 的源碼托管到 GitHub,方便使用者參考,其版本變更策略和 SDK 版本的變化保持一致。盡管是個(gè) Demo,它的開發(fā)原則也要與 SDK 一致,確保高質(zhì)量的交付。
“如何開發(fā)Android SDK”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!