直接接入Tinker的话,需要配置的东西太多了,所以我使用了腾讯自己也在使用的Bugly来接入Tinker热更新方案。
// tinkersupport插件(1.0.3以上无须再配置tinker插件)
classpath "com.tencent.bugly:tinker-support:1.1.5"
注意:自tinkersupport 1.0.3版本起无需再配tinker插件的classpath。
版本对应关系:
tinker-support 1.1.3 对应 tinker 1.9.8
tinker-support 1.1.2 对应 tinker 1.9.6
tinker-support 1.1.1 对应 tinker 1.9.1
tinker-support 1.0.9 对应 tinker 1.9.0
tinker-support 1.0.8 对应 tinker 1.7.11
tinker-support 1.0.7 对应 tinker 1.7.9
tinker-support 1.0.4 对应 tinker 1.7.7
tinker-support 1.0.3 对应 tinker 1.7.6
tinker-support 1.0.2 对应 tinker 1.7.5(需配置tinker插件的classpath)
android {
compileSdkVersion 28
// 编译选项
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// recommend
dexOptions {
jumboMode = true
}
// 签名配置
signingConfigs {
release {
try {
storeFile file("./keystore/release.keystore")
storePassword "testres"
keyAlias "testres"
keyPassword "testres"
} catch (ex) {
throw new InvalidUserDataException(ex.toString())
}
}
debug {
storeFile file("./keystore/debug.keystore")
}
}
defaultConfig {
applicationId "com.yqw.testhotup"
minSdkVersion 21
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// 开启multidex
multiDexEnabled true
}
// 构建类型
buildTypes {
release {
minifyEnabled false
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
signingConfig signingConfigs.debug
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
repositories {
flatDir {
dirs 'libs'
}
}
// 多渠道配置
/*flavorDimensions "tier"
productFlavors {
xiaomi {
dimension "tier"
}
yyb {
dimension "tier"
}
wdj {
dimension "tier"
}
}*/
lintOptions {
checkReleaseBuilds false
abortOnError false
}
}
dependencies {
// 多dex配置
implementation "com.android.support:multidex:1.0.1"
// 集成Bugly热更新aar(本地集成使用方式)
//compile(name: 'bugly_crashreport_upgrade-1.3.2', ext: 'aar')
// 远程仓库集成方式(推荐)
//compile 'com.tencent.bugly:crashreport_upgrade:1.3.8'
implementation 'com.tencent.bugly:crashreport_upgrade:latest.release'
//1. 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
//2.为了便于解答问题,这里的tinker版本建议跟随此处demo设置,如果微信更新了tinker版本,bugly会定期同步更新
implementation 'com.tencent.tinker:tinker-android-lib:1.9.9'
}
// 依赖插件脚本
apply from: 'tinker-support.gradle'
然后在 app/build.gradle 同级目录下创建 tinker-support.gradle 文件(内容可以直接拷贝):
apply plugin: 'com.tencent.bugly.tinker-support'
def bakPath = file("${buildDir}/bakApk/")
/**
* 此处填写每次构建生成的基准包目录
*/
def baseApkDir = "app-0430-00-01-31"
/**
* 对于插件各参数的详细解析请参考,如果没有特殊需求下面的参数都可以不用更改;如果apk需要加固等可以参考具体描述设置参数
*/
tinkerSupport {
// 开启tinker-support插件,默认值true
enable = true
// 指定归档目录,默认值当前module的子目录tinker
autoBackupApkDir = "${bakPath}"
//建议设置true,用户就不用再自己管理tinkerId的命名,插件会为每一次构建的base包自动生成唯一的tinkerId,默认命名规则是versionname.versioncode_时间戳
//具体参考https://github.com/BuglyDevTeam/Bugly-Android-Demo/wiki/Tinker-ID%E8%AF%A5%E6%80%8E%E4%B9%88%E8%AE%BE%E7%BD%AE
autoGenerateTinkerId = true
//tinkerId必须保证唯一性,如果两个base包的tinkerid是一样的,并且都联网激活了,那么后续补丁上传到后台的时候会出现匹配错误
tinkerId = "if autoGenerateTinkerId=true ,no need set here"
// 是否启用覆盖tinkerPatch配置功能,默认值false
// 开启后tinkerPatch配置不生效,即无需添加tinkerPatch
overrideTinkerPatchConfiguration = true
// 编译补丁包时,必需指定基线版本的apk,默认值为空
// 如果为空,则表示不是进行补丁包的编译
// @{link tinkerPatch.oldApk }
baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// 对应tinker插件applyMapping
baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// 对应tinker插件applyResourceMapping
baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"
// 是否开启加固模式,默认为false
// isProtectedApp = true
enableProxyApplication = false
supportHotplugComponent = true
}
/**
* 一般来说,我们无需对下面的参数做任何的修改
* 对于各参数的详细介绍请参考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
//oldApk ="${bakPath}/${appName}/app-release.apk"
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
//tinkerId = "1.0.1-patch"
//applyMapping = "${bakPath}/${appName}/app-release-mapping.txt" // 可选,设置mapping文件,建议保持旧apk的proguard混淆方式
//applyResourceMapping = "${bakPath}/${appName}/app-release-R.txt" // 可选,设置R.txt文件,通过旧apk文件保持ResId的分配
}
}
配置混淆(如果不混淆可以不用配置,但是记得设置 minifyEnabled false):
# Bugly混淆规则
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
# 避免影响升级功能,需要keep住support包的类
-keep class android.support.**{*;}
这是Tinker推荐的接入方式,一定程度上会增加接入成本,但具有更好的兼容性。
集成Bugly升级SDK之后,我们需要按照以下方式自定义ApplicationLike来实现Application的代码(以下是示例):
自定义Application
public class SampleApplication extends TinkerApplication {
public SampleApplication() {
super(ShareConstants.TINKER_ENABLE_ALL, "xxx.xxx.SampleApplicationLike",
"com.tencent.tinker.loader.TinkerLoader", false);
}
}
注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中
参数解析
参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKER_ENABLE_ALL
参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike
参数3:loaderClassName Tinker的加载器,使用默认即可
参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false
我们需要您将以前的Applicaton配置为继承TinkerApplication的类:
自定义ApplicationLike
package com.yqw.testhotup;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.multidex.MultiDex;
import android.widget.Toast;
import com.tencent.bugly.Bugly;
import com.tencent.bugly.beta.Beta;
import com.tencent.bugly.beta.interfaces.BetaPatchListener;
import com.tencent.tinker.entry.DefaultApplicationLike;
import java.util.Locale;
//import com.meituan.android.walle.WalleChannelReader;
/**
* 自定义ApplicationLike类.
*
* 注意:这个类是Application的代理类,以前所有在Application的实现必须要全部拷贝到这里
*
* @author wenjiewu
* @since 2016/11/7
*/
public class SampleApplicationLike extends DefaultApplicationLike {
public static final String TAG = "Tinker.SampleApplicationLike";
public SampleApplicationLike(Application application, int tinkerFlags,
boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,
long applicationStartMillisTime, Intent tinkerResultIntent) {
super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime,
applicationStartMillisTime, tinkerResultIntent);
}
@Override
public void onCreate() {
super.onCreate();
// 设置是否开启热更新能力,默认为true
Beta.enableHotfix = true;
// 设置是否自动下载补丁,默认为true
Beta.canAutoDownloadPatch = true;
// 设置是否自动合成补丁,默认为true
Beta.canAutoPatch = true;
// 设置是否提示用户重启,默认为false
Beta.canNotifyUserRestart = true;
// 补丁回调接口
Beta.betaPatchListener = new BetaPatchListener() {
@Override
public void onPatchReceived(String patchFile) {
Toast.makeText(getApplication(), "补丁下载地址" + patchFile, Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadReceived(long savedLength, long totalLength) {
Toast.makeText(getApplication(),
String.format(Locale.getDefault(), "%s %d%%",
Beta.strNotificationDownloading,
(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)),
Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadSuccess(String msg) {
Toast.makeText(getApplication(), "补丁下载成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onDownloadFailure(String msg) {
Toast.makeText(getApplication(), "补丁下载失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onApplySuccess(String msg) {
Toast.makeText(getApplication(), "补丁应用成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onApplyFailure(String msg) {
Toast.makeText(getApplication(), "补丁应用失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onPatchRollback() {
}
};
// 设置开发设备,默认为false,上传补丁如果下发范围指定为“开发设备”,需要调用此接口来标识开发设备
Bugly.setIsDevelopmentDevice(getApplication(), true);
// 多渠道需求塞入
// String channel = WalleChannelReader.getChannel(getApplication());
// Bugly.setAppChannel(getApplication(), channel);
// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId
Bugly.init(getApplication(), "ed56ad6829", true);
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onBaseContextAttached(Context base) {
super.onBaseContextAttached(base);
// you must install multiDex whatever tinker is installed!
MultiDex.install(base);
// TODO: 安装tinker
Beta.installTinker(this);
//其他你自己的application的初始化代码可以放在这下面
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void registerActivityLifecycleCallback(
Application.ActivityLifecycleCallbacks callbacks) {
getApplication().registerActivityLifecycleCallbacks(callbacks);
}
@Override
public void onTerminate() {
super.onTerminate();
Beta.unInit();
}
}
注意:tinker需要你开启MultiDex,你需要在dependencies中进行配置
compile "com.android.support:multidex:1.0.1"
才可以使用MultiDex.install方法; SampleApplicationLike这个类是Application的代理类,以前所有在Application的实现必须要全部拷贝到这里,在onCreate
方法调用SDK的初始化方法,在onBaseContextAttached
中调用Beta.installTinker(this);
。
在AndroidMainfest.xml中进行以下配置:
1. 权限配置
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. Activity配置
<activity
android:name="com.tencent.bugly.beta.ui.BetaActivity"
android:configChanges="keyboardHidden|orientation|screenSize|locale"
android:theme="@android:style/Theme.Translucent" />
3. 配置FileProvider
注意:如果您想兼容Android N或者以上的设备,必须要在AndroidManifest.xml文件中配置FileProvider来访问共享路径的文件。
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
provider>
如果你使用的第三方库也配置了同样的FileProvider, 可以通过继承FileProvider类来解决合并冲突的问题,示例如下:
".utils.BuglyFileProvider" android:authorities="${applicationId}.fileProvider" android:exported="false" android:grantUriPermissions="true" tools:replace="name,authorities,exported,grantUriPermissions">
name= name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" tools:replace="name,resource"/>
这里要注意一下,FileProvider类是在support-v4包中的,检查你的工程是否引入该类库。
在res目录新建xml文件夹,创建provider_paths.xml文件如下:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="beta_external_path" path="Download/"/>
<external-path name="beta_external_files_path" path="Android/data/"/>
paths>
这里配置的两个外部存储路径是升级SDK下载的文件可能存在的路径,一定要按照上面格式配置,不然可能会出现错误。
注:1.3.1及以上版本,可以不用进行以上配置,aar已经在AndroidManifest配置了,并且包含了对应的资源文件。
ok,到这里就结束配置了。我只是摘了自己配置的部分,结合了buglyDemo来修改了部分我觉得ok的内容。
Bugly官方配置链接
==============================华丽的分割线===============================================
点击后会生成一个已经签名打包的apk
这里第二个.txt没有生成成功的没有关系,只要apk生成就好了。
注意:这里你需要将这个apk给手机安装,然后打开应用,这时应用会自动上报联网,Bugly才会知道你已经有一个可用的版本了,不这样的话,会在上传补丁包的时候报错:未匹配到可应用补丁包的app版本。
修改代码;
TextView tv_testbug = findViewById(R.id.tv_testbug);
tv_testbug.setText("我是正常的嘿嘿");
然后复制上面生成线上版本apk的文件夹名
/**
* 此处填写每次构建生成的基准包目录
*/
def baseApkDir = "app-0504-01-23-33"
接着
然后将补丁发布就ok了发布补丁的后台
需要注意的是,这里的补丁包上传成功后,本地还需要重启一次应用,然后等待就可以了,这个时间可能要十分钟左右,才会提示下载补丁包,然后弹出重启提示框,点击重启就可以看到你修改的效果了!
转载请注明来源:https://blog.csdn.net/you943047219/article/details/89810041