系列文章

HOOK技术一-HOOK技术初探
HOOK技术二-未注册Activity的启动
HOOK技术三-插件Activity启动前提分析
HOOK技术四-插件中Activity启动实战
HOOK技术五-使用LoadedApk式插件化的理论分析
HOOK技术六-LoadedApk式插件化代码实现
HOOK技术七-版本适配及总结

说明

上篇文章中,我们已经分析了, 如果要启动插件中的Activity, 就需要将插件的element与宿主的element融合成一个整的element,然后设置给BaseDexClassLoader。这里还有有一个问题,虽然说Activity的class可以通过这样的方式加载,但是资源文件却不行,资源文件的加载是靠AssetManager和Resource加载的,所以插件中使用AssetManager和Resource时,要避免使用宿主的,否则会加载宿主的资源文件,造成类加载正确但是资源文件加载错误的情况。

整合Element

 /*** 把插件的dexElements 和 宿主中的 dexElements 融为一体*/private void pluginToAppAction() throws Exception {// 第一步:找到宿主 dexElements 得到此对象   PathClassLoader代表是宿主PathClassLoader pathClassLoader = (PathClassLoader) this.getClassLoader(); // 本质就是PathClassLoaderClass mBaseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");// private final DexPathList pathList;Field pathListField = mBaseDexClassLoaderClass.getDeclaredField("pathList");pathListField.setAccessible(true);Object mDexPathList = pathListField.get(pathClassLoader);Field dexElementsField = mDexPathList.getClass().getDeclaredField("dexElements");dexElementsField.setAccessible(true);// 本质就是 Element[] dexElementsObject dexElements = dexElementsField.get(mDexPathList);/*** ---------------------- ***/// 第二步:找到插件 dexElements 得到此对象,代表插件 DexClassLoader--代表插件File file = new File(Environment.getExternalStorageDirectory() + File.separator + "p.apk");if (!file.exists()) {throw new FileNotFoundException("没有找到插件包!!");}String pluginPath = file.getAbsolutePath();File fileDir = this.getDir("pluginDir", Context.MODE_PRIVATE); // data/data/包名/pluginDir/DexClassLoader dexClassLoader = newDexClassLoader(pluginPath, fileDir.getAbsolutePath(), null, getClassLoader());Class mBaseDexClassLoaderClassPlugin = Class.forName("dalvik.system.BaseDexClassLoader");// private final DexPathList pathList;Field pathListFieldPlugin = mBaseDexClassLoaderClassPlugin.getDeclaredField("pathList");pathListFieldPlugin.setAccessible(true);Object mDexPathListPlugin = pathListFieldPlugin.get(dexClassLoader);Field dexElementsFieldPlugin = mDexPathListPlugin.getClass().getDeclaredField("dexElements");dexElementsFieldPlugin.setAccessible(true);// 本质就是 Element[] dexElementsObject dexElementsPlugin = dexElementsFieldPlugin.get(mDexPathListPlugin);// 第三步:创建出 新的 dexElements []int mainDexLeng =  Array.getLength(dexElements);int pluginDexLeng =  Array.getLength(dexElementsPlugin);int sumDexLeng = mainDexLeng + pluginDexLeng;// 参数一:int[]  String[] ...  我们需要Element[]// 参数二:数组对象的长度// 本质就是 Element[] newDexElementsObject newDexElements = Array.newInstance(dexElements.getClass().getComponentType(),sumDexLeng); // 创建数组对象// 第四步:宿主dexElements + 插件dexElements =----> 融合  新的 newDexElementsfor (int i = 0; i < sumDexLeng; i++) {// 先融合宿主if (i < mainDexLeng) {// 参数一:新要融合的容器 -- newDexElementsArray.set(newDexElements, i, Array.get(dexElements, i));} else { // 再融合插件的Array.set(newDexElements, i, Array.get(dexElementsPlugin, i - mainDexLeng));}}// 第五步:把新的 newDexElements,设置到宿主中去// 宿主dexElementsField.set(mDexPathList, newDexElements);// 处理加载插件中的布局doPluginLayoutLoad();}

为插件创建AssetManager和Resource

  private Resources resources;private AssetManager assetManager;/*** 处理加载插件中的布局* Resources*/private void  doPluginLayoutLoad() throws Exception {assetManager = AssetManager.class.newInstance();// 把插件的路径 给 AssetManagerFile file = new File(Environment.getExternalStorageDirectory() + File.separator + "p.apk");if (!file.exists()) {throw new FileNotFoundException("没有找到插件包!!");}// 执行此 public final int addAssetPath(String path) 方法,才能把插件的路径添加进去Method method = assetManager.getClass().getDeclaredMethod("addAssetPath", String.class); // 类类型method.setAccessible(true);method.invoke(assetManager, file.getAbsolutePath());Resources r = getResources(); // 拿到的是宿主的 配置信息// 实例化此方法 final StringBlock[] ensureStringBlocks()Method ensureStringBlocksMethod = assetManager.getClass().getDeclaredMethod("ensureStringBlocks");ensureStringBlocksMethod.setAccessible(true);ensureStringBlocksMethod.invoke(assetManager); // 执行了ensureStringBlocks  string.xml  color.xml   anim.xml 被初始化// 特殊:专门加载插件资源resources = new Resources(assetManager, r.getDisplayMetrics(), r.getConfiguration());}@Overridepublic Resources getResources() {return resources == null ? super.getResources() : resources;}@Overridepublic AssetManager getAssets() {return assetManager == null ? super.getAssets() : assetManager;}

插件中的所有Activity使用AssetManager或者Resource时,都要从上面这个代码里面取,否则加载的资源文件会有问题的。
在插件中新建BaseActivity

public class BaseActivity extends Activity {@Overridepublic Resources getResources() {if (getApplication() != null && getApplication().getResources() != null) {return getApplication().getResources();}return super.getResources();}@Overridepublic AssetManager getAssets() {if (getApplication() != null && getApplication().getAssets() != null) {return getApplication().getAssets();}return super.getAssets();}
}

插件的所有Activity继承BaseActivity,如下所示

public class TestActivity extends BaseActivity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);Toast.makeText(this, "我是插件里的Activity", Toast.LENGTH_SHORT).show();}
}

