VirtualApk是滴滴提供的一套插件化解决方案。一步一个坑,赶紧写个记录,供大家参考。如果自己写真的会哭的。
插件化分成两部分:宿主apk和插件apk
首先让我们来创建一个宿主apk
第一部分:创建宿主apk
第一步:项目gradle设置并添加virtualApk插件
dependencies { // 说明gradle的版本号 classpath 'com.android.tools.build:gradle:2.3.3' //必须是这个版本的gradle,大于3.0的无法运行 classpath 'com.didi.virtualapk:gradle:0.9.4' //VirtualApk // NOTE: Do not place your application dependencies zhere; they belong // in the individual module build.gradle files }
备注:就在选择gradle的版本上,我正在花费了两天,virtualApk对gradle的版本兼容性极其的差,基本不支持3.0以上版本。但是我之前使用的又是3.3.1,这样完全没法玩了。改成了2.3.3以后,又发生编译报错。最后发现原来 gradle 在3.0前后对依赖包引入的名称是不同的,实例:
3.0以后版本:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:26.1.0' compile 'com.android.support.constraint:constraint-layout:1.0.2' }3.0以前版本:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' testImplementation 'junit:junit:4.12' }第二步:在app的gradle添加host和依赖,并添加编译工具的版本
在文件头部添加
apply plugin: 'com.didi.virtualapk.host'在android{} 中添加编译工具版本,不写的话也报错
android { compileSdkVersion 26 // 编译工具的版本 buildToolsVersion "26.0.2" // 编译工具的版本最后在dependencies中添加依赖包
compile 'com.didi.virtualapk:core:0.9.1'
第三步:编写Applicaton,在其中做VirtualApk的初始化工作
public class MyApplication extends Application{ @Override protected void attachBaseContext(Context context) { super.attachBaseContext(context); PluginManager.getInstance(context).init(); } }第四步:加混淆(在这个地方,我必须要骂一句人tmd,不加混淆根本没法运行插件apk,滴滴你倒是说一下啊!!!一个下午找问题),混淆好像也是可以不加的
-keep class com.didi.virtualapk.internal.VAInstrumentation { *; } -keep class com.didi.virtualapk.internal.PluginContentResolver { *; } -dontwarn com.didi.virtualapk.** -dontwarn android.content.pm.** -keep class android.** { *; }第五步:启动插件(此时,假设插件apk被我们放到了sd卡中)
String pluginPath = Environment.getExternalStorageDirectory().getAbsolutePath().concat("/malei.apk"); File plugin = new File(pluginPath); if(plugin.exists()){ PluginManager.getInstance(MainActivity.this).loadPlugin(plugin); Intent intent = new Intent(); intent.setClassName("com.malei.virtualsonapk", "com.malei.virtualsonapk.MainActivity"); //插件apk的包名 startActivity(intent); }第六步:在配置文件中添加权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第二部分:创建插件apk
第一步:项目gradle设置并添加virtualApk插件
dependencies { classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.didi.virtualapk:gradle:0.9.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }第二步:在app的gradle中添加virtualapk配置
apply plugin: 'com.didi.virtualapk.plugin' virtualApk { packageId = 0x6f // 避免资源文件冲突 targetHost='D:\\private_git\\virtualApkPro\\app' // The path of application module in host project. applyHostMapping = true // [Optional] Default value is true. }第三步:同时添加编译工具版本(与宿主apk版本相同)
buildToolsVersion "26.0.2" // 编译工具的版本第四步:将插件apk进行编译生存release版本(必须)
将生成的apk添加到指定的sd中,一切就完成了!
备注:
1.gradle版本为3.0.1以下 (具体原因要查询)
2.xml文件名宿主项目和插件项目名不要相同,否则展示页面发生问题,比如host的界面是main.xml 进入到plugin中的时候界面不可以叫main.xml。(
注意插件资源名称不要和宿主相同,否则会认为使用宿主的资源,导致插件的资源编译时被移除。我一开始定义创建 Demo 时,宿主和插件布局文件都叫 R.layout.activity_main,就导致了引用资源错误以及资源空指针异常。同时注意插件类名称也不要和宿主类名称相同,否则会出现启动插件时显示的界面与宿主相同的错误。)
3.Activity类的宿主和插件名最好不同,否则异常