Android 热修复,微信开源框架tinker的接入,就是这么简单
2017-01-18 19:49
861 查看
最近在弄热更新,看了几个开源框架,感觉微信的tinker不错,学习一下,但是发现官方文档给的实在蛋疼,全是坑,做个笔记记录一下,以后用的时候避过这些坑。
微信demo
下载下来以后有很多,直接把tinker-sample-android拿出来就好了,看这个就行了。
这个是官网给的接入指南,看下里边gradle的介绍
1.导入demo的问题,导入后你有可能遇见这个
tinkerId is not set!!!
找到你的moudle的build.gradle,在那里边有这个` tinkerId = “1.0”的配置我这直接给写死了
注意:这个你自己导入的时候最好是写你的版本号,因为这个是来判断到底你的修复的差别文件在那个上边使用,如果你像我一样写死你会发现你在更新包的时候,你的apk更新不了
2.运行demo在这块会生成你的apk包
![](http://img.blog.csdn.net/20170118190710623?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
3.然后你随意修改下代码
在你的gradle文件中修改tinkerOldApkPath
![](http://img.blog.csdn.net/20170118190911881?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
这个要和你上边生成的包名字保持一致
3.点击生成差别文件,debug和release看你是正式的还是测试的
![](http://img.blog.csdn.net/20170118191139900?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
4.等待运行完毕就会生成这个差别文件,没有生成差别文件的话你点击生成的log看看有什么错误,我运行的就有一个这个错误,
这个的话你修改下build里边的这个就好了,改成true
具体错误自己看下,很好理解。
![](http://img.blog.csdn.net/20170118191344110?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
5.生成差别包以后,demo里边会有一个loadpatch的按钮,把你的差别包拷贝进这个路径下,这是德莫的路径自己你可以自己定
装你原来的应用然后点击加载按钮,然后点击kill按钮杀死应用重新进入就是你改过的了。
接入常见问题
tinkerAPI
[b]******************************[/b]以上是导入demo********************************
集成进入项目
1.新建一个项目,找到你的project的gradle,引入这个,后边那个tinker_version是我在gradle.properties这个里边配置的版本,你也可以直接写,demo也有配置我就不在贴图了。
![](http://img.blog.csdn.net/20170118192808491?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
2.
(1.)找到model的gradle,进行配置,只贴一些必要的不必要的就不再贴了,添加依赖
![](http://img.blog.csdn.net/20170118193135742?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FvMTI2MTk3MTAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(2.)apk路径你可以自己定,
3.在代码中的使用,tinker定了一个自己的DefaultApplicationLike
我们的application得继承这个
在然后调用下这个代码
其他的生成差别文件这些和demo一样
最后在附上一个我写的一个下载差别文件的测试代码
最后附上一个通过修改class方式的 RocooFix热修复
微信demo
下载下来以后有很多,直接把tinker-sample-android拿出来就好了,看这个就行了。
这个是官网给的接入指南,看下里边gradle的介绍
1.导入demo的问题,导入后你有可能遇见这个
tinkerId is not set!!!
找到你的moudle的build.gradle,在那里边有这个` tinkerId = “1.0”的配置我这直接给写死了
注意:这个你自己导入的时候最好是写你的版本号,因为这个是来判断到底你的修复的差别文件在那个上边使用,如果你像我一样写死你会发现你在更新包的时候,你的apk更新不了
2.运行demo在这块会生成你的apk包
3.然后你随意修改下代码
在你的gradle文件中修改tinkerOldApkPath
这个要和你上边生成的包名字保持一致
3.点击生成差别文件,debug和release看你是正式的还是测试的
4.等待运行完毕就会生成这个差别文件,没有生成差别文件的话你点击生成的log看看有什么错误,我运行的就有一个这个错误,
Warning:ignoreWarning is false, but resources.arsc is changed
这个的话你修改下build里边的这个就好了,改成true
ignoreWarning = false
具体错误自己看下,很好理解。
5.生成差别包以后,demo里边会有一个loadpatch的按钮,把你的差别包拷贝进这个路径下,这是德莫的路径自己你可以自己定
Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed_7zip.apk"
装你原来的应用然后点击加载按钮,然后点击kill按钮杀死应用重新进入就是你改过的了。
接入常见问题
tinkerAPI
[b]******************************[/b]以上是导入demo********************************
集成进入项目
1.新建一个项目,找到你的project的gradle,引入这个,后边那个tinker_version是我在gradle.properties这个里边配置的版本,你也可以直接写,demo也有配置我就不在贴图了。
2.
(1.)找到model的gradle,进行配置,只贴一些必要的不必要的就不再贴了,添加依赖
(2.)apk路径你可以自己定,
//在build中创建一个bakApk文件夹 def bakPath = file("${buildDir}/bakApk/") ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? tinkerEnabled = true //旧版本apk路径配置 tinkerOldApkPath = "${bakPath}/app-debug-0118-16-57-13.apk" //用于混淆,没有混淆可以不管 tinkerApplyMappingPath = "${bakPath}/app-debug-1018-17-32-47-mapping.txt" //旧版本apk R文件 tinkerApplyResourcePath = "${bakPath}/app-debug-0118-16-43-45-R.txt" //only use for build all flavor, if not, just ignore this field tinkerBuildFlavorDirectory = "${bakPath}/app-1018-17-32-47" } //全局信息相关的配置项 tinkerPatch { // 基准apk包的路径,必须输入,否则会报错。 oldApk = tinkerOldApkPath // 在运行过程中,我们需要验证基准apk包与补丁包的签名是否一致,我们是否需要为你签名。 useSign = true ignoreWarning = true // 编译相关的配置项 buildConfig { // 在运行过程中,我们需要验证基准apk包的tinkerId是否等于补丁包的tinkerId. // 这个是决定补丁包能运行在哪些基准包上面,一般来说我们可以使用git版本号、versionName等等 tinkerId = "1.0" } packageConfig { configField("patchMessage", "tinker is sample to use") configField("platform", "all") configField("patchVersion", "1.0") } // dex相关的配置项 dex { /*只能是'raw'或者'jar'。 对于'raw'模式,我们将会保持输入dex的格式。 对于'jar'模式,我们将会把输入dex重新压缩封装到jar。 如果你的minSdkVersion小于14,你必须选择‘jar’模式,而且它更省存储空间, 但是验证md5时比'raw'模式耗时。默认我们并不会去校验md5,一般情况下选择jar模式即可。*/ dexMode = "jar" // 需要处理dex路径,支持*、?通配符,必须使用'/'分割。路径是相对安装包的,例如assets/.. pattern = ["classes*.dex", "assets/secondary-dex-?.jar"] /*这一项非常重要,它定义了哪些类在加载补丁包的时候会用到。 这些类是通过Tinker无法修改的类,也是一定要放在main dex的类。 这里需要定义的类有: 1. 你自己定义的Application类; 2. Tinker库中用于加载补丁包的部分类,即com.tencent.tinker.loader.*; 3. 如果你自定义了TinkerLoader,需要将它以及它引用的所有类也加入loader中; 4. 其他一些你不希望被更改的类,例如Sample中的BaseBuildInfo类。 这里需要注意的是,这些类的直接引用类也需要加入到loader中。或者你需要将这个类变成非preverify。 5. 使用1.7.6版本之后版本,参数1、2会自动填写。*/ loader = [ "tinker.sample.android.app.BaseBuildInfo" ] } // lib相关的配置项 lib { pattern = ["lib/armeabi/*.so", "lib/arm64-v8a/*.so", "lib/armeabi-v7a/*.so", "lib/mips/*.so", "lib/mips64/*.so", "lib/x86/*.so", "lib/x86_64/*.so"] } // res相关的配置项 res { pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] largeModSize = 100 ignoreChange = ["assets/sample_meta.txt"] } sevenZip { zipArtifact = "com.tencent.mm:SevenZip:1.1.10" } } List<String> flavors = new ArrayList<>(); project.android.productFlavors.each {flavor -> flavors.add(flavor.name) } boolean hasFlavors = flavors.size() > 0 android.applicationVariants.all { variant -> /** * task type, you want to bak */ def taskName = variant.name def date = new Date().format("MMdd-HH-mm-ss") tasks.all { if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) { it.doLast { copy { def fileNamePrefix = "${project.name}-${variant.baseName}" def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}" def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath from variant.outputs.outputFile into destPath rename { String fileName -> fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk") } from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt" into destPath rename { String fileName -> fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt") } from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt" into destPath rename { String fileName -> fileName.replace("R.txt", "${newFileNamePrefix}-R.txt") } } } } } } project.afterEvaluate { //sample use for build all flavor for one time if (hasFlavors) { task(tinkerPatchAllFlavorRelease) { group = 'tinker' def originOldPath = tinkerBuildFlavorDirectory for (String flavor : flavors) { def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release") dependsOn tinkerTask def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest") preAssembleTask.doFirst { String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15) project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk" project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt" project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt" } } } task(tinkerPatchAllFlavorDebug) { group = 'tinker' def originOldPath = tinkerBuildFlavorDirectory for (String flavor : flavors) { def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug") dependsOn tinkerTask def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest") preAssembleTask.doFirst { String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13) project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk" project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt" project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt" } } } } }
3.在代码中的使用,tinker定了一个自己的DefaultApplicationLike
我们的application得继承这个
@DefaultLifeCycle( application = "com.tinker.tinker.MyApplication", flags = ShareConstants.TINKER_ENABLE_ALL ) public class ApplicationLike extends DefaultApplicationLike { public ApplicationLike(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); TinkerInstaller.install(this); } }
在然后调用下这个代码
TinkerInstaller.onReceiveUpgradePatch(this.getApplication(),"你的差别文件的路径");
其他的生成差别文件这些和demo一样
最后在附上一个我写的一个下载差别文件的测试代码
url = "你的下载路径"; String s = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AAAAAA" + File.separator; File file = new File(s); if (!file.exists()) { file.mkdirs(); } patch = new File(s + "patch.apk"); if (!patch.exists()) { try { patch.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } new Thread(new Runnable() { @Override public void run() { try { URL url1 = new URL(url); HttpURLConnection connection = (HttpURLConnection) url1.openConnection(); if (connection.getResponseCode() == 200) { InputStream inputStream = connection.getInputStream(); byte[] bytes = new byte[1024]; int len; connection.connect(); FileOutputStream outputStream = new FileOutputStream(patch); while ((len = inputStream.read(bytes)) != -1) { outputStream.write(bytes, 0, len); } inputStream.close(); outputStream.close(); Log.e("下载", "下载---》patch成功"); } else { Log.e("下载", "下载---》patch失败"); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start();
最后附上一个通过修改class方式的 RocooFix热修复
相关文章推荐
- Tinker 1.7.11 发布,微信开源的 Android 热修复框架 - 开源中国社区
- android 微信热修复Tinker接入过程以及使用方法
- 微信开源的Android热补丁框架 Tinker
- Android 微信Tinker三分钟接入七分钟原理 让你成为热修复牛人
- Android热更新:微信Tinker框架的接入与测试
- Android 微信热修复 Tinker 接入过程及使用方法
- Android热修复框架 Tinker 接入
- Android热修复框架Tinker接入
- android 热修复框架Tinker的详细简单使用
- [Android]腾讯Tinker热修复框架简单使用
- Android热更新:微信Tinker框架的接入与测试
- Android 笔记: Tinker 热修复框架 简单上手教程
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理
- 小心,Android木马工具SpyNote免费啦!远程监听就是这么简单
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位...
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发
- 开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发
- 微信 Tinker 负责人张绍文关于 Android 热修复直播分享记录
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位网友补充完善
- 【开源框架】Android之史上最全最简单最有用的第三方开源库收集整理,有助于快速开发,欢迎各位网友补充完善