組件化框架是指 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
不是控制臺的登錄用戶名和密碼。您必須 提交工單 獲取這兩個值。其中:
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'
}