Tinker是腾讯推出的一个热修复的SDK,目前看来,很好用。Tinker可以使用它提供的后台,也可以不使用,本文没有使用Tinker的后台。要使用Tinker,其实还有很多要注意的地方。Tinker的文档很多,理解透彻也很难,不适合理解能力差的开发者。本文不教你Tinker的基本用法,基本用法参考https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97。本文要教你需要注意哪些地方。
1.TINKER_ID,它是作为基准包的标识的,比如旧版本的包(即安装在手机的包)和新旧版本包的补丁,它们的TINKER_ID应该是一样的,它内部是根据它完成修复的。
2.需要配置
javaCompileOptions {
//Tinker需要
annotationProcessorOptions {
includeCompileClasspath = true
}
}
3.Tinker的混淆是必须的,否则会修复失败
multiDexKeepProguard file("tinker_multidexkeep.pro")
4.修复的补丁是覆盖的
比如A+补丁B,会换成A+补丁C,而不是A+B+C
5.什么情况可以修复,什么情况不可以修复
(1)可以新增普通的Java方法,不带res资源
(2)可以删除普通的Java方法,不带res资源
(3)可以修改普通的Java方法,不带res资源
(4)不可以在清单文件新增组件,如Activity
(5)基准包中使用了tools:replace="android:label”,而第三方库中带有AndroidManife.xml中没有要求替换,会修复失败,通常是第三方库没有删除掉app模块导致的
(6)第三方库minSdk大于基准包的minSdk,会修复失败
下面给你介绍几个关键类的写法。
class MusicApp(private val application: Application?) : Application(), AppConfig {
/**
* 全局的音乐播放控制管理器。
*/
var mediaManager: MediaManager? = null
private set
/**
* 内存泄漏检测。
*/
private var refWatcher: RefWatcher? = null
companion object {
/**
* 全局Application单例。
*/
@JvmStatic
var instance: MusicApp? = null
private set
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
//dex分包
MultiDex.install(base)
}
}
原自定义的Application要组合一个Application类,这个传入的Application来自Tinker自动生成的。这样你在你的自定义Application也可以拿到Context。
package site.doramusic.app.tinker
import android.annotation.TargetApi
import android.app.Application
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.multidex.MultiDex
import com.tencent.tinker.anno.DefaultLifeCycle
import com.tencent.tinker.entry.DefaultApplicationLike
import com.tencent.tinker.lib.tinker.Tinker
import com.tencent.tinker.lib.tinker.TinkerInstaller
import com.tencent.tinker.loader.shareutil.ShareConstants
import site.doramusic.app.MusicApp
import site.doramusic.app.base.conf.AppConfig
import site.doramusic.app.tinker.log.TinkerLog
import site.doramusic.app.tinker.util.TinkerManager
/**
* because you can not use any other class in your application, we need to
* move your implement of Application to [ApplicationLifeCycle]
* As Application, all its direct reference class should be in the main dex.
*
* We use tinker-android-anno to make sure all your classes can be patched.
*
* application: if it is start with '.', we will add SampleApplicationLifeCycle's package name
*
* flags:
* TINKER_ENABLE_ALL: support dex, lib and resource
* TINKER_DEX_MASK: just support dex
* TINKER_NATIVE_LIBRARY_MASK: just support lib
* TINKER_RESOURCE_MASK: just support resource
*
* loaderClass: define the tinker loader class, we can just use the default TinkerLoader
*
* loadVerifyFlag: whether check files' md5 on the load time, defualt it is false.
*
*/
@DefaultLifeCycle(application = "site.doramusic.app.AppLoader", flags = ShareConstants
.TINKER_ENABLE_ALL, loadVerifyFlag = false)
class TinkerApplicationLike(application: Application, tinkerFlags: Int, tinkerLoadVerifyFlag: Boolean,
applicationStartElapsedTime: Long, applicationStartMillisTime: Long,
tinkerResultIntent: Intent?) : DefaultApplicationLike(application, tinkerFlags,
tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent) {
private var musicApp: MusicApp? = null
init {
musicApp = MusicApp(application)
}
override fun onCreate() {
super.onCreate()
musicApp!!.onCreate()
}
/**
* install multiDex before install tinker
* so we don't need to put the tinker lib classes in the main dex
*
* @param base
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
override fun onBaseContextAttached(base: Context) {
super.onBaseContextAttached(base)
MultiDex.install(base)
TinkerManager.setTinkerApplicationLike(this)
TinkerManager.initFastCrashProtect()
TinkerManager.setUpgradeRetryEnable(true)
TinkerInstaller.setLogIml(TinkerLog())
TinkerManager.installTinker(this)
TinkerManager.loadPatch(AppConfig.FOLDER_PATCH + "/patch_signed.apk")
Tinker.with(application)
}
}
这个Tinker的ApplicationLike用来生成Application,那个Tinker的Application入口。其他类使用Tinker官方Demo的代码就可以了。
最后注意一点,所有在你原先自定义Application的所有用到this拿上下文的地方,都要使用传入的这个,即Tinker生成的Application。