启动测试

在宿主中增加跳转事件

    public void startTestActivity(View view) {// 启动插件中的ActivityIntent intent = new Intent();intent.setComponent(new ComponentName("com.sanguine.placeholder.plugin", "com.sanguine.placeholder.plugin.TestActivity"));startActivity(intent);}

最终

HOOK技术四-插件中Activity启动实战相关推荐

  1. Android中Activity启动模式详解

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  2. Android中Activity启动模式

    Android中Activity启动模式一共是四种,这里我写一下我对其的理解: 1.standard(默认) 2.singleTop,如果某个Activity设置了该属性,且当前Activity就是这 ...

  3. And解roid中Activity启动模式详

    转自: http://www.cnblogs.com/fanchangfa/archive/2012/08/25/2657012.html And解roid中Activity启动模式详 在Androi ...

  4. 【Android 插件化】Hook 插件化框架总结 ( 插件包管理 | Hook Activity 启动流程 | Hook 插件包资源加载 ) ★★★

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  5. 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 主线程创建 Activity 实例之前使用插件 Activity 类替换占位的组件 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  6. 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  7. Android APP热更新中的插件化(Hook技术:反射或动态代理),Demo (2)

    修改AAPT,资源分区,用于Android插件化- https://github.com/BaoBaoJianqiang/AAPT -- Android下的挂钩(hook)和代码注入(inject) ...

  8. html获取此次点击的id,github项目解析(八)--Activity启动过程中获取组件宽高的三种方式...

    转载请标明出处:1片枫叶的专栏 上1个github小项目中我们介绍了避免按钮重复点击的小框架,其实现的核心逻辑是重写OnClickListener的onClick方法,添加避免重复点击的逻辑,即为第2 ...

  9. framework之Activity启动流程(基于Android11源码)

    一步步看,你就会对activity的启动流程有深刻的认知. 引言 Android11上,Activity的启动流程与Android10的实现(可以参考Activity的启动过程详解(基于10.0源码) ...

最新文章

  1. iOS面试准备之思维导图
  2. Could not find action or result
  3. Objective-C iOS纯代码布局 一堆代码可以放这里!
  4. JavaSE(二十二)——TCP协议的三次握手
  5. numberformate php_php number_format函数怎么用?
  6. 西南科技大学研究生计算机,我们毕业啦……西南科技大学2020研究生毕业记!...
  7. Two-Stream RNN/CNN for Action Recognition in 3D Videos-阅读笔记
  8. SpringBoot @Cacheable缓存入门程序
  9. C# —— IEnumerable和状态机
  10. 基于Maven的S2SH(Struts2+Spring+Hibernate)框架搭建
  11. 初学C++——VS2013开发工具包下载及破解
  12. 宠物管理系统mysql_基于java+MySQL的宠物管理系统
  13. linux系统怎么拨号上网,linux配置上网 linux adsl拨号上网设置
  14. Qt报错 error: C1083
  15. Android7.0调用系统相机拍照、读取系统相册照片+CropImageView剪裁照片
  16. 计量经济学学习笔记:多重共线性、异方差、自相关
  17. 【Visual C++】游戏开发笔记三十二 浅墨DirectX提高班之一 DirectX大局观认知篇
  18. python的describe参数_Python Pandas Series.describe()用法及代码示例
  19. 两种Random函数的使用
  20. 多目标/单-VRT路径规划-更新汇总

热门文章

  1. 利用Tushare获取A股所有股票代码
  2. 洛谷P1789 【Mc生存】插火把
  3. 删除文件时提示需要administrator 权限
  4. 1月16日服务器例行维护更新公告,1月16日例行维护暨版本更新公告
  5. Word2016中文字间距突然变大了是怎么回事?
  6. tp5利用redis缓存制作qq邮箱验证
  7. Frame-Pannel-Button综合
  8. You Dont Know JS 中文版
  9. 【通信】盖氏圆盘方法(GDE)计算均匀直线阵(ULA)中信号源个数附matlab代码
  10. 计算机开机错误62,电脑开机出现Error 1962错误如何解决?