VirtualAPK插件框架介绍(一)----框架接入

作者: piglet696 | 来源:发表于2017-07-12 15:06 被阅读13351次

背景

近几年Android插件化技术是比较热门领域,6月30日滴滴也开源了自研的插件化框架VirtualAPK。一周多的时间已经有3300+star,从官方wiki可以看到,该框架功能完备,支持Android四大组件,良好的兼容性,且入侵性较低,作为加载耦合插件方案是较好选择。笔者会写一系列VirtualAPK学习的文章,第一篇先介绍一下插件化和VirtualAPK如何接入,请先Clone https://github.com/piglet696/VirtualAPKDemo.git 项目,从一个全新的项目接入VirtualAPK。

什么是插件化?

插件(Plugin)在计算机领域是一个通用的概念,维基百科上这样解释:

In computing, a plugin is a software component that adds a specific feature to an existing computer program.

意思是对现有的程序添加额外的功能组件。这样的好处是可以对原有程序进行扩展,以Android Studio为例,我们可以安装FindBugs插件,这样IDE就具备了更强大的静态代码检查功能。插件可以是第三方的开发者开发,只需要遵循一定的协议即可,插件可以随时更新、卸载,可以看到插件化使我们的程序更加灵活。

为什么要插件化?

插件化听起来很美好,但是谷歌并没有赋予Android这种能力,因为这样存在安全风险,试想一下表面上是一个计算器App,谷歌审核通过后,加载插件后变成一个窃取隐私的App怎么办。那为什么在国内插件化技术非常热门,各个大厂都在使用呢?总结了下有以下几个原因:

  1. 国内App的版本碎片较为严重,想减少升级成本。国内没有统一的应用分发市场,静默升级需要ROM的支持,否则第三方应用市场需要Root的方式实现;
  2. 解决App方法数超65536问题。在谷歌官方的Multidex方案没有出现时,可以采用插件方式解决,而现在该问题不应该是你选择插件化的原因;
  3. 减少App包大小。宿主App包含了主要功能,其余放到插件中实现,动态下发;
  4. 快速修改线上Bug或者发布新功能。作为程序员这个场景肯定遇到过,刚发布一个新版本存在Bug,再重新发版成本又特别高。而只发布插件成本就会很低,又能快速解决线上问题。
  5. 模块解耦,协同开发。一个超级App,可以拆分成不同的插件模块,基于一定的规则业务线之间协同开发,最终每个业务模块生成一个插件,由宿主加载组合即可。再比如你需要接入第三方App的功能,只需要第三方基于插件协议开发即可,不需要在宿主代码中进行开发,很好的做到业务隔离,合作终止时直接移除插件即可。

当你想引入插件化技术时问一下自己接入的原因和要解决什么问题,不要为了接入而接入,毕竟接入和维护需要一定的成本,比如解决一些奇怪的问题、一套插件管理&下发的后台等。

VirtualAPK框架接入

简介

VirtualAPK的开源地址:https://github.com/didi/VirtualAPK请读者详细阅读一下Readme和Wiki,对VirtualAPK框架有个整体的认识。引用Wiki中VirtualAPK和其他开源框架的对比:

特性 DynamicLoadApk DynamicAPK Small DroidPlugin VirtualAPK
支持四大组件 只支持Activity 只支持Activity 只支持Activity 全支持 全支持
组件无需在宿主manifest中预注册 ×
插件可以依赖宿主 ×
支持PendingIntent × × ×
Android特性支持 大部分 大部分 大部分 几乎全部 几乎全部
兼容性适配 一般 一般 中等
插件构建 部署aapt Gradle插件 Gradle插件

