Android 插件开发实现
Android插件开发 老生常谈问题
1 Android类加载
PathClassLoader
DexClassLoader
两者都继承自BaseDexClassLoader
但是两者又有区别
PathClassLoader 是加载apk包的路径 比如/data/data/包名/XXXX.dex
DexClassLoader 可以加载指定apk包路径和dex文件解压路径 比如/sdcard
本文热更插件原理 基于tinker 原理实现
TINKER原理
1.使用DexClassLoader加载补丁包的dex文件
2.通过反射获取DexClassLoader类的pathList,再次通过反射获得dexElements数组。
3.获取加载应用类的PathClassLoader,同样通过反射获取它的dexElements数组。
4.合并两个dexElements数组,且将补丁包的dex文件放在前面。
代码实现
1 我们建一个需要fix 的类 MainActivity.java
package com.example.fixtest;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;public class MainActivity extends Activity {public TextView fixText ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fixText = findViewById(R.id.fixtext);testFix();myadd(2,3);}public void testFix(){fixText.setText("修复之前 显示错误");Log.e("mytag","fix before");}public int myadd(int a, int b){return a+b;}}
接来下我们骚骚修改一下 把修改的java 制作打包成dex
package com.example.fixtest;import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;public class MainActivity extends Activity {public TextView fixText ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fixText = findViewById(R.id.fixtext);testFix();myadd(2,3);}public void testFix(){fixText.setText("修复之后 显示正确");Log.e("mytag","fix before");}public int myadd(int a, int b){return a+b;}}
2 将java打包成dex
需要用到的工具 dx.bat
工具路径 \android-sdk-windows\build-tools\29.0.0
添加环境变量
使用
dx --dex --output=表示打包输出/hotfix.dex 表示原文件的路径名
将一下目录 打包为dex 也可以单独复制出来 我是单独复制出来的 删除了没有必要的类
单独复制出来
在 com 同级目录 执行一下命令既可以生成 dex
dx --dex --output=./hotfix.dex ./
由于我没有服务器 我直接复制到 项目的assets 下 然后拷贝到apk 的缓存目录 然后执行加载操作
public class MyAppliction extends Application {protected void attachBaseContext(Context base) {FixManeger.copyDex(base);FixManeger.loadDex(base);super.attachBaseContext(base);}
}
public class FixManeger {public static void copyDex(Context context) {File filedex = new File(context.getCacheDir() + "/hotfix.dex");if(filedex.exists()) {filedex.delete();}try {InputStream ins = context.getAssets().open("hotfix.dex");byte[] buffer = new byte[ins.available()];ins.read(buffer);ins.close();FileOutputStream outs = new FileOutputStream(filedex);outs.write(buffer);outs.close();}catch(Exception e) {e.printStackTrace();}}public static void loadDex(Context context) {File filedex = new File(context.getCacheDir() + "/hotfix.dex");if(filedex.exists()) {try { //通过反射获取dexElements 成员 ClassLoader classLoader = context.getClassLoader();Field pathListField = BaseDexClassLoader.class.getDeclaredField("pathList");pathListField.setAccessible(true);Object pathListObject = pathListField.get(classLoader);Field dexElementsField = pathListObject.getClass().getDeclaredField("dexElements");dexElementsField.setAccessible(true);Object dexElementsObject = dexElementsField.get(pathListObject);Object newDexElementsObject = dexElementsField.get(pathListField.get(new PathClassLoader(filedex.getPath(), classLoader.getParent())));int oldLength = Array.getLength(dexElementsObject);int newLength = Array.getLength(newDexElementsObject);//开始拼接dexObject concatDexElementsObject = Array.newInstance(dexElementsObject.getClass().getComponentType(), oldLength + newLength);//加载新的dexint i;for(i = 0; i < newLength; ++i) {Array.set(concatDexElementsObject, i, Array.get(newDexElementsObject, i));}//加载原有的dexint oldindex = 0;while(oldindex < oldLength) {Array.set(concatDexElementsObject, newLength + oldindex, Array.get(dexElementsObject, oldindex));++oldindex;classLoader = classLoader;}dexElementsField.set(pathListObject, concatDexElementsObject);}catch(NoSuchFieldException e) {e.printStackTrace();}catch(IllegalAccessException e) {e.printStackTrace();}return;}}
}
Android 插件开发实现相关推荐
- android插件框架机制的选择,Android插件开发初探——基础篇
Android插件开发初探 对于Android的插件化其实已经讨论已久了,但是市面上还没有非常靠谱成熟的插件框架供我们使用.这里我们就尝试性的对比一下Java中,我们使用插件化该是一个怎么样的流程,且 ...
- android插件开发,使用360加固自动多渠道打包
android插件开发,使用360加固自动多渠道打包 最近研究了一下安卓插件的开发,就以开发一个360加固自动打包插件为例,练了一下,本次使用android studio基于kotlin构建自动打包插 ...
- Android插件开发初探——分析篇
承接上文 Android插件开发初探--基础篇 http://blog.csdn.net/yzzst/article/details/45582315 我们通过使用DexClassLoader能够将c ...
- 谷歌浏览器android插件开发工具,ARC Welder:在谷歌浏览器运行安卓APK
ARC Welder插件开发背景 现在的手机操作系统是IOS和Android的天下,很多开发人员之前想要在电脑上跑 Android APP,大部份都是安装模拟器,但这些模拟器有些并不是太好用,或是安装 ...
- 如何导出android studio程序,Android Studio 如何导出 Jar 给 Unity 使用
大致步骤如下:1.创建新的 Android Studio 工程2.为此 Android Studio 工程创建 Android Library 类库(也就是一个 Module)(后面就是用它生成 ja ...
- 插件开发遇到的坑------final 型变量,编译过程被优化
android 插件开发遇到的坑 今天遇到一个坑,pdf 插件,调用了主工程的一个静态final 字符串,但是主工程里面已经没有这个字符串了,却没有崩溃. 后来同事说,因为字符串可能已经直接被写死了. ...
- c 调用 android jar包,Unity调用AndroidStudio导出的Jar包
8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 课程内容制作步骤介绍 创建AndroidStudio工程及Jar包导出 Unity中调用Jar包函数 制作步骤 大致步骤 ...
- 未配置appkey或配置错误,uniapp原生安卓插件开发
开发安卓原生插件 一.官方文档 1.https://nativesupport.dcloud.net.cn/NativePlugin/course/android 2.下载对应的SDK.工程文件 二. ...
- 初学者---Android 学习资料
转自: 1.hanhailong/AndroidStudyResources https://github.com/hanhailong/AndroidStudyResources 2.Android ...
最新文章
- Magento 模版路径
- php mysql 配置
- python2和3的区别字符编码格式上下文管理is和==的区别
- kotlin学习笔记——Kotlin Android Extensions
- 为什么我不信任通配符,以及为什么我们仍然需要通配符
- 三角形数、五边形数和六角形数
- 如何在.NET控制台应用程序中获取应用程序的路径?
- linux mint 18安装中文,无法在Linux Mint 18.1“Serena”下安装pyFFTW
- 每天备份数据库中的表
- 线性代数 n维向量思维导图总结(看这一张就完事了)
- 有效沟通bic法则_职场中5个有效沟通的法则
- 程序员的8个职业发展方向,了解一下!
- 1894 完美的牛栏
- MySQL数据库表数据迁移--ibd的使用
- ABO区块链在医疗行业中的重要作用
- mac OS系统中 设置ssh连接端口
- 智能电视是否是一台计算机,误区四 智能电视代替电脑使用_平板电视_液晶电视评测-中关村在线...
- 线性代数需要注意的一些点
- java 进阶笔记线程与并发之ForkJoinPool简析
- 在VMware中安装CentOS7(超详细的图文教程)
热门文章
- gc日志一般关注什么_理解GC日志
- 腾讯云「轻量应用服务器」开放公测!
- 嵌入式单片机基础篇(一)之stm32F1GPIO详解
- python 请在微信客户端打开_完美解决 请在微信客户端打开链接
- nginx 之 http 转 https (两种方式)
- js获取当前日期,并且转化为时间格式“yyyy-MM-dd HH:MM:SS”
- 古有陈天华万字血书抗沙俄,今有本剧蒻万字背包虐dp(01,完全,多重,分组,混合等各种背包详解 + 板子题+ 奇奇怪怪滴变式题)
- 天猫精灵连接蓝牙摸索1 关于阿里巴巴蓝牙MESH芯片TG7100B LINUX 开发环境塔建图文说明
- 五位本科生4个月造出芯片毕业!新的后续来了……
- 梅长苏:因为人的心,会变得越来越硬