最近项目由于急匆匆上线,导致有低级bug出现,由于没有集成热更新,所以修复玩这些bug后还要打新版本的apk包,造成用户抱怨,所以集成热更新:然后就了解了现在的热更新框架,觉得微信的tinker集成相对比较简单,就拿来试一试。
现在拿我用的AndroidStudio和项目环境进行集成还是遇到了不少坑。再次做一下 记录:
-
先来说一下我用的AnroidStudio环境:
我用的AndroidStudio3.0的稳定版,gradle的版本:
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
gradle工具版本
classpath 'com.android.tools.build:gradle:3.0.1'
编译环境版本
android = [ compileSdkVersion: 26, buildToolsVersion: '26.0.2', minSdkVersion : 19, targetSdkVersion : 26, javaVersion : JavaVersion.VERSION_1_8, versionCode : 7, versionName : '3.1.0', ]
- 集成步骤:
-
app的gradle中添加tinker的依赖:
dependencies {
// 若使用annotation需要单独引用,对于tinker的其他库都无需再引用
provided("com.tinkerpatch.tinker:tinker-android-anno:1.8.0")
compile("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.1.8")
}
apply from: 'tinkerpatch.gradle'
- 在项目的gradle中添加
dependencies {
// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.1.8"
}
- 在app的更目录下面添加tinkerpatch.gradle文件:
apply plugin: 'tinkerpatch-support'
apply from: 'tinkerpatch.gradle'
/**
* TODO: 请按自己的需求修改为适应自己工程的参数
*/
//基包路径
def bakPath = file("${buildDir}/bakApk/")
//基包文件夹名(打补丁包的时候,需要修改)
def baseInfo = ""
//版本名称
def variantName = "debug" //"release"
/**
* 对于插件各参数的详细解析请参考
*
*/
tinkerpatchSupport {
//可以在debug的时候关闭 tinkerPatch
tinkerEnable = true
//是否使用一键接入功能 默认为false 是否反射 Application 实现一键接入;
// 一般来说,接入 Tinker 我们需要改造我们的 Application, 若这里为 true, 即我们无需对应用做任何改造即可接入。
reflectApplication = true
//将每次编译产生的 apk/mapping.txt/R.txt 归档存储的位置
autoBackupApkPath = "${bakPath}"
appKey = ""// 注意!!! 需要修改成你的appkey
/** 注意: 若发布新的全量包, appVersion一定要更新 **/
appVersion = "1.0.0"
def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
def name = "${project.name}-${variantName}"
/**
* 基准包的文件路径, 对应 tinker 插件中的 oldApk 参数;编译补丁包时,
* 必需指定基准版本的 apk,默认值为空,则表示不是进行补丁包的编译
*/
baseApkFile = "${pathPrefix}/${name}.apk"
/**
* 基准包的 Proguard mapping.txt 文件路径, 对应 tinker 插件 applyMapping 参数;在编译新的 apk 时候,
* 我们希望通过保持基准 apk 的 proguard 混淆方式,
* 从而减少补丁包的大小。这是强烈推荐的,编译补丁包时,我们推荐输入基准 apk 生成的 mapping.txt 文件。
*/
baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
/**
* 基准包的资源 R.txt 文件路径, 对应 tinker 插件 applyResourceMapping 参数;在编译新的apk时候,
* 我们希望通基准 apk 的 R.txt 文件来保持 Resource Id 的分配,这样不仅可以减少补丁包的大小,
* 同时也避免由于 Resource Id 改变导致 remote view 异常
*/
baseResourceRFile = "${pathPrefix}/${name}-R.txt"
/**
* 若有编译多flavors需求, 可以参照: https://github.com/TinkerPatch/tinkerpatch-flavors-sample
* 注意: 除非你不同的flavor代码是不一样的,不然建议采用zip comment或者文件方式生成渠道信息(相关工具:walle 或者 packer-ng)
**/
}
/**
* 用于用户在代码中判断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 = false
useSign = true //是否需要签名,打正式包如果这里是true,则要配置签名,否则会编译不过去
dex {
dexMode = "jar"
pattern = ["classes*.dex"]
loader = []
}
lib {
pattern = ["lib/*/*.so"]
}
res {
pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
ignoreChange = []
largeModSize = 100
}
packageConfig {
}
sevenZip {
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
// path = "/usr/local/bin/7za"
}
buildConfig {
keepDexApply = false
}
}
- 项目的Application 中添加:
public class XscdApplication extends MultiDexApplication {
private ApplicationLike tinkerApplicationLike;
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.TINKER_ENABLE) {
// 我们可以从这里获得Tinker加载过程的信息
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
// 初始化TinkerPatch SDK, 更多配置可参照API章节中的,初始化SDK
TinkerPatch.init(tinkerApplicationLike)
.reflectPatchLibrary()
.setPatchRollbackOnScreenOff(true)
.setPatchRestartOnSrceenOff(true);
// 每隔3个小时去访问后台时候有更新,通过handler实现轮训的效果
new FetchPatchHandler().fetchPatchWithInterval(3);
}
}
}
- 添加类FetchHandler:
public class FetchPatchHandler extends Handler {
public static final long HOUR_INTERVAL = 3600 * 1000;
private long checkInterval;
/**
* 通过handler, 达到按照时间间隔轮训的效果
*/
public void fetchPatchWithInterval(int hour) {
//设置TinkerPatch的时间间隔
TinkerPatch.with().setFetchPatchIntervalByHours(hour);
checkInterval = hour * HOUR_INTERVAL;
//立刻尝试去访问,检查是否有更新
sendEmptyMessage(0);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//这里使用false即可
TinkerPatch.with().fetchPatchUpdate(false);
//每隔一段时间都去访问后台, 增加10分钟的buffer时间
sendEmptyMessageDelayed(0, checkInterval + 10 * 60 * 1000);
}
}
- 微信的TInker需要集成的东西就已经集成完了,然后编译一下项目,会发现出现错误,首先遇到的错误:
Error:Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- tinker-android-anno-1.8.0.jar (com.tinkerpatch.tinker:tinker-android-anno:1.8.0)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
原因:大概原因就是我使用le Gradle3.0的工具吧,新的 gradle 不再支持 annotation processors。解决办法:
如果需要使用需要显式声明,在app的gradle中添加
defaultConfig {
javaCompileOptions {
// 显式声明支持注解
annotationProcessorOptions {
includeCompileClasspath true
}
}
}扫描二维码关注公众号,回复: 5709339 查看本文章
要么使用低版本的gradle
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
这里我先用第一种方法试一下,编译由报错:
Error:Could not get unknown property 'apkVariantData' for object of type com.android.build.gradle.internal.api.ApplicationVariantImpl.
原因是:gradle升级到3.0以后去除了apkVariantData这个api,所以我们还是要使用低版本的gradle了,于是修改gradle的版本
在项目的gradle文件中修改gradle版本为2.3.2,这时编译之后可能出现gradle3.0时添加依赖是使用的implementation关键自不能用了,改成compile就好啦:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
}
接着编译,发现又报错了:
Error:Jack is required to support java 8 language features. Either enable Jack or remove sourceCompatibility JavaVersion.VERSION_1_8.
意思就是要使用java8的特性,需要配置一下jack,Jack 是 Java Android Compiler Kit 的缩写 ,算是Android自己的java编译器,需要在app的gradle文件中,配置:
defaultConfig {
jackOptions {
enabled true
}
}
编译,又出现错误:
Error:Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.tree.JCTree$VisitorError: at java.lang.Class.getDeclaredConstructors0(Native Method)
Error: at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
Error: at java.lang.Class.getConstructor0(Class.java:3075)
Error: at java.lang.Class.newInstance(Class.java:412)
Error: at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
Error: ... 16 more
这个错误出现的原因,我也没有查出来是为什么,可能还是java8配置的Jack出的问题,所以我还是把gradle里面配置java8的地方给去掉了,以前用的很多lanmuda表达式也要改回来了。