[Android]如何做一個(gè)崩潰率少于千分之三噶應(yīng)用app(32)-Android app Bundle

Android組件化架構(gòu)

以下是我這個(gè)系列的相關(guān)文章扑眉,有興趣可以參考一下纸泄,可以給個(gè)喜歡或者關(guān)注我的文章。
[Android IM技術(shù)指南] 里面介紹的是加密IM的技術(shù)應(yīng)用和指南

[Android 進(jìn)程化架構(gòu)] 里面介紹的是進(jìn)程化的方案腰素。

[Android]如何做一個(gè)崩潰率少于千分之三噶應(yīng)用app--章節(jié)列表

國(guó)內(nèi)的插件化出不了海聘裁,而Google終于也出了組件化和插件化的模型了,這一節(jié)就是帶你感受一下來(lái)自官方的威力弓千。
1.只有上線google市場(chǎng)的應(yīng)用才能使用衡便。
2.先下載Android Studio 3.3吧,gradle會(huì)默認(rèn)使用最新的4.9洋访,騷年
不符合以上的條件的同學(xué)镣陕,請(qǐng)自動(dòng)略過(guò)吧

優(yōu)勢(shì)
1.初始下載的大小更加小
2.可以只下載地區(qū)資源
3.安裝更加快
4.可以動(dòng)態(tài)更新

限制
1.手機(jī)要有g(shù)oogle store和google play
2.需要上傳你的簽名文件到google play
3.最低版本支持api 21
4.低于api21的第一次下載就會(huì)下載完整包,會(huì)優(yōu)化地區(qū)和資源配置姻政,但是無(wú)法做到動(dòng)態(tài)更新
5.base app不能大于100M呆抑,動(dòng)態(tài)更新的aab文件不要大于10M,而且最好要有下載提示

App分為3種狀態(tài)
1.Base App
首次安裝到手機(jī)的資源和文件汁展,基礎(chǔ)的dex資源

2.Configuration APKs
native libraries 和適配當(dāng)前手機(jī)屏幕分辨率的資源

3.Dynamic feature APKs
不需要在首次安裝就加載的模塊鹊碍,動(dòng)態(tài)加載模塊厌殉,打包后是.aab后綴的文件。

操作基礎(chǔ)介紹
動(dòng)態(tài)更新的module必須使用Dynamic Feature Module


Dynamic Feature Module.png

默認(rèn)就是選擇Android 5.0版本


.png

應(yīng)用于app商店使用下載和安裝動(dòng)態(tài)功能的模塊侈咕,如果下載的機(jī)型低于api21公罕,會(huì)直接全量下載動(dòng)態(tài)模塊。


配置動(dòng)態(tài)更新信息.png

創(chuàng)建后生成的AndroidManifest.xml文件耀销,其中dist中的內(nèi)容是用于動(dòng)態(tài)更新配置的楼眷。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    package="com.hotflyer.bussiness">

    <dist:module
        dist:onDemand="true"
        dist:title="@string/title_bussiness">
        <dist:fusing dist:include="true" />
    </dist:module>
</manifest>

代碼分析
1.最重要使用到的庫(kù)是play:core,這個(gè)庫(kù)是使用動(dòng)態(tài)更新提供接口

api 'com.google.android.play:core:1.3.0'

2.依賴關(guān)系如圖


image.png

加載到模塊的時(shí)候使用到SplitInstallRequest

    // Create request to install a feature module by name.
        val request = SplitInstallRequest.newBuilder()
                .addModule(name)
                .build()

        // Load and install the requested feature module.
        manager.startInstall(request)

3.添加加載監(jiān)聽(tīng)

