Android热修复(一):Tinker的使用(一)命令行接入
程序员文章站
2024-03-20 19:16:52
...
介绍
Tinker是微信官方的Android热补丁解决方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。当然,你也可以使用Tinker来更新你的插件。
它主要包括以下几个部分:
gradle编译插件(主要是为了帮助我们在Android Studio直接生成patch文件): tinker-patch-gradle-plugin
核心sdk库(tinker为用户提供的所有的api): tinker-android-lib
非gradle编译用户的命令行版本(主要是为了使用命令行来生成patch文件): tinker-patch-cli.jar
现在有许多热修复方案,比如说我上次介绍的阿里的AndFix,美团的Robust,QQ空间的超级补丁方案,那么我们为什么还要去学习Tinker呢?Tinker的优势在哪里呢?
总的来说:
1、AndFix作为native解决方案,首先面临的是稳定性与兼容性问题,更重要的是它无法实现类替换,它是需要大量额外的开发成本的;
2、Robust兼容性与成功率较高,但是它与AndFix一样,无法新增变量与类只能用做的bugFix方案;
3、Qzone方案可以做到发布产品功能,但是它主要问题是插桩带来Dalvik的性能问题,以及为了解决Art下内存地址问题而导致补丁包急速增大的。
Tinker的集成
添加依赖
//自定义注解库 生成application时使用
provided 'com.tencent.tinker:tinker-android-anno:1.7.7'
//tinker核心库
compile 'com.tencent.tinker:tinker-android-lib:1.7.7'
//支持分包,不需要分包可以不导入
compile 'com.android.support:multidex:1.0.1'
Tinker初始化
//判断是否安装(初始化)tinker
private static boolean isInstalled = false;
private static ApplicationLike mAppLike;
......
//初始化tinker
public static void installTinker(ApplicationLike applicationLike){
mAppLike = applicationLike;
if(isInstalled){
return;
}else {
TinkerInstaller.install(applicationLike);
isInstalled = true;
}
}
Tinker不能直接调用它的初始化方法,而是需要在ApplicationLike中去使用。先创建一个ApplicationLike的类,然后在onBaseContextAttached()方法中去调用它的初始化方法。
@DefaultLifeCycle(application = ".MyApplication", flags = ShareConstants.TINKER_ENABLE_ALL,
loadVerifyFlag = false)
public class CustomTinkerLike extends ApplicationLike {
public CustomTinkerLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag,
long applicationStartElapsedTime, long applicationStartMillisTime,
Intent tinkerResultIntent) {
super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime,
applicationStartMillisTime, tinkerResultIntent);
}
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
//使用multidex,使应用支持分包
MultiDex.install(base);
//初始化tinker
TinkerPatchManager.installTinker(this);
}
}
然后rebuild一下项目,然后就会生成MyApplication.
可以在manifest来使用这个application
Patch文件的加载
//加载patch
public static void loadPatch(String path){
if(Tinker.isTinkerInstalled()){
TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),path);
}
}
//通过ApplicationLink获取Context
private static Context getApplicationContext(){
if(mAppLike != null){
return mAppLike.getApplication().getApplicationContext();
}
return null;
}
Tinker的使用
首先和上篇AndFix的使用一样,我们首先构建出存放patch文件的路径,即我们要加载的patch文件的路径。
//patch文件后缀名
private static final String FILE_END = ".apk";
//patch文件的路径
private String mPatchDir;
......
mPatchDir = getExternalCacheDir().getAbsolutePath() + "/tpatch/";
Log.v("xq_msg", "path: " + mPatchDir);
//创建文件夹
File file = new File(mPatchDir);
if (file == null || !file.exists()) {
file.mkdir();
}
......
//构造patch文件名
private String getPatchName() {
return mPatchDir.concat("xq_sq").concat(FILE_END);
}
然后写一个按钮来调用我们加载patch文件的方法
//加载patch
public void loadPatch(View view) {
TinkerPatchManager.loadPatch(getPatchName());
}
再在我们的Manifest文件中添加
//用来判断这个patch文件是否能加载到我们的手机当中,只有当patch文件的id和我们手机中的apk的id一致才能加载
<meta-data
android:name="TINKER_ID"
android:value="tinker_id_1"/>
接着打出老的apk(签名版),先保存一份(我们后面还需要用它来生成patch文件),再安装到手机中。我们再修改一下代码(例如我们修改一下布局,增加一个按钮,然后打包,打出新的apk)
生成patch文件(使用命令行)
首先我们需要先下载命令行工具(链接在文章末尾),它主要包括下图圈出来的几个部分,其他是我们生成命令行需要的一些文件
然后我们需要去修改tinker_config.xml文件的2个地方,如下图所示,一个是loader,我们需要改成我们的application的全路径,一个是最下面的签名文件的一个配置
然后我们就可以使用我们的命令来生成我们的patch文件了。
java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output_path
我们对应修改一些来执行我们的命令
java -jar tinker-patch-cli-1.7.7.jar -old tinker_old.apk -new tinker_new.apk -config tinker_config.xml -out output/
然后我们可以在我们的output文件夹中去找到我们的生成的patche文件
我们需要的就是这签名了patch文件,然后我们使用adb命令来将这个文件push到我们代码中对应的目录下,然后点击loadPatch按钮,应用自动重启,再次打开我们会发现,我们新增的按钮已经出现了。这个使用命令行来接入Tinker与我们上次讲到的AndFix的使用是没有太大的区别。但是我们在实际项目中都是使用配置gradle文件来使用我们的Tinker的,这个我们在后续的文章中也会讲到具体的是怎么使用配置gradle文件使用Tinker的。