VirtualApk介紹
VirtualAPK是滴滴出行自研的一款插件化框架。
??傳送門
接入文檔
接入步驟以及細(xì)節(jié)可參考文檔
接入注意點(diǎn)
- gradle 版本可以使用3.0.0 ,官網(wǎng)建議是2.14.1 實(shí)際demo運(yùn)行可行
- 插件模塊配置信息virtualApk,放在文件末尾(注意個(gè)配置的含義)
virtualApk {
packageId = 0x6f // 插件資源id,避免資源id沖突
targetHost='../host/app' // 宿主工程的路徑(絕對或者相對路徑)
applyHostMapping = true // 插件編譯時(shí)是否啟用應(yīng)用宿主的apply mapping
}
- 打包插件之前需要先編譯宿主工程,編譯之后生成一些信息(在build/VAHost文件夾下),插件構(gòu)建的時(shí)候會(huì)讀取這些信息,所以要確保運(yùn)行的宿主和插件基于相同信息構(gòu)建的,宿主變化時(shí)請重新構(gòu)建插件
- 插件運(yùn)行(不能直接Run出來)需要通過 命令打出
- ./gradlew clean assemblePlugin
原理簡介
插件化重點(diǎn)看下類的加載以及資源的加載:
類的加載VirtualAPK大體方案如下:
Activity:在宿主apk中提前占幾個(gè)坑,然后通過“欺上瞞下”(這個(gè)詞好像是360之前的ppt中提到)的方式,啟動(dòng)插件apk的Activity;因?yàn)橐С植煌膌aunchMode以及一些特殊的屬性,需要占多個(gè)坑。
Service:通過代理Service的方式去分發(fā);主進(jìn)程和其他進(jìn)程,VirtualAPK使用了兩個(gè)代理Service。
BroadcastReceiver:靜態(tài)轉(zhuǎn)動(dòng)態(tài)
ContentProvider:通過一個(gè)代理Provider進(jìn)行分發(fā)。
資源的加載:
主要是在LoadedOlugin中的createResources方法中
private static Resources createResources(Context context, File apk) {
if (Constants.COMBINE_RESOURCES) {
Resources resources = ResourcesManager.createResources(context, apk.getAbsolutePath());
ResourcesManager.hookResources(context, resources);
return resources;
} else {
Resources hostResources = context.getResources();
AssetManager assetManager = createAssetManager(context, apk);
return new Resources(assetManager, hostResources.getDisplayMetrics(), hostResources.getConfiguration());
}
}
Constants.COMBINE_RESOURCES
- 為true的時(shí)候
- ResourcesManager.createResources通過反射將當(dāng)前apk的路徑添加到host中
- 將apk的class加載到了主host中
- 插件可以引用到主項(xiàng)目中的資源
- 為falsede 時(shí)候
- 重新創(chuàng)建了新的resource
- 插件和主項(xiàng)目資源分離,不可引用
插件和宿主之間的通信
插件如何和宿主交互?
通過compile相同aar的方式來交互。 比如,宿主工程中compile了如下aar:
compile 'com.didi.foundation:sdk:1.2.0'
compile 'com.didi.virtualapk:core:[newest version]'
compile 'com.android.support:appcompat-v7:22.2.0'
但是插件工程需要訪問宿主sdk中的類和資源,那么可以在插件工程中同樣compile sdk的aar,如下:
compile 'com.didi.foundation:sdk:1.2.0'
這樣一來,插件工程就可以正常地引用sdk了。并且,插件構(gòu)建的時(shí)候會(huì)自動(dòng)將這個(gè)aar從apk中剔除。
上述就是VirtualAPK中插件和宿主通信的基本方式。
拿龍珠項(xiàng)目舉個(gè)例子??
龍珠項(xiàng)目目前各個(gè)模塊之間的跳轉(zhuǎn)是通過路由來實(shí)現(xiàn),在VirtualApk插件中使用路由,只需要在主App中和插件中都引入路由,做好各自相應(yīng)的注冊,就能正常跳轉(zhuǎn)。
Virtual不支持
- 目前暫不支持的特性
暫不支持Activity的一些不常用特性(比如process、configChanges等屬性),但是支持theme、launchMode和screenOrientation屬性; - overridePendingTransition(int enterAnim, int exitAnim)這種形式的轉(zhuǎn)場動(dòng)畫,動(dòng)畫資源不能使用插件的(可以使用宿主或系統(tǒng)的);
- 插件中彈通知,需要統(tǒng)一處理,走宿主的邏輯,通知中的資源文件不能使用插件的(可以使用宿主或系統(tǒng)的)。
- 插件的Activity中不支持動(dòng)態(tài)申請權(quán)限。
結(jié)論
由于以下幾種問題,Virtual插件方案和當(dāng)前項(xiàng)目適用性不好,所以不使用:
- 可能是由于第一個(gè)不支持,在房間收到切換橫豎屏無效,具體原因未明。
- 主hostApp和插件之間必須有一個(gè)明確的路徑
virtualApk{
targetHost='../host/app' // 宿主工程的路徑(絕對或者相對路徑)
}