- 2019.9.30
- VirtualAPK
- 接入指南
- 一 預注意事項
- 1. gradle-wrapper.properties
- 2. 根 build.gradle 配置
- 3. 注意混淆
- 4. 依賴庫
- 二 宿主程序
- 1. 應用級 build.gradle 配置
- 2. 初始化
- 3. 假設已有插件包
- (1)安裝
- (2)檢查插件是否安裝
- (3)啟動
- (4)刪除插件
- 三 插件程序
- 1. 應用級 build.gradle 配置
- 2. 生成插件包
- 3. 問題
- (1) 使用 FragmentActivity
- (2) Theme.AppCompat.Light.NoActionBar 主題無法去除 ActionBar
- (3) IncompatibleClassChangeError
- (4) 插件使用 material 控件會報錯
- (5) CardView 背景會變黑
- (6) 約束布局在插件中無效
- (7) 其他
- 一 預注意事項
2019.9.30
以下內容時當前時間2019.9.30版本下,跑通了 VirtualAPK 的踩坑接入總結裁奇。
VirtualAPK
https://github.com/didi/VirtualAPK
要是在 RePlugin 和 VirtualAPK 里選對話音五,我更偏向 RePlugin, 因為它至少可用 AppCompatActivity羔沙, VirtualAPK 在 2019.9.30 當前版本的插件里面只能用 Activity躺涝,而且插件不支持多module, 倒是 入侵性極低 這個很不錯。
但是扼雏,至少可以讓項目跑起來上線坚嗜,在當前已經接入百萬級APP里看,還算穩(wěn)定呢蛤。
接入指南
官網(wǎng) Wiki 也說的很詳細, 建議使用 Androidx惶傻。
一 預注意事項
宿主和插件保持一致性,才會讓坑更少點其障。
1. gradle-wrapper.properties
目前最好使用 4.6:
#Fri Mar 01 16:49:19 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
2. 根 build.gradle 配置
classpath 'com.android.tools.build:gradle:3.2.0'
classpath 'com.didi.virtualapk:gradle:0.9.8.6.2-dev'
3. 注意混淆
混淆文件盡量保持一致银室。如果報錯提示沒有找到某個文件,那么就是這個文件需要被keep励翼。
記住 keep 你的啟動頁蜈敢,別讓它被混淆了。
virtualapk 混淆:
-keep class com.didi.virtualapk.internal.VAInstrumentation { *; }
-keep class com.didi.virtualapk.internal.PluginContentResolver { *; }
-dontwarn com.didi.virtualapk.**
-dontwarn android.content.pm.**
如果插件使用 Retrofit+Rxjava+OkHttp:
#retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keep class io.reactivex.**
-keep class io.reactivex.** { *; }
#okhttp
-dontwarn okhttp3.**
-keep class okhttp3.**{*;}
-keep interface okhttp3.**{*;}
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.** { *;}
-dontwarn okio.**
# rxjava
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
4. 依賴庫
在當前測試情況下汽抚,只要把插件的依賴庫完整的拷貝一份到宿主里面抓狭,就可以不用針對不同宿主重新編譯插件包。
插件所用依賴庫的版本必須和宿主一致造烁。
二 宿主程序
宿主的資源id最好有自己的命名前綴否过,如果想坑少點午笛。
1. 應用級 build.gradle 配置
應用插件:
apply plugin: 'com.android.application'
apply plugin: 'com.didi.virtualapk.host'
可以使用 Java 8:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
添加 virtualapk 依賴:
implementation ('com.didi.virtualapk:core:0.9.9.1-dev') {
exclude group: 'com.android.support'
}
2. 初始化
在 Application 進行初始化
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
PluginManager.getInstance(base).init();
}
3. 假設已有插件包
插件包后綴必須 .apk
(1)安裝
PluginManager.getInstance(PCache.getContext()).loadPlugin(file);
需要記錄插件啟動頁相對路徑比如: com.afra55.greate.MainActivity
。
安裝代碼執(zhí)行后苗桂,插件包不要刪除药磺,目前的情況是,每次進入插件都 安裝一次才不會出問題煤伟。
(2)檢查插件是否安裝
自己進行安裝判斷癌佩。
(3)啟動
Intent intent = new Intent();
intent.setClassName(packageName, "com.afra55.greate.MainActivity");
context.startActivity(intent);
(4)刪除插件
無。
三 插件程序
注意便锨,如果有多個 module围辙,最好把多個module 的代碼都放到一個module下,不能直接去依賴module 會出錯放案。 或者把module庫代碼放到 maven 倉庫去依賴姚建。
插件不支持分包,代碼越少越好卿叽,重的依賴庫就放到宿主桥胞,通過反射調用恳守。
插件不能配置 Java8, 謹記考婴。
1. 應用級 build.gradle 配置
在最底下配置:
apply plugin: 'com.didi.virtualapk.plugin'
virtualApk {
packageId = 0x6f // 插件的唯一標志,不用插件要有不同的 packageId.
targetHost = '/Users/afra55/Program/Android/TestMaster/app' // TODO(根據(jù)不同的項目催烘,修改成應用級module的全路徑)
applyHostMapping = true //optional, default value: true.
forceUseHostDependences = true // 強制使用宿主工程的依賴
}
targetHost 需要根據(jù)不同的項目沥阱,修改成應用級module的全路徑。
上面也提到了伊群,拷貝一份插件的全部依賴到宿主考杉,插件包就可以復用。
這樣就配置完成了舰始。
2. 生成插件包
使用Terminal到應用級目錄下執(zhí)行命令:
../gradlew clean assemblePlugin
這樣就打包出來了崇棠。
可以修改打包路徑 (適用 gradle-3.2.0):
release {
signingConfig signingConfigs.release
debuggable false
zipAlignEnabled true
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
if (outputFile != null &&
outputFile.name.endsWith('release.apk')) {
variant.getPackageApplication().outputDirectory = new File("${getApkSavedPath()}")
def fileName =
"afra55.apk"
output.outputFileName = fileName
}
}
}
}
3. 問題
(1) 使用 FragmentActivity
不能使用 AppCompatActivity, 會報錯
(2) Theme.AppCompat.Light.NoActionBar 主題無法去除 ActionBar
在代碼里實現(xiàn)你的去ActionBar效果丸卷,在主題里無效:
try {
requestWindowFeature(Window.FEATURE_NO_TITLE);
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.hide();
}
} catch (Exception e) {
e.printStackTrace();
}
(3) IncompatibleClassChangeError
凡是出現(xiàn)這個問題枕稀,就是插件和宿主的相同依賴度的版本不一致造成的。
(4) 插件使用 material 控件會報錯
去除 material 控件谜嫉,自己寫一個吧萎坷。
(5) CardView 背景會變黑
那就別用了,自己寫個沐兰。
(6) 約束布局在插件中無效
換掉哆档。
(7) 其他
參考官網(wǎng)的常見問答:https://github.com/didi/VirtualAPK/wiki/常見問題解答