全部產品
Search
文件中心

Mobile Platform as a Service:關於 Portal 和 Bundle 工程

更新時間:Jul 13, 2024

組件化架構是指 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子 Modulebuild.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'

image.png

主 module 的 build.gradle

在主 module 的 build.gradle 中,增加了 mPaaS Bundle Apply 外掛程式 的聲明,表示該工程為 Bundle 工程,Bundle 配置如下:

apply plugin: 'com.alipay.bundle'

主 module 的 build.gradle 中還增加了以下配置:image

其中:

  • version:該 Bundle 的 version。

  • group:該 Bundle 的 groupid。

  • exportPackages: 描述當前 Bundle 工程所有的類在哪些包名下面,包名可以取合集。非靜態連結的 Bundle 必須填寫 exportPackages,否則會出現類載入不到的問題。例如,如果所有的代碼在 com.alipay.democom.alipay.bundle 下,那麼在 exportPackages 中就可以寫 com.alipay,也可以寫 com.alipay.democom.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,來自於由 build.gradle 檔案中的 groupsettings.gradle 中定義的 name

Bundle-Version

Bundle Version,來自於 build.gradle 檔案中的 version

Init-Level

Bundle 的載入時機,來自於 build.gradle 檔案中定義的 properties:init.level

Package-Id

Bundle 資源的 packageid,來自於 build.gradle 檔案中定義的 properties。

Contains-Dex

是否包含 dex,編譯外掛程式自動判斷。

Contains-Res

是否包含資源,編譯外掛程式自動判斷。

Native-Library

包含的 so 檔案有哪些,編譯外掛程式自動判斷。

Component-Name

來自於 AndroidManifest.xml 檔案中定義的 ActivityServiceBroadcastReceiverContentProvider

exportPackages

該 Bundle 的所有的類所在的包名,參考主 module 的 build.gradle

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 的代碼打進 apkclasses.dex 或者 classes1.dexclasses2.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 外掛程式 :

說明

因功能迭代,外掛程式版本可能會不斷增加。

image.png

該外掛程式中包含 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:

image

重要
  • 通常 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 中聲明倉庫依賴地址。

重要

以下配置中的 usernamepassword 不是控制台的登入使用者名稱和密碼。請搜尋群號 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 依賴。只需:

  1. 在 Portal 或 Bundle 最外層的 build.gradle 中聲明依賴倉庫地址。依賴倉庫應和上文 Bundle 發布倉庫相對應。依賴倉庫的配置方法,請參見 配置依賴倉庫

  2. 在 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'
}

相關連結