零蚀
[🔗 tinker 官方文档]
-
step 1 配置
前言:Tinker文档写的比较抽象, 要多看看网上如何解决问题,尤其在打包错误时,要多看输出信息来给错误定位,网上有很多错误的信息。而且版本不一样,代码也不同。毕竟现在崇尚傻瓜式的操作。
我一直以为腾讯只有充钱才能快乐,没想到tinker可以免费30天,享受人名币玩家待遇
官网配置
注意这个版本号,这个版本号需要和你的基准包(也就是你发生bug需要改动的包版本号一致),保证两号一致(补丁包没有要求),就可以开始dex下发,合成了。
依赖
// -------------- project -------------- // thinker classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.14.6" // -------------- module -------------- android { compileSdkVersion projcompileSdkVersion buildToolsVersion projbuildToolsVersion defaultConfig { ...... multiDexEnabled true } ..... signingConfigs { config { keyAlias 'xxxxxx' keyPassword '123456' storeFile file('/Users/baicha/workspace/android/temp/xxxxxx/key/xxxxxx.keystore') storePassword '123456' } debug { keyAlias 'xxxxxx' keyPassword '123456' storeFile file('/Users/baicha/workspace/android/temp/xxxxxx/key/xxxxxx.keystore') storePassword '123456' } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } debug{ signingConfig signingConfigs.debug } } dexOptions { javaMaxHeapSize "2g" preDexLibraries = false jumboMode = true } } apply from: 'tinkerpatch.gradle' // thinker api "com.android.support:multidex:1.0.3" // 这个要在主module中 annotationProcessor("com.tinkerpatch.tinker:tinker-android-anno:1.9.8") compileOnly("com.tinkerpatch.tinker:tinker-android-anno:1.9.8") api("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.8")
-
step 2 构建
application
open class BaseApplication : Application() { override fun onCreate() { super.onCreate() ... tinker() } ...... private fun tinker(){ // 我们可以从这里获得Tinker加载过程的信息 val tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike(); // 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK TinkerPatch.init(tinkerApplicationLike) .reflectPatchLibrary() .fetchPatchUpdate(true) .setPatchRollbackOnScreenOff(true) .setPatchRestartOnSrceenOff(true) //.setFetchPatchIntervalByHours(3) .setPatchResultCallback{ if(it.isSuccess){ LogUtil.e("Result:Success") try { val rawFile = File(it.rawPatchFilePath) if (rawFile.exists()) { SharePatchFileUtil.safeDeleteFile(rawFile) } }catch (e:Exception){ LogUtil.e("Result:${e.message}") } }else{ LogUtil.e("已经安装了") } } .setPatchRollBackCallback{ LogUtil.e("RollBackCallback") } // 获取当前的补丁版本 LogUtil.d( "Current patch version is " + TinkerPatch.with().patchVersion) // fetchPatchUpdateAndPollWithInterval 与 fetchPatchUpdate(false) // 不同的是,会通过handler的方式去轮询 TinkerPatch.with().fetchPatchUpdate(true) // 每隔3个小时(通过setFetchPatchIntervalByHours设置)去访问后台时候有更新,通过handler实现轮训的效果 //TinkerPatch.with().fetchPatchUpdateAndPollWithInterval() } }
构建tinkerpatch.gradle 必须在主module(app:)下
apply plugin: 'tinkerpatch-support' /** * TODO: 请按自己的需求修改为适应自己工程的参数 */ def bakPath = file("${buildDir}/bakApk/") def baseInfo = "app-2.0.0-0407-14-46-01" def variantName = "debug" /** * 对于插件各参数的详细解析请参考 * http://tinkerpatch.com/Docs/SDK */ tinkerpatchSupport{ /** 可以在debug的时候关闭 tinkerPatch **/ tinkerEnable = true /** 是否使用一键接入功能 **/ reflectApplication = true /** 是否开启加固模式,只有在使用加固时才能开启此开关 **/ protectedApp = false /** 补丁是否支持新增 Activity (exported必须为false)**/ supportComponent = false autoBackupApkPath = "${bakPath}" /** 在tinkerpatch.com得到的appKey **/ appKey = "ef885584b5xxxxxx" /** 注意: 若发布新的全量包, appVersion一定要更新 **/ appVersion = "$appVersionName" def pathPrefix = "${bakPath}/${baseInfo}/${variantName}" def name = "${project.name}-${variantName}" baseApkFile = "${pathPrefix}/${name}.apk" baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt" baseResourceRFile = "${pathPrefix}/${name}-R.txt" } /** * 用于用户在代码中判断tinkerPatch是否被使能 */ android { defaultConfig { buildConfigField "boolean", "TINKER_ENABLE", "${tinkerpatchSupport.tinkerEnable}" } } /** * 一般来说,我们无需对下面的参数做任何的修改 * 对于各参数的详细介绍请参考: * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 */ tinkerPatch { ignoreWarning = true tinkerEnable=true useSign = true dex { dexMode = "jar" pattern = ["classes*.dex"] loader = [] } lib { pattern = ["lib/*/*.so"] } res { pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] ignoreChange = [] largeModSize = 1000 } packageConfig { } sevenZip { zipArtifact = "com.tencent.mm:SevenZip:1.1.10" // path = "/usr/local/bin/7za" } buildConfig { keepDexApply = false } }
当我们到这一步可以打一个基准包,就是你需要改动的那个包。我们可以发现生成了对应的目录,这样就生成了基准包。
然后我们需要注意基准包的信息一定要对的上
然后生成补丁,补丁中有一个old文件,一个new文件,这就是将前后的apk进行对比,从而来拿出其中不一样的dex文件,然后作出新的包含差异的dex文件的apk,使在list_dexs时,可以先加载这个差异的dex,从而避免掉之前的bug。(含有补丁的包,目前没有用)
多说一句,为什么要重启,因为要重新加载dex文件,在类加载器之前把我们需要的内容注入。当然这里可以代码重启。
🔗 前言
🔗 Android Temporary
🔗 NO.1 Retrofit
🔗 NO.2 CameraX
🔗 NO.3 GreenDao(&加密问题)