組件化架構是指 mPaaS 基於 OSGi(Open Service Gateway Initiative,開放服務網關倡議)技術把一個 App 劃分成業務獨立的一個或多個 Bundle 工程以及一個 Portal 工程的架構。mPaaS 會對每個 Bundle 工程的生命週期和依賴加以管理,使用 Portal 工程把所有的 Bundle 工程包合并成一個可啟動並執行 .apk
包。
mPaaS 架構適合團隊協同開發 App,並且該架構套件含組件初始化、埋點等功能,方便您輕鬆接入 mPaaS 組件。
Bundle 工程
傳統的原生工程由一個主模組或是一個主 module 和若干個子 module 組成,而一個 mPaaS Bundle 工程一般由一個名為 app 的主 module 和若干個子 module 組成。
例如,在支付寶中,一個 Bundle 一般由一個名為 app 的主 module 和以下三個子 module 組成:
api:純程式碼介面,interface 的定義。
biz:interface 的實現。
ui:activity,自訂 view 等。
至少有一個名為 api 的子 module。如果沒有子 module, 就打不出 Bundle 的介面包,並且該 Bundle 不能被其他 Bundle 依賴。
通過閱讀本文,您將從以下方面瞭解 Bundle 工程:
Bundle 與傳統工程區別
Bundle 本質上也是一個原生工程,只是在 工程、主 Module、子 Module 的 build.gradle
中多了 mPaaS 的 Apply 外掛程式,具體差別體現在以下方面:
工程根目錄
build.gradle
主 module 的
build.gradle
子 module 的
build.gradle
工程根目錄 build.gradle
在工程根目錄的 build.gradle
中,增加了對 mPaaS 外掛程式的依賴:
因功能迭代,外掛程式版本可能會不斷增加。
classpath 'com.alipay.android:android-gradle-plugin:3.0.0.9.13'
主 module 的 build.gradle
在主 module 的 build.gradle
中,增加了 mPaaS Bundle Apply 外掛程式 的聲明,表示該工程為 Bundle 工程,Bundle 配置如下:
apply plugin: 'com.alipay.bundle'
主 module 的 build.gradle
中還增加了以下配置:
其中:
version
:該 Bundle 的 version。group
:該 Bundle 的 groupid。exportPackages
: 描述當前 Bundle 工程所有的類在哪些包名下面,包名可以取合集。非靜態連結的 Bundle 必須填寫exportPackages
,否則會出現類載入不到的問題。例如,如果所有的代碼在com.alipay.demo
和com.alipay.bundle
下,那麼在exportPackages
中就可以寫com.alipay
,也可以寫com.alipay.demo
、com.alipay.bundle
。包名不宜過長或過短。initLevel
:架構啟動時載入該 Bundle 的時機。時機範圍在 0-100,數字越小表示越早載入。其中11110000
為使用時載入,即懶載入。packageId
:描述當前 Bundle 的資源的 ID,供 aapt 打包時需要。由於是多 Bundle 架構,每個 Bundle 的 packageId 必須唯一,不可與其它 Bundle 的 packageId 重複。目前 mPaaS 已經使用的 packageId 如下:
Bundle | packageId |
com.alipay.android.phone.thirdparty:androidsupportrecyclerview-build | 28 |
com.alipay.android.phone.mobilesdk:framework-build | 30 |
com.alipay.android.phone.rome:pushservice-build | 35 |
com.alipay.android.phone.sync:syncservice-build | 38 |
com.alipay.android.phone.wallet:nebulabiz-build | 41 |
com.alipay.android.phone.mobilecommon:share-build | 42 |
com.alipay.android.phone.wallet:nebulacore-build | 66 |
com.alipay.android.mpaas:scan-build | 72 |
com.alipay.android.phone.wallet:nebula-build | 76 |
com.alipay.android.phone.securitycommon:aliupgrade-build | 77 |
在 dependencies
中會添加對 mPaaS 的如下依賴:
dependencies {
compile project(":api")
apt 'com.alipay.android.tools:androidannotations:2.7.1@jar'
//mPaaS dependencies
provided 'com.alipay.android.phone.thirdparty:fastjson-api:1.1.73@jar'
provided 'com.alipay.android.phone.thirdparty:androidsupport-api:13.23@jar'
}
子 module 的 build.gradle
在子 module 的 build.gradle
中,增加了 mPaaS Apply 外掛程式 的聲明,表示該工程為 Bundle 的子 module 工程,最終會打出該 Bundle 的介面包。
apply plugin: 'com.alipay.library'
在 dependencies
中會添加對 mPaaS 的如下依賴:
dependencies {
apt 'com.alipay.android.tools:androidannotations:2.7.1@jar'
//mPaaS dependencies
provided "com.alipay.android.phone.thirdparty:utdid-api:1.0.3@jar"
provided "com.alipay.android.phone.mobilesdk:framework-api:2.1.1@jar"
}
Bundle 屬性
本架構的 Bundle 屬性設計思路參考 OSGi 的 Bundle,但比 OSGi 的 Bundle 更簡潔和輕巧。
以下表格列出 Bundle 屬性及其解釋:
屬性 | 解釋 |
Bundle-Name | Bundle Name,來自於由 |
Bundle-Version | Bundle Version,來自於 |
Init-Level | Bundle 的載入時機,來自於 |
Package-Id | Bundle 資源的 packageid,來自於 |
Contains-Dex | 是否包含 dex,編譯外掛程式自動判斷。 |
Contains-Res | 是否包含資源,編譯外掛程式自動判斷。 |
Native-Library | 包含的 |
Component-Name | 來自於 |
exportPackages | 該 Bundle 的所有的類所在的包名,參考主 module 的 |
Bundle 介面包
一個 Bundle 有可能包含多個 子 Module,如 biz, api, ui。在編譯打包 Bundle 的時候,每個子 module 都會分別產生一個格式為 .jar
介面包,其中 api 介面包可以被其他 Bundle 使用。
在打包的同時,也會產生一個 Bundle 工程包,這個工程包包含所有的子 module,工程包可以被 Portal 工程使用,工程包在 Portal 中編譯,最後產生 .apk
包。
由 Bundle 的 子 module 打出來的介面包,只對外提供定義的 java/kotlin 介面類,不包含其他如 res 下的資源,且這些介面包僅限於來自名稱為 api 的 module。
各 Bundle 工程直接通過 Bundle 的介面包互相依賴,需要在 bundle 的
build.gradle
中的dependency
配置依賴 api 介面。例如,Bundle A 依賴 Bundle B 中的bapi
子 module,那麼在 Bundle A 相應的子 module 的build.gradle
中的dependency
配置對bapi
的依賴。provided "com.alipay.android.phone:bundleB:1.0.1:bapi@jar"
依賴中涉及的
groupId:artifactid:version:classifier
分別對應 Bundle 中聲明的 group,name,version,子 module 的名字。Bundle 的 name 預設為主 module 的檔案夾名,可以在
settings.gradle
中修改,如下代碼所示,其中 app 為主 module 的工程名:include ':api', ':xxxx-build' project(':xxxx-build').projectDir = new File('app')
Bundle 工程包
由整個 Bundle 工程打出來的
.jar
包其實是一個.apk
格式的檔案,但是也以.jar
結尾,如framework-build.jar
。如果要在 Portal 中依賴 Bundle,則在 Portal 主 module 的
build.gradle
中的dependency
中聲明依賴 Bundle 包,如下所示:dependencies { bundle "com.alipay.android.phone.mobilesdk:framework-build:version@jar" manifest "com.alipay.android.phone.mobilesdk:framework-build:version:AndroidManifest@xml" }
對 Bundle 打包分兩種:debug 包和 release 包,在 Portal 依賴 Bundle 的 debug 包時,需要在 debug 包中額外加上
:raw
。當 Portal 依賴 Bundle 的 debug 包時,
bundle "com.alipay.android.phone.mobilesdk:framework-build:version:raw@jar"
當 Portal 依賴 Bundle 的 release 包時,
bundle "com.alipay.android.phone.mobilesdk:framework-build:version@jar"
打 Portal 包時,需要確定以下內容:
哪些 Bundle 是要打在 app 的主 dex 中。靜態連結,有
ContentProvider
的 Bundle 必須放在靜態連結中。哪些動態載入。如果 App 不大,建議都在主 dex 中。
如果想把 Bundle 的代碼打進主 dex 中,則需要在 Portal 的
slinks
檔案中配置當前 Bundle。配置內容為:groupId-artifactId
。如果以-build
結尾,則去掉 -build。例如, groupId 為com.mpaas.group
,artifactId 為testBundle-build
,則需要在slinks
檔案中添加一行:com.mpaas.group-testBundle
。靜態連結:把 Bundle 的代碼打進
apk
的classes.dex
或者classes1.dex
,classes2.dex
等中,以便工程啟動時就可以載入 Bundle 中的類。
Portal 工程
Portal 工程把所有的 Bundle 工程包合并成一個可啟動並執行 .apk
包。
Portal 與傳統工程區別
Portal 和傳統開發中的工程的區別體現在 build.gradle
:
工程根目錄
build.gradle
主 module 目錄
build.gradle
工程根目錄 build.gradle
如下圖所示,classpath 多了一個 com.alipay.android:android-gradle-plugin:2.1.3.2.7
外掛程式 :
因功能迭代,外掛程式版本可能會不斷增加。
該外掛程式中包含 Portal 外掛程式,Portal 外掛程式可以在打包過程中把各 Bundle 合并。
合并 Bundle 的
.jar
合并 Bundle 的
AndroidManifest
主 module 目錄 build.gradle
多了 mPaaS Apply Portal 外掛程式 的聲明,表示該工程為 Portal 工程。Portal 配置如下:
apply plugin: 'com.alipay.portal'
同時,在 dependencies
中添加相應的對 Bundle 的依賴。dependencies
中的語句是 bundle 和 manifest 的聲明,用來表示 Portal 依賴了哪些 Bundle 或 manifest:
通常 Portal 下面不寫代碼。
以下幾種在 Bundle 工程中使用的資源(style/drawable/string等),必須放在 Portal 工程中,否則會導致編譯/運行時找不到資源:
AndroidManifest.xml
中使用的資源。傳遞給 NotificaionManager 使用的資源。
通過
getResources().getIdentifier()
方法使用的資源。引用的第三方
AAR
包中如有以上三種情況,也需要解壓AAR
,將對應的資源複製一份放到 Portal 工程中。
工程依賴
一個 基於 mPaaS 架構 的 App 包括 一個或多個 Bundle 和 一個 Portal。一個 App 有且只能有一個 Portal 工程,但可以有多個 Bundle 工程。
通過 mPaaS 外掛程式,Portal 工程把所有的 Bundle 工程包合并成一個可啟動並執行 .apk
包。合并後,該外掛程式把 Bundle 工程部署至指定的倉庫地址。該倉庫地址在 Bundle 的主 module 中的 build.gradle
中定義,如下代碼所示:
uploadArchives {
repositories {
mavenLocal()
}
}
該倉庫地址是上傳至本地的 ~/.m2
倉庫地址。您也可以添加自訂的倉庫地址,如下所示:
mavenDeployer {
mavenLocal()
repository(url: "${repository_url}") {
authentication(userName: 'userName', password: 'userName_pwd')
}
snapshotRepository(url: "${repository_url}") {
authentication(userName: 'userName', password: 'userName_pwd')
}
}
上傳之後,Bundle 以 groupid:artifactid:version:classifier@type
的形式存在指定的倉庫中。因此,只要在 Portal 最外層主 module 的 build.gradle
中聲明 dependency
就可指定各 Bundle 依賴,如下代碼所示:
dependencies {
bundle 'com.alipay.android.phone.mobilesdk:quinox-build:2.2.1.161221190158:nolog@jar'
manifest 'com.alipay.android.phone.mobilesdk:quinox-build:2.2.1.161221190158:AndroidManifest@xml'
}
此外,Bundle 工程之間的相互依賴也需要在 Bundle 的最外層的 build.gradle
中聲明倉庫依賴地址。
以下配置中的 username
和 password
不是控制台的登入使用者名稱和密碼。請搜尋群號 41708565 加入DingTalk群進行諮詢擷取這兩個值。其中:
mavenLocal()
描述依賴的本地倉庫地址。maven{}
聲明依賴的遠程倉庫地址。
allprojects {
repositories {
mavenLocal()
mavenCentral()
maven {
credentials {
username "{username}"
password "{password}"
}
url "http://mvn.cloud.alipay.com/nexus/content/repositories/releases/"
}
}
}
Bundle 編譯打包結果
使用 mPaaS 外掛程式編譯打包後,一個 Bundle 會產生一個工程包(是一個 .jar
包)。更多資訊,請參考 Bundle 工程包 和 Bundle 介面包。
工程包會以 groupid:artifactid:version:classifier@type
的形式發布到指定倉庫中。發布倉庫地址在 Bundle 主 module 中的 build.gradle
中定義,樣本如下:
uploadArchives {
repositories {
mavenLocal()
}
}
上述配置指定發布倉庫為本地 Maven 倉庫(mavenLocal
)。如需修改本地 Maven 倉庫地址(預設 ~/.m2
)或增加發布倉庫,請參見 配置發布倉庫。
添加 Bundle 依賴
您可以在 Portal 中添加 Bundle 依賴,也可以在 Bundle 中添加其他 Bundle 依賴。只需:
在 Portal 或 Bundle 最外層的
build.gradle
中聲明依賴倉庫地址。依賴倉庫應和上文 Bundle 發布倉庫相對應。依賴倉庫的配置方法,請參見 配置依賴倉庫。在 Portal 或 Bundle 主 module 的
build.gradle
中聲明dependencies
依賴。如添加 Bundle(quinox
)依賴的樣本如下:
dependencies {
bundle 'com.alipay.android.phone.mobilesdk:quinox-build:2.2.1.161221190158:nolog@jar'
manifest 'com.alipay.android.phone.mobilesdk:quinox-build:2.2.1.161221190158:AndroidManifest@xml'
}