VirtualAPK工程中包括了插件的源代码和DEMO,为了更加清晰的展示如何接入SDK,笔者新建了一个VirtualAPKDemo工程,建议Clone代码后结合源码阅读文章,更容易理解。该工程包括宿主工程Host和插件工程ImageBrowser,可以把宿主工程想象成一个所有功能的展示入口,而ImageBrowser插件工程用于实现具体的图片浏览业务。为了展示VirtualAPK对耦合型插件的支持,这里宿主和插件都会依赖Picasso库加载图片,但VirtualAPK框架构建插件APK时会把插件中的Picasso库移除,插件直接使用宿主的Picasso库,下文会具体说明。

环境准备

  • Gradle版本需要为2.14.1,可以使用gradle -v查看环境中配置的Gradle版本号。也可以使用工程中gradlew来编译,可以在gradle/wrapper/gradle-wrapper.properties中更改版本号
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
  • com.android.tools.build的版本号为2.1.3

宿主工程接入

Host宿主工程接入需要以下6步

  1. 在宿主工程根目录的build.gradle添加依赖
dependencies {
    classpath 'com.didi.virtualapk:gradle:0.9.0'
}
  1. 在App的工程模块的build.gradle添加使用gradle插件
apply plugin: 'com.didi.virtualapk.host'
  1. 添加VirtualAPK SDK compile依赖
dependencies {
    compile 'com.didi.virtualapk:core:0.9.0'
}
  1. 在App的工程模块proguard-rules.pro文件添加混淆规则(Ps:Picasso库的混淆规则没有列出来)
-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.** { *; }
  1. MyApplication类是继承了Application,覆写attachBaseContext函数,进行插件SDK初始化工作
@Override
protected void attachBaseContext(Context base)  {
      super.attachBaseContext(base);
      PluginManager.getInstance(base).init();
}
  1. 在使用插件之前加载插件,可以根据具体业务场景选择合适时机加载,我是在MainActivity的onCreate时机加载
