VirtualAPK学习

Activity加载

参考了鸿洋的博客:
https://blog.csdn.net/lmj623565791/article/details/75000580

 Activity:
 首先通过反射拿到了原本的Instrumentation对象,拿的过程是首先拿到ActivityThread,由于ActivityThread可以通过静态变量sCurrentActivityThread或者静态方法currentActivityThread()获取,所以拿到其对象相当轻松。拿到ActivityThread对象后,调用其getInstrumentation()方法,即可获取当前的Instrumentation对象。然后自己创建了一个VAInstrumentation对象,接下来就直接反射将VAInstrumentation对象设置给ActivityThread对象即可。

 hook Instrumentation的dispatchStubActivity方法,判断是否是启动插件类,是的话就选择一个坑位将真正的activity放在intent的响应变量中,启动activity的方法为:
 AMS在处理完启动Activity后,会调用:app.thread.scheduleLaunchActivity,这里的thread对应的server端未我们ActivityThread中的ApplicationThread对象(binder可以理解有一个client端和一个server端),所以会调用ApplicationThread.scheduleLaunchActivity方法,在其内部会调用mH类的sendMessage方法,传递的标识为H.LAUNCH_ACTIVITY,进入调用到ActivityThread的handleLaunchActivity方法->ActivityThread#handleLaunchActivity->mInstrumentation.newActivity()。

   还原Activity:
   在newActivity中替换要真正加载的activity,
   在callActivityOnCreate中设置了修改了mResources、mBase(Context)、mApplication对象。以及设置一些可动态设置的属性。



service:

创建一个代理service,hook住IActivityManager对象,里面是service的所有方法,当判断是插件service的时候,启动代理service,在代理service中的start。


BroadcastReceiver的支持:

    将静态代理转换为动态代理


ContentProvider:通过一个代理Provider进行分发。

资源加载

我们知道android资源加载是与AssetManager和Resources两个类有关的,AssetManager根据文件名加载资源,Resources先根据资源id获取资源名称,然后再根据AssetManager加载资源。先创建AssetManager,这个是一个native的方法,将系统资源和所对应的apk路径addAssetPath一个verctor集合中,在Resources创建的时候mResources指向的是一个ResTable对象,如果它的值不等于NULL,那么就说明当前应用程序已经解析过它使用的资源包里面的resources.arsc文件,因此,这时候AssetManager类的成员函数getResources就可以直接将该ResTable对象返回给调用者。如果还没有初始化 mResources 则按照一定步骤遍历当前应用所使用的每个资源包进而生成 mResources 。ResTable对象就是对应资源id 的一个列表。

VirtualAPk资源加载

virtual有两种模式:1.插件有一个独立的Resources,2.插件可以访问宿主的资源。
如果将宿主和插件隔离,我们只需要生成一个独立的Resources对象给插件使用,如果要调用宿主资源则需要将宿主的APK和插件的APK一起添加到同一个AssetManager里。

由于资源做过分区,则在Android L后直接将插件包的apk地址addAssetPath`之后就可以,但是在Android L之前,addAssetPath只是把补丁包加入到资源路径列表里,但是资源的解析其实是在很早的时候就已经执行完了,问题出现在这部分代码:

const ResTable* AssetManager::getResTable(bool required) const
{
    ResTable* rt = mResources;
    if (rt) {
        return rt;
    }
    //....

}

由于有系统资源的存在,mResources 的初始化在很早就初始化了,所以我们就算通过addAssetPath方法将 apk 添加到mAssetPaths里,在查找资源的时候也不会找到这部分的资源,因为在旧的 mResources 里没有这部分的 id。

所以在 Android L 之前是需要想办法构造一个新的AssetManager里的 mResources 才行,这里有两种方案,VirtualAPK 用的是类似 InstantRun 的那种方案,构造一个新的 AssetManager,将宿主和加载过的插件的所有 apk 全都添加一遍,然后再调用hookResources方法将新的 Resources 替换回原来的,这样会引起两个问题,一个是每次加载新的插件都会重新构造一个 AssetManger 和 Resources,然后重新添加所有资源,这样涉及到很多机型的兼容(因为部分厂商自己修改了 Resources 的类名),一个是需要有一个替换原来Resources的过程,这样就需要涉及到很多地方,从hookResources的实现里看,替换了四处地方,在尽量少的 hook 原则下这样的情况还是尽量避免的。

Activity 启动过程中对资源的处理

在newActivity中将新创建的Resources添加到要启动的activity中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VirtualAPK是一个Android插件化框架,可以将插件APK独立运行在宿主App中。以下是使用VirtualAPK的教程: 1. 配置Gradle依赖:在宿主App的build.gradle文件中添加VirtualAPK的依赖: ``` dependencies { ... compile 'com.didi.virtualapk:core:0.9.0' } ``` 2. 创建插件Module:在宿主App的项目中创建一个新的Module,作为插件的开发工程。 3. 配置插件的build.gradle:在插件Module的build.gradle文件中添加VirtualAPK的插件配置: ``` apply plugin: 'com.didi.virtualapk.plugin' virtualApk { packageId = 0x6f // 插件资源表中的packageId,需要确保不同插件有不同的packageId targetHost = '../VirtualAPKHostDemo/app' // 宿主工程application模块的路径,插件的构建需要依赖这个路径 applyHostMapping = true // 默认为true,如果插件有引用宿主的类,那么这个选项可以使得插件和宿主保持混淆一致 } ``` 4. 构建插件:在插件Module的根目录下运行以下命令进行插件构建: ``` ./gradlew clean virtualApkDebug ``` 5. 加载插件:在宿主App中的合适位置,使用VirtualAPK加载插件: ```java VirtualAPK virtualAPK = VirtualAPK.getInstance(context); virtualAPK.loadPlugin(new File(pluginPath)); ``` 6. 启动插件Activity:使用VirtualAPK启动插件中的Activity: ```java Intent intent = new Intent(); ComponentName componentName = new ComponentName("com.example.plugin", "com.example.plugin.PluginActivity"); intent.setComponent(componentName); context.startActivity(intent); ``` 以上是使用VirtualAPK的基本教程。在实际开发中,还可以参考VirtualAPK的官方文档和示例代码进行更详细的配置和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值