/** Listener used to handle changes in state for install requests. */
    private val listener = SplitInstallStateUpdatedListener { state ->
        val multiInstall = state.moduleNames().size > 1
        state.moduleNames().forEach { name ->
            // Handle changes in state.
            when (state.status()) {
                SplitInstallSessionStatus.DOWNLOADING -> {  //網(wǎng)絡(luò)拉取動(dòng)態(tài)模塊
                    //  In order to see this, the application has to be uploaded to the Play Store.
                    displayLoadingState(state, "Downloading $name")
                }
                SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> {  //需要用戶確認(rèn)選項(xiàng)(如更新play商店)
                    /*
                      This may occur when attempting to download a sufficiently large module.

                      In order to see this, the application has to be uploaded to the Play Store.
                      Then features can be requested until the confirmation path is triggered.
                     */
                    startIntentSender(state.resolutionIntent().intentSender, null, 0, 0, 0)
                }
                SplitInstallSessionStatus.INSTALLED -> {  //成功下載回調(diào)
                    onSuccessfulLoad(name, launch = !multiInstall)
                }

                SplitInstallSessionStatus.INSTALLING ->   //安裝中
                      displayLoadingState(state, "Installing $name")
                SplitInstallSessionStatus.FAILED -> {    //安裝失敗
                    Log.e(TAG, "Error: ${state.errorCode()} for module ${state.moduleNames()}")
                }
            }
        }
    }

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        manager = SplitInstallManagerFactory.create(this)  //拆分app管理
        initializeViews()
    }

    override fun onResume() {
        // Listener can be registered even without directly triggering a download.
        manager.registerListener(listener)   //注冊(cè)監(jiān)聽(tīng)
        super.onResume()
    }

    override fun onPause() {
        // Make sure to dispose of the listener once it's no longer needed.
        manager.unregisterListener(listener)  //銷毀監(jiān)聽(tīng)
        super.onPause()
    }

4.跳轉(zhuǎn)到相應(yīng)關(guān)系树姨,因?yàn)橐蕾囮P(guān)系的問(wèn)題摩桶,只能通過(guò)包名跳轉(zhuǎn)。

  /** Launch an activity by its class name. */
    private fun launchActivity(className: String) {
        Intent().setClassName(packageName, className)
                .also {
                    startActivity(it)
                }
    }

但是熟悉跳轉(zhuǎn)邏輯帽揪,應(yīng)該會(huì)明白這種情況硝清,可以做一個(gè)適配的路由也是可以正常跳轉(zhuǎn)的。

5.還能動(dòng)態(tài)移除模塊

 /** Request uninstall of all features. */
    private fun requestUninstall() {

        toastAndLog("Requesting uninstall of all modules." +
                "This will happen at some point in the future.")

        val installedModules = manager.installedModules.toList()
        manager.deferredUninstall(installedModules).addOnSuccessListener {
            toastAndLog("Uninstalling $installedModules")
        }
    }

6.需要注意的是動(dòng)態(tài)添加native so需要使用SplitInstallHelper.loadLibrary加載

 SplitInstallHelper.loadLibrary(this, "hello-jni")

7.base module中需要配置dynamicFeature转晰,才會(huì)編譯AndroidManifest.xml中方向合并Dynamic library的AndroidManifest.xml

android{
    dynamicFeatures = [':features:kotlin',
                       ':features:java',
                       ':features:native',
                       ':features:assets', ":bussiness"]
}

在build/intermediates/merged_manifests中可以找到合并的AndroidManifest

8.在build/intermediates/feature_set_metadata中可以看到feature-metadata.json
上面是有一些Dynamic library的信息的

9.play core的庫(kù)是經(jīng)過(guò)混淆的芦拿,除了個(gè)別幾個(gè)對(duì)外使用的文件外,全部混淆查邢,部分原理只能參照國(guó)內(nèi)的插件化了蔗崎。
提供了SplitCompat.install的方式安裝,但是最低只兼容到api19扰藕,即4.4

10.需要配置Application缓苛,有兩種方式,繼承SplitCompatApplication邓深,或者使用SplitCompat.install(this),在該方法中主要完成split apks代碼(dex和so)和資源的安裝未桥。

11.編譯方式如圖,會(huì)生成.aab格式的文件


編譯.png

注意點(diǎn)
1.因?yàn)闀?huì)將四大組件信息都預(yù)先注冊(cè)到合并的base AndroidManifest當(dāng)中芥备,那么無(wú)法新增四大組件冬耿,暫時(shí)不能像國(guó)內(nèi)這樣熱更新。
2.比較適合使用的場(chǎng)景是熱修復(fù)和地區(qū)適配場(chǎng)景萌壳。
3.動(dòng)態(tài)library也是需要上傳給google審核的

相比于普通的組件化架構(gòu)亦镶,其啟動(dòng)入口是從base 的Application當(dāng)中,其他的動(dòng)態(tài)模塊都需要下載后才能使用袱瓮。

那么就需要一個(gè)啟動(dòng)加載畫面下載App module和重要的module缤骨,然后再使用后臺(tái)下載加載其他內(nèi)容,然后模塊跳轉(zhuǎn)前尺借,需要捕獲異常和預(yù)判定模塊加載是否完成绊起,保證程序不會(huì)崩潰。