protected void onCreate(Bundle savedInstanceState) {
        // 加载plugin.apk插件包
        PluginManager pluginManager = PluginManager.getInstance(this);
        File apk = new File(getExternalStorageDirectory(), "plugin.apk");
        if (apk.exists()) {
            try {
                pluginManager.loadPlugin(apk);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } 
    }

经过上述6步后,VirtualAPK插件功能就集成到宿主中了,宿主打包和运行方式没有任何改变。接下来看下插件工程如何集成和构建的。

插件工程接入

ImageBrowser插件工程接入分为3步:

  1. ImageBrowser工程根目录的build.gradle添加依赖
dependencies {
    classpath 'com.didi.virtualapk:gradle:0.9.0'
}
  1. 在App的工程模块的build.gradle添加使用gradle插件和插件配置信息,信息需要放在文件最下面
apply plugin: 'com.didi.virtualapk.plugin'
...
...
// 插件配置信息,放在文件最下面
virtualApk {
    packageId = 0x6f             // 插件资源id,避免资源id冲突
    targetHost='../host/app'     // 宿主工程的路径
    applyHostMapping = true      // 插件编译时是否启用应用宿主的apply mapping
}

解释一下上面3个参数的作用

  • packageId用于定义每个插件的资源id,多个插件间的资源Id前缀要不同,避免资源合并时产生冲突
  • targetHost指明宿主工程的应用模块,插件编译时需要获取宿主的一些信息,比如mapping文件、依赖的SDK版本信息、R资源文件,一定不能填错,否则在编译插件时会提示找不到宿主工程。
  • applyHostMapping表示插件是否开启apply mapping功能。当宿主开启混淆时,一般情况下插件就要开启applyHostMapping功能。因为宿主混淆后函数名可能有fun()变为a(),插件使用宿主混淆后的mapping映射来编译插件包,这样插件调用fun()时实际调用的是a(),才能找到正确的函数调用。
  1. 最后一步生成插件,需要使用Gradle命令
gradle clean assemblePlugin
或者
./gradlew clean assemblePlugin  

强调一下如果构建时确保Gradle版本需要为2.14.1,否则构建可能发生错误。构建成功后在build/outputs/apk 或者plugin目录中查看插件,plugin目录和apk目录中插件的区别在于plugin将插件以packageName_timestamp格式重命名,DEMO中的插件构建成功后才3KB。

插件包位置.png

官方WIKI中还说明了:

  • 插件包均是Release包,不支持debug模式的插件包
  • 如果存在多个productFlavors,那么将会构建出多个插件包

前面说到VirtualAPK是对耦合型业务有很好的支持,对于我们的DEMO来说,宿主和插件都用到了Picasso库,我们反编译插件包后看一下里面包含的内容如下图所示。

插件包内容.png

可以看到,插件包中没有Picasso库的相关源码,构建时VirtualAPK已经帮我们移除了。需要注意,宿主和插件包中依赖的SDK版本需要完全一致时才会被移除。

运行插件

因为宿主中代码写的是从SD卡根目录加载plugin.apk插件,所以我们需要将生成的插件重命名后放到指定位置。

adb push 插件路径 /sdcard/plugin.apk

然后启动宿主程序后点击"查看更多美图",此时加载的Activity来自于插件中,启动代码如下所示

@Override
public void onClick(View v) {
    if (PluginManager.getInstance(this).getLoadedPlugin(PLUGIN_PKG_NAME) == null) {
        Toast.makeText(getApplicationContext(),
                    "插件未加载,请尝试重启APP", Toast.LENGTH_SHORT).show();
        return;
    }
    Intent intent = new Intent();
    intent.setClassName("com.virtualapk.imageplugin",       "com.virtualapk.imageplugin.ImageBrowserActivity");
    startActivity(intent);
}

OK,插件就么运行起来了,可以看到在开发宿主和插件时,几乎没有侵入,在生成插件时需要一些命令操作,可以通过脚本实现编译插件+Push到SD卡中,提高开发效率。

DEMO比较简单只包含了Activity,后面会扩展到其他组件的使用,大家可以仔细看下官方WIKI-插件开发指南,里面介绍了插件中四大组件的使用、so库的加载、已知的约束和插件加载时机的选取问题。

其他注意点

  1. 要想清楚宿主和插件的业务边界很重要,才能找到插件的入口点。Demo中是以ImageBrowserActivity为边界,从这个Activity之后的功能来来自于插件中。其实我们可以把插件看成一个类提供者,可以使用Class.forName()这种方式使用插件中的类,所以不是只能从Activity/Fragment作为入口点。
  2. 编译宿主工程时会生成一些信息(在build/VAHost文件夹下),插件构建时会读取这些信息,所以要确保运行的宿主和插件基于相同信息构建的,宿主变化时请重新构建插件。

常见错误解法

以下问题是基于VirtuAPK 0.9.0版本,官方Wiki也列举了常见问题解决方式。

  1. 编译时报错 Failed to notify project evaluation listener,具体信息如下
What went wrong:
A problem occurred configuring project ':app'.
> Failed to notify project evaluation listener.
   > com/android/builder/dependency/ManifestDependency

解决方式:修改Gradle和build tools的版本,参考前文环境准备

  1. 编译插件时报错 Caused by: java.lang.NullPointerException: Cannot invoke method getAt() on null object
    解决方式:插件中至少包含一个资源文件。
  2. 编译插件时报错The directory of host application doesn't exist!
    解决方式:检查插件工程中build.gradle文件targetHost参数填写的路径是否正确。
  3. 编译插件时报错 java.lang.ArrayIndexOutOfBoundsException: 2,具体信息如下
Caused by: java.lang.ArrayIndexOutOfBoundsException: 2
at com.didi.virtualapk.VAPlugin$_pickSplitEntries_closure8.doCall(VAPlug
in.groovy:188)
at com.didi.virtualapk.VAPlugin.pickSplitEntries(VAPlugin.groovy:186)
at com.didi.virtualapk.VAPlugin$_apply_closure1$_closure16.doCall(VAPlug
in.groovy:66)
at com.didi.virtualapk.VAPlugin$_apply_closure1.doCall(VAPlugin.groovy:5
2)
at org.gradle.listener.ClosureBackedMethodInvocationDispatch.dispatch(Cl
osureBackedMethodInvocationDispatch.java:40)
at org.gradle.listener.ClosureBackedMethodInvocationDispatch.dispatch(Cl
osureBackedMethodInvocationDispatch.java:25)

解决方式:请检查dependencies中aar的依赖方式,请参下面的方式

dependencies {
    √ compile 'com.didi.virtualapk:core:0.9.0'
    √ compile project (":CoreLibrary")
    √ compile(group:'test', name: 'CoreLibrary-release', version:'0.1', ext: 'aar') // group和version字段必须有

    × releaseCompile 'com.didi.virtualapk:core:0.9.0'
    × compile(name: 'CoreLibrary-release', ext: 'aar')
}
  1. 启动插件时显示的界面与宿主相同,或者引用资源错误。
    解决方式:注意插件资源名称不要和宿主相同,否则会认为使用宿主的资源,导致插件的资源编译时被移除。有网友定义创建demo时,宿主和插件布局文件都叫R.layout.activity_main,就会导致该问题。
  2. 运行时Crash报错java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
    解决方式:检查下宿主里引用的所有SDK版本号和插件中的版本号是否一致,不一致的话会插件编译时不会把共有SDK移除,导致两个相同类打包进来,加载时会出错。最常见的就是插件和宿主的V4包版本不一致导致问题。

结束语

VirtualAPK插件框架在使用过程中还是比较简单的,没有过多的侵入性,所以大家可以尝试玩起来。要实现一个插件化技术需要对Android系统原理、编译构建都有较好理解,所以接下会学习、拆解该框架的技术原理,请大家继续关注后续文章吧,会第一时间发布在微信公众号:Mob行者。VirtualAPK官方QQ群号656602897,作者玉刚大神也在啊!


微信公众号二维码.jpg

相关文章

网友评论

  • 9be9bdba2c91:插件里面依赖的library中引用的资源文件获取不到 ,?
  • c84a6998a6c6:您好,我自己写了一个demo,host里点击按钮启动插件,怎么跳转到host了,是哪里配置错了吗??
  • c84a6998a6c6:插件配置gradle报错Error:Cause: com/android/build/gradle/internal/scope/ConventionMappingHelper
  • 威威dett:求教一下如果第三方公司自己开发插件
    targetHost = '../../VirtualAPK/app' 这个要怎么写呢,又怎么编译呢
    劫匪强:把 targetHost 下的 Host_R.txt 和versions.txt 给他们就行
  • 6054a4da381e:你好,什么都正常编译,插件apk也复制到了sdcard目录下,就是从宿主里打开更多图片时,闪退了。请问什么情况。控制台也没什么关键的错误信息。不知道怎么解决了
  • a41b547f4e79:请问使用window电脑,按wiki中说的编译插件,成功后在demo中加载插件会报这个错误是什么原因? Mac电脑下按wiki操作没有问题
    12-07 14:41:29.059 16390-16390/com.didi.virtualapk W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6217)
    12-07 14:41:29.059 16390-16390/com.didi.virtualapk W/System.err: at java.lang.reflect.Method.invoke(Native Method)
    12-07 14:41:29.059 16390-16390/com.didi.virtualapk W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:929)
    12-07 14:41:29.059 16390-16390/com.didi.virtualapk W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:819)
    12-07 14:41:29.060 16390-16390/com.didi.virtualapk W/System.err: Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.didi.virtualapk/com.didi.virtualapk.demo.aidl.BookManagerActivity}; have you declared this activity in your AndroidManifest.xml?
    12-07 14:41:29.060 16390-16390/com.didi.virtualapk W/System.err: at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1821)
    12-07 14:41:29.060 16390-16390/com.didi.virtualapk W/System.err: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1534)
    12-07 14:41:29.060 16390-16390/com.didi.virtualapk W/System.err: ... 21 more
    12-07 14:41:29.060 16390-16390/com.didi.virtualapk V/PerformanceManager_JNI: event notify: fd = 63, event_id = 0X00304803
    12-07 14:41:29.265 16390-16390/com.didi.virtualapk D/ryg: query book:3, Android
    12-07 14:41:29.265 16390-16390/com.didi.virtualapk D/ryg: query book:4, Ios
    12-07 14:41:29.265 16390-16390/com.didi.virtualapk D/ryg: query book:5, Html5
  • Alien的小窝:本来准备研究下源码的,听你的介绍,这个框架也仅仅是能加载 【特定的apk插件:需要参与编译】,而不是任意第三方apk?这样的话有些场景意义就不是很大了!
    9be9bdba2c91:你想的太简单了
    Alien的小窝:@piglet696 我说的并不片面啊,我上面说的是【有的场景】,这和之前任主席第一个框架Dynamic-Load-Apk是差不多的需求,宿主和插件的需求一样,只是功能和实现更加稳定而已。我的需求则是360和VA那种的,毕竟实现方式都不一样,这种方式能实现一些黑科技,而virtualAPK这种实现肯定就不行了,我是这个意思的。
    piglet696:@编程之乐 @编程之乐 你的说法有些片面。首先需要搞清楚自己业务需要的场景,一种是类似手机助手加载业务无关的第三方app。第二种是跟自己业务相关的,比如你需要公司内部的统一sdk,而插件里不需要再包含了,这样每个插件的包都很小,实现业务的拆分。所以需要是看你的场景。实际上对于大型app耦合型插件应用场景更多。
  • 半行代码:宿主工程跳转插件的activity时,报错:android.content.ActivityNotFoundException: Unable to find explicit activity class......... have you declared this activity in your AndroidManifest.xml?但是插件中的activity已经注册过了,为什么还会出现这样的异常呢,检查跳转的包名类名都没有错误,按照官方文档集成的,还有可能是什么问题呢?
    4636aedce931:遇到这个问题的朋友可以手动打开存储空间的权限解决!!!
  • 51815fd1aac5:宿主的路径是什么?
  • micheal_chen:插件正常生成,但是插件中png图片都是 黑色的图,这是什么原因。不知道楼主有没有在插件中放png 的图片
  • 745058404db3:您好,gradle-2.14.1-al 需要Android studio 2.2.x 2.3版本的无法使用吗?
    另外就是支持unity 导出的apk 吗? 谢谢啦:blush:
  • c5e74c2269e6:可以用Library作为宿主吗?
    我试了下,Library下不生成VAhost文件夹,编译插件失败:
    Can't find ../VirtualAPK-master/testlibrary/build/VAHost/Host_R.txt, please check up your host application need apply com.didi.virtualapk.host in build.gradle of host application

  • JackiePark:您好,我执行 gradle clean assemblePlugin的时候报:A problem occurred configuring project ':app'.
    > Can't find ..\host\app\build\VAHost\Host_R.txt, please check up your host application
    need apply com.didi.virtualapk.host in build.gradle of host application
    请问这个问题如何解决啊
    JackiePark:@piglet696 按照您说的,确实可以了,万分感谢!:pray:
    piglet696: @JackiePark 首先你的先编译宿主工程,会生成host
    JackiePark:是直接运行的您的demo
  • laifrog:同时加载两个插件,第二个插件的页面打不开,报setcontentView()的id找不到, Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x6f070003
    at android.content.res.Resources.getValue(Resources.java:1233)
    at android.content.res.Resources.loadXmlResourceParser(Resources.java:2598)
    at android.content.res.Resources.getLayout(Resources.java:1049)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:412)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:377)
    at android.app.Activity.setContentView(Activity.java:2144)
    at com.cantv.other.virtual.plugin.activity.StandardOtherActivity.onCreate(StandardOtherActivity.java:26) 还是的姿势不对?请大神指点。
  • b8fd6e64a2d5:你好 ,编译你的demo时报这个错
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.virtualapk.host/com.didi.virtualapk.core.A$1}: java.lang.ClassCastException: android.widget.Button cannot be cast to android.widget.ImageView
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)


    Caused by: java.lang.ClassCastException: android.widget.Button cannot be cast to android.widget.ImageView
    b8fd6e64a2d5:插件apk可以正常运行,这是为什么
  • 草蜢的逆袭:你好,环境不支持2.3.3的android studio吗,gradle 3.5我这边一运行gradle clean assemblePlugin报FAILURE: Build failed with an exception.

    * What went wrong:
    A problem occurred configuring project ':plugina'.
    > The directory of host application doesn't exist!

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.求解
    JackiePark:@syusikoku 您好,请问您具体是怎么解决的啊,我也遇到这个问题了,一直没解决。
    草蜢的逆袭: @piglet696 问题解决了,谢谢,我是下载下来,先来代理,啥都不管他,等他自己更新,然后解决的
    piglet696: @syusikoku 首先你这个错误提示的是宿主目录找不到,所以先看下插件target目录是否正确,在文章中有说明。第二个gradle版本建议先用文中所说
  • 0445981d6022:你好,按照楼主的方法操作,一直显示插件未加载,请重启app,可是重启还是不起作用。
    c8c928ed5b0b:@谢伊帕特里克寇马克 我也遇到相同的问题了,希望博主能帮助一下~
    0445981d6022:@piglet696 谢谢你的回复,插件存放的路径就是放在根目录下的,打debug,是能够找到这个apk的,报错是 android.content.pm.PackageParser$PackageParserException: Failed adding asset path: /storage/emulated/0/plugin.apk 。文件是在的,运行在6.0上,我追踪bug,在PackageParserCompat中执行PackageParserLollipop静态内部类的 parser.collectCertificates(pkg, flags);这个方法报错的,不知道什么原因,麻烦有空指导一下,谢了。
    piglet696: @谢伊帕特里克寇马克 看下代码,没加载是不是因为插件存放的路径不对
  • 56be6af42693:你好,我在写demo时候尝试了一下,宿主程序第一次加载插件然后进入插件界面没有问题,但是我完全杀死程序后(手机自带清理程序功能),再次进入时候需要重新加载插件。这样在实际应用中,如果用户吧插件apk删了,那岂不是不能进入插件界面了
    piglet696: @然后呢_dbac demo的话是放在SD卡,所以可以被删除。你也可以放在APP私有data下面,这样删除的概率会小很多。还需要从业务自身考虑该插件是否必须时刻存在来决定是否APP内置一个插件,还是选择云端下发加载。
  • 7e54bde5e9b7:在某些模拟器上测试有问题
  • Rave_Tian:写的非常好,正准备按照步骤一步步接入。顺便请教一下滴滴这个框架,对于插件管理这块(升级更新等)的操作细节。
  • 93e190379222:这个插件路径是指?
  • 2c4117a9984b:请教您,在编译宿主是否遇到这个问题:

    Error:Execution failed for task ':app_plugin:transformClassesAndResourcesWithStrippedForRelease'.
    > Cannot cast object 'null' with class 'org.codehaus.groovy.runtime.NullObject' to class 'java.util.Set'。
  • Zackratos:运行 demo 时,编译宿主和插件都会报一下错误,什么原因

    D:\GithubProjects\VirtualAPK>gradle clean iR
    Incremental java compilation is an incubating feature.

    FAILURE: Build failed with an exception.

    * What went wrong:
    A problem occurred configuring project ':AndroidStub'.
    > org.gradle.api.internal.tasks.DefaultTaskInputs$TaskInputUnionFileCollection cannot be cast to org.gradle.api.internal.file.collections.DefaultConfigurableFileCollection

    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    piglet696: @风魔龙郎 那你检查一下环境,看看是不是要求的环境
    Zackratos:@piglet696 就是官方的 demo 啊,github 上下载的
    piglet696: @风魔龙郎 可以把你的demo传到百度云发我链接看一下
  • 2c4117a9984b:"插件包均是Release包,不支持debug模式的插件包"

    这里 宿主包与插件包要都是release包吗?
    需要签名一致么?
    piglet696: @时光村落里的往事 这个官方wiki里有说明,你看一下
    2c4117a9984b:@piglet696 因为构建命令的原因 ?
    piglet696: @时光村落里的往事 宿主不需要,插件因为构建命令的原因所以生成的是release 。签名不需要一致
  • 2c4117a9984b:“targetHost指明宿主工程的应用模块,插件编译时需要获取宿主的一些信息,比如mapping文件、依赖的SDK版本信息、R资源文件,一定不能填错,否则在编译插件时会提示找不到宿主工程。”

    这里,随便写一个,编译插件时并不会报错啊。
    2c4117a9984b:还遇到一个问题,插件的生命周期走了,但是是白板 vaplugindemo SecondActivity onCreate
    2c4117a9984b:@piglet696 再请教一个问题,这边能加载成功,有跳转动作,但是是跳转到宿主的activity,是什么问题?
    piglet696: @时光村落里的往事 你要随便写会找不到宿主app工程会编译提示的
  • 69a430c37b1f:官方文档没有内置插件相关的说明? 部分模块希望可以直接在宿主程序中打包,如何处理?
    使用assets资源目录?
    piglet696: @甘宁KAZAMI 放在asset还是从服务端下载都可以的,看业务需求,插件框架只管加载,不关心插件来源
  • 776ab0ef6ef0:编译插件时,报下面错误,什么原因?
    org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:processReleaseResources'.

    Caused by: java.lang.NullPointerException: Cannot invoke method getAt() on null object
    at com.didi.virtualapk.aapt.ArscEditor.slice(ArscEditor.groovy:61)
    at com.didi.virtualapk.aapt.ArscEditor$slice.call(Unknown Source)
    at com.didi.virtualapk.aapt.Aapt.filterPackage(Aapt.groovy:51)
    at com.didi.virtualapk.aapt.Aapt$filterPackage$0.call(Unknown Source)
    at com.didi.virtualapk.merge.ResourceMerger$_merge_closure2.doCall(ResourceMerger.groovy:73)
    at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:590)
    at org.gradle.api.internal.AbstractTask$ClosureTaskAction.execute(AbstractTask.java:571)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    piglet696: @776ab0ef6ef0 插件中最少放一个资源
  • 开发者头条_程序员必装的App:感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/viuj57 欢迎点赞支持!
    欢迎订阅《Mob行者》https://toutiao.io/subjects/143291
  • MrZhousf:VirtualAPK自宣布开源以来,可查阅的资料的确太少了,作为原创团队的作者,能持续发表关于VirtualAPK技术细节文章,真的很不错!期待你的下篇文章...
  • d01785f0a2d4:按照文档接入后 跳转到插件Activity 但是界面还是显示宿主的Activity界面 插件Activity里面的Toast执行了。请问下怎么显示插件的界面呢
    piglet696:方便的话可以把你demo放到云盘共享我看一下什么原因
    d01785f0a2d4:@廷皓 :cold_sweat: 插件化还是又好多坑啊。今天试了RePlugin也好多坑
    674fa1c36ad3:对的对的 我也是 但是我连Toast都不执行 点击之后 还是显示宿主 只不过 主题变黑了

本文标题:VirtualAPK插件框架介绍(一)----框架接入

本文链接:https://www.haomeiwen.com/subject/sefbhxtx.html