以下是我這個(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
默認(rèn)就是選擇Android 5.0版本
應(yīng)用于app商店使用下載和安裝動(dòng)態(tài)功能的模塊侈咕,如果下載的機(jī)型低于api21公罕,會(huì)直接全量下載動(dòng)態(tài)模塊。
創(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)系如圖
加載到模塊的時(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格式的文件
注意點(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ù)
詳細(xì)說(shuō)明
這個(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í)組件化