Android热更新Tinker接入项目详解:
1 项目根目录build.gradle文件添加:
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
// TinkerPatch 插件
classpath "com.tinkerpatch.sdk:tinkerpatch-gradle-plugin:1.2.14"
}
2 APP的build.gradle文件中添加:
dependencies {
annotationProcessor("com.tinkerpatch.tinker:tinker-android-anno:1.9.14")
implementation("com.tinkerpatch.sdk:tinkerpatch-android-sdk:1.2.14")
}
头部添加
apply from: 'tinkerpatch.gradle'
3 添加tinkerpatch.gradle文件
tinkerpatch.gradle文件内容如下:
apply plugin: 'tinkerpatch-support'
/**
* TODO: 请按自己的需求修改为适应自己工程的参数
*/
def bakPath = file("${buildDir}/bakApk/")
def baseInfo = "tinkerapp-1.0.0-1031-17-05-07"
def variantName = "release"
/**
* 对于插件各参数的详细解析请参考
* http://tinkerpatch.com/Docs/SDK
*/
tinkerpatchSupport {
/** 可以在debug的时候关闭 tinkerPatch **/
/** 当disable tinker的时候需要添加multiDexKeepProguard和proguardFiles,
这些配置文件本身由tinkerPatch的插件自动添加,当你disable后需要手动添加
你可以copy本示例中的proguardRules.pro和tinkerMultidexKeep.pro,
需要你手动修改'tinker.sample.android.app'本示例的包名为你自己的包名, com.xxx前缀的包名不用修改
**/
tinkerEnable = true
reflectApplication = true
/**
* 是否开启加固模式,只能在APK将要进行加固时使用,否则会patch失败。
* 如果只在某个渠道使用了加固,可使用多flavors配置
**/
protectedApp = false
/**
* 实验功能
* 补丁是否支持新增 Activity (新增Activity的exported属性必须为false)
**/
supportComponent = true
autoBackupApkPath = "${bakPath}"
appKey = "f589fed933b9ae15"
/** 注意: 若发布新的全量包, appVersion一定要更新 **/
appVersion = "1.0.0"
def pathPrefix = "${bakPath}/${baseInfo}/${variantName}/"
def name = "${project.name}-${variantName}"
baseApkFile = "${pathPrefix}/${name}.apk"
baseProguardMappingFile = "${pathPrefix}/${name}-mapping.txt"
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
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
}
}
需要注意 def baseInfo = “tinkerapp-1.0.0-1031-17-05-07”
tinkerEnable = true
reflectApplication = true 这三个参数的意义
参数的详解查看 http://tinkerpatch.com/Docs/SDK
4 将SampleApplication接入到项目中
SampleApplication 代码如下:
package com.test.tinkerapp;
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 Shengjie Sim Sun
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import android.app.Application;
import android.content.Context;
//import android.support.multidex.MultiDex;
import android.support.multidex.MultiDex;
import android.util.Log;
import com.tencent.tinker.entry.ApplicationLike;
import com.tencent.tinker.lib.listener.DefaultPatchListener;
import com.tencent.tinker.lib.patch.UpgradePatch;
import com.tencent.tinker.lib.reporter.DefaultLoadReporter;
import com.tencent.tinker.lib.reporter.DefaultPatchReporter;
import com.tencent.tinker.lib.service.PatchResult;
import com.tinkerpatch.sdk.TinkerPatch;
import com.tinkerpatch.sdk.loader.TinkerPatchApplicationLike;
import com.tinkerpatch.sdk.server.callback.ConfigRequestCallback;
import com.tinkerpatch.sdk.server.callback.RollbackCallBack;
import com.tinkerpatch.sdk.server.callback.TinkerPatchRequestCallback;
import com.tinkerpatch.sdk.tinker.callback.ResultCallBack;
import com.tinkerpatch.sdk.tinker.service.TinkerServerResultService;
import java.util.HashMap;
public class SampleApplication extends Application {
private static final String TAG = "Tinker.SampleApppatch";
private ApplicationLike tinkerApplicationLike;
public SampleApplication() {
}
@Override
public void attachBaseContext(Context base) {
super.attachBaseContext(base);
//you must install multiDex whatever tinker is installed!
MultiDex.install(base);
}
/**
* 由于在onCreate替换真正的Application,
* 我们建议在onCreate初始化TinkerPatch,而不是attachBaseContext
*/
@Override
public void onCreate() {
super.onCreate();
initTinkerPatch();
}
/**
* 我们需要确保至少对主进程跟patch进程初始化 TinkerPatch
*/
private void initTinkerPatch() {
// 我们可以从这里获得Tinker加载过程的信息
if (BuildConfig.TINKER_ENABLE) {
tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
// 初始化TinkerPatch SDK
TinkerPatch.init(
tinkerApplicationLike
// new TinkerPatch.Builder(tinkerApplicationLike)
// .requestLoader(new OkHttp3Loader())
// .build()
)
.reflectPatchLibrary()
.setPatchRollbackOnScreenOff(true)
.setPatchRestartOnSrceenOff(true)
.setFetchPatchIntervalByHours(3)
;
// 获取当前的补丁版本
Log.d(TAG, "Current patch version is " + TinkerPatch.with().getPatchVersion());
// fetchPatchUpdateAndPollWithInterval 与 fetchPatchUpdate(false)
// 不同的是,会通过handler的方式去轮询
TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
}
}
/**
* 在这里给出TinkerPatch的所有接口解释
* 更详细的解释请参考:http://tinkerpatch.com/Docs/api
*/
private void useSample() {
TinkerPatch.init(tinkerApplicationLike)
//是否自动反射Library路径,无须手动加载补丁中的So文件
//注意,调用在反射接口之后才能生效,你也可以使用Tinker的方式加载Library
.reflectPatchLibrary()
//向后台获取是否有补丁包更新,默认的访问间隔为3个小时
//若参数为true,即每次调用都会真正的访问后台配置
.fetchPatchUpdate(false)
//设置访问后台补丁包更新配置的时间间隔,默认为3个小时
.setFetchPatchIntervalByHours(3)
//向后台获得动态配置,默认的访问间隔为3个小时
//若参数为true,即每次调用都会真正的访问后台配置
.fetchDynamicConfig(new ConfigRequestCallback() {
@Override
public void onSuccess(HashMap<String, String> hashMap) {
}
@Override
public void onFail(Exception e) {
}
}, false)
//设置访问后台动态配置的时间间隔,默认为3个小时
.setFetchDynamicConfigIntervalByHours(3)
//设置当前渠道号,对于某些渠道我们可能会想屏蔽补丁功能
//设置渠道后,我们就可以使用后台的条件控制渠道更新
.setAppChannel("default")
//屏蔽部分渠道的补丁功能
.addIgnoreAppChannel("googleplay")
//设置tinkerpatch平台的条件下发参数
.setPatchCondition("test", "1")
//设置补丁合成成功后,锁屏重启程序
//默认是等应用自然重启
.setPatchRestartOnSrceenOff(true)
//我们可以通过ResultCallBack设置对合成后的回调
//例如弹框什么
//注意,setPatchResultCallback 的回调是运行在 intentService 的线程中
.setPatchResultCallback(new ResultCallBack() {
@Override
public void onPatchResult(PatchResult patchResult) {
Log.i(TAG, "onPatchResult callback here");
}
})
//设置收到后台回退要求时,锁屏清除补丁
//默认是等主进程重启时自动清除
.setPatchRollbackOnScreenOff(true)
//我们可以通过RollbackCallBack设置对回退时的回调
.setPatchRollBackCallback(new RollbackCallBack() {
@Override
public void onPatchRollback() {
Log.i(TAG, "onPatchRollback callback here");
}
});
}
/**
* 自定义Tinker类的高级用法, 使用更灵活,但是需要对tinker有更进一步的了解
* 更详细的解释请参考:http://tinkerpatch.com/Docs/api
*/
private void complexSample() {
//修改tinker的构造函数,自定义类
TinkerPatch.Builder builder = new TinkerPatch.Builder(tinkerApplicationLike)
.listener(new DefaultPatchListener(this))
.loadReporter(new DefaultLoadReporter(this))
.patchReporter(new DefaultPatchReporter(this))
.resultServiceClass(TinkerServerResultService.class)
.upgradePatch(new UpgradePatch())
.patchRequestCallback(new TinkerPatchRequestCallback());
//.requestLoader(new OkHttpLoader());
TinkerPatch.init(builder.build());
}
}
5 在Tinker Platform 平台注册账号
直接都是下一步,最后拿到appKey,填入到tinkerpatch.gradle文件中的
appKey = “e9c7e10e43fe406f”
点击添加app版本,App版本号是项目中的 versionName “1.0.0”,如果这里填写的是versionName的值那么tinkerpatch.gradle文件中的 appVersion = “1.0.0”,这俩者是对应的;切记
6 生成Signing Configs(如果项目中已经有,可以忽略)
File>Project Structure
生成自己的Key store
Build>Generate Signed Bundle / APK…
以上准备工作已经完成
===============================================================
以下步骤是怎么生成补丁包
1 生成自己的release包
举个例子:
MainActivity中有bug的内容(线上的包)
双击assembleRelease生成release包
同时在bakApk目录下会生成一个release包
修改bug:
当bug修改过后,在tinkerpatch.gradle文件的def baseInfo = “tinkerapp-1.0.0-1031-17-06-33”,把baseInfo 的值改为上一次的地址
双击tinkerPatchRelease生成补丁包:
当前的文件就是生成的补丁包
将生成的补丁包发到Tinker Platform平台上,点击提交就可以了
在模拟器中点击按钮,就可以强制更新平台上的包了,但是要想看到修改后的内容,必须把app kill掉,重新进去就可以看到了。
完毕