……2018.7.23更新……
google store 發(fā)布應(yīng)用褐望,需要選擇是否使用App Bundle勒庄,如果使用了,那么將會(huì)重新去打包文件瘫里。會(huì)造成实蔽,你在google市場(chǎng)上下載的包和在其他市場(chǎng)中下載的包,包簽名不一致谨读,無(wú)法覆蓋安裝局装。如果在國(guó)內(nèi)渠道發(fā)布,將無(wú)法用google市場(chǎng)中的app覆蓋安裝劳殖。
如果保持簽名選退出計(jì)劃铐尚,如果使用Android app bundle 選繼續(xù)


簽名方式提示.png

詳細(xì)說(shuō)明


image.png

這個(gè)只有一次機(jī)會(huì),選擇之后哆姻,不會(huì)存在更改了宣增,所以請(qǐng)慎重。

……2020.1.3更新……
1.無(wú)法使用kapt矛缨,驗(yàn)證了build.gradle中無(wú)法使用kapt
2.暫時(shí)無(wú)法引用CameraX 的alpha5版本爹脾,因?yàn)镻review這個(gè)類,會(huì)引用不到MutableLiveData箕昭,然而明明引用了灵妨,換回Library Module可以正常引用

群1已滿,可以進(jìn)群2學(xué)習(xí)組件化

組件化交流群2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末落竹,一起剝皮案震驚了整個(gè)濱河市泌霍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌述召,老刑警劉巖朱转,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異桨武,居然都是意外死亡肋拔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門呀酸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凉蜂,“玉大人,你說(shuō)我怎么就攤上這事性誉×裕” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵错览,是天一觀的道長(zhǎng)纫雁。 經(jīng)常有香客問(wèn)我,道長(zhǎng)倾哺,這世上最難降的妖魔是什么轧邪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任刽脖,我火速辦了婚禮,結(jié)果婚禮上忌愚,老公的妹妹穿的比我還像新娘曲管。我一直安慰自己,他們只是感情好硕糊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布院水。 她就那樣靜靜地躺著,像睡著了一般简十。 火紅的嫁衣襯著肌膚如雪檬某。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天螟蝙,我揣著相機(jī)與錄音恢恼,去河邊找鬼。 笑死胶逢,一個(gè)胖子當(dāng)著我的面吹牛厅瞎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播初坠,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼和簸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了碟刺?” 一聲冷哼從身側(cè)響起锁保,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎半沽,沒(méi)想到半個(gè)月后爽柒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡者填,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年浩村,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片占哟。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡心墅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榨乎,到底是詐尸還是另有隱情怎燥,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布蜜暑,位于F島的核電站铐姚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肛捍。R本人自食惡果不足惜隐绵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一之众、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧依许,春花似錦酝枢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)袍患。三九已至坦康,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诡延,已是汗流浹背滞欠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留肆良,地道東北人筛璧。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像惹恃,于是被迫代替她去往敵國(guó)和親夭谤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,744評(píng)論 25 707
  • 以下是我這個(gè)系列的相關(guān)文章巫糙,有興趣可以參考一下朗儒,可以給個(gè)喜歡或者關(guān)注我的文章。 [Android]如何做一個(gè)崩潰率...
    CangWang閱讀 1,626評(píng)論 4 10
  • 你聽(tīng)說(shuō)過(guò)一見(jiàn)鐘情嗎参淹? 那個(gè)十二歲的夏天醉锄,校門口邊上 他倚在單車邊上,微微回頭尋找我 我撞上他眼睛里浙值,他撞進(jìn)我心底 ...
    Blot閱讀 226評(píng)論 0 0
  • 騎車40分鐘恳不,上課一個(gè)小時(shí),晚上去逛超市了开呐,吃的好多東西烟勋,現(xiàn)在的生活過(guò)得很充足,感謝親愛(ài)的负蚊,還有保佑我這次晉升成功...
    SPP164810閱讀 305評(píng)論 0 0
  • 第四章 逃離 眾人在離開(kāi)女神島后神妹,登上了醫(yī)科塞艇,駛回主島家妆。 “回到原來(lái)的地方嗎鸵荠?”軟毛賣力地劃動(dòng)船槳。 “看那里...
    光是電磁波閱讀 203評(píng)論 0 1