android tinker 加固,Android接入Tinker(Bugly)热更新步骤及一些避免坑的方式

Android接入Tinker(Bugly)热更新步骤及一些避免坑的方式

腾讯的Tinker是一个应用比较广的开源三方热修复框架,现将接入过程及接入遇到的问题记录如下。

官网

GitHub:tinker的demo

Bugly: 官方文档-接入步骤

PS:文档不是最新的接入代码,最新的代码可以参考Github上的Demo

接入环境

Windows10;

Android Studio 3.6.2;

compileSdkVersion: 29;

buildToolsVersion: "29.0.3";

minSdkVersion : 21;

步骤

head:官方配置

1.app的build.gradle导入配置

apply from: 'tinker-support.gradle'

android {

defaultConfig {

ndk {

//选择要添加的对应cpu类型的.so库。

abiFilters 'armeabi', 'armeabi-v7a', 'x86', "mips"

}

}

}

dependencies {

implementation 'com.tencent.bugly:crashreport_upgrade:latest.release'

implementation 'com.tencent.tinker:tinker-android-lib:latest.release'

implementation 'com.tencent.bugly:nativecrashreport:latest.release'

}

2.项目的build.gradle导入

buildscript {

dependencies {

classpath 'com.android.tools.build:gradle:3.3.2'

//tinker

classpath "com.tencent.bugly:tinker-support:latest.release"

}

}

3.在app的build.gradle同级下新建tinker-support.gradle文件

apply plugin: 'com.tencent.bugly.tinker-support'

def bakPath = file("${buildDir}/bakApk/")

/**

* 此处填写每次构建生成的基准包目录

*/

def baseApkDir = "app-0122-11-36-28"

/**

* 对于插件各参数的详细解析请参考

*/

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

// 是否启用覆盖tinkerPatch配置功能,默认值false

// 开启后tinkerPatch配置不生效,即无需添加tinkerPatch

overrideTinkerPatchConfiguration = true

// 编译补丁包时,必需指定基线版本的apk,默认值为空

// 如果为空,则表示不是进行补丁包的编译

// @{link tinkerPatch.oldApk }

// v1.4_fachan_yingyongbao_release_080901

baseApk = "${bakPath}/${baseApkDir}/${APP_NAME}_${APP_VERSION}_${VERSION_CODE}.apk"

// baseApk = "${bakPath}/${baseApkDir}/app-debug.apk"

// 对应tinker插件applyMapping

baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-${BUILD_TYPE}-mapping.txt"

// 对应tinker插件applyResourceMapping

baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-${BUILD_TYPE}-R.txt"

// 构建基准包和补丁包都要指定不同的tinkerId,并且必须保证唯一性

// tinkerId = "base-1.0.3"//autoGenerateTinkerId = true无效

// 构建多渠道补丁时使用

// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"

// 是否启用加固模式,默认为false.(tinker-spport 1.0.7起支持)

// isProtectedApp = true

// 是否开启反射Application模式

enableProxyApplication = false

// 是否支持新增非export的Activity(注意:设置为true才能修改AndroidManifest文件)

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

allowLoaderInAnyDex = true

removeLoaderForAllDex = 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 = 100

}

packageConfig {

}

sevenZip {

zipArtifact = "com.tencent.mm:SevenZip:1.1.10"

// path = "/usr/local/bin/7za"

}

buildConfig {

keepDexApply = false

//tinkerId = "1.0.1-base"

//applyMapping = "${bakPath}/${appName}/app-release-mapping.txt" // 可选,设置mapping文件,建议保持旧apk的proguard混淆方式

// applyResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt" // 可选,设置R.txt文件,通过旧apk文件保持ResId的分配

}

}

PS:1>.baseApkDir的位置是:../app/build/baseApk(bakPath);

2>baseApk的命名规则和自己../app/build.gradle文件里面的命名规则一致,命名可以自定义,方便找到对应的base包;

...

android {

applicationVariants.all { variant ->

variant.outputs.all {

outputFileName = "${APP_NAME}_collaborative_${APP_VERSION}_${VERSION_CODE}.apk"

}

}

}

...

3>错误:com.tencent.tinker.build.util.TinkerPatchException: loader classes are found in old secondary dex.

原因:minSdk>=21的时候,编译器打包生成的dex文件分配会不同。

修改:加入以下设置可行

allowLoaderInAnyDex = true

removeLoaderForAllDex = true

5.以上配置还有来自于gradle.properties文件配置

BUILD_TYPE=Debug

APP_VERSION=1.0.0

android.useAndroidX=true

android.enableJetifier=true

...

6.因为没有开启application反射模式(enableProxyApplication = false),所以还需要修改application:

import com.tencent.tinker.loader.app.TinkerApplication;

import com.tencent.tinker.loader.shareutil.ShareConstants;

public class MyApp extends TinkerApplication {

//tinker

public MyApp(){

super(ShareConstants.TINKER_ENABLE_ALL, "com.xx.xxx.SampleApplicationLike",

"com.tencent.tinker.loader.TinkerLoader", false,true);

}

}

...

android:name=".MyApp"

...

>

android:name=".MyFileProvider"

android:authorities="${applicationId}.fileProvider"

android:exported="false"

android:grantUriPermissions="true"

tools:replace="name,authorities,exported,grantUriPermissions">

android:name="android.support.FILE_PROVIDER_PATHS"

android:resource="@xml/provider_paths"

tools:replace="name,resource" />

...

public class MyFileProvider extends BuglyFileProvider {

}

name="cache"

path="/temp"/>

name="exCache"

path="/temp"/>

name="sdcardCache"

path="/mnt/sdcard/com.swartz.cicada/temp"/>

name="scanner"

path=""/>

name="beta_external_path"

path="temp/"/>

name="beta_external_files_path"

path="temp/"/>

import android.annotation.TargetApi;

import android.app.Application;

import android.content.Context;

import android.content.Intent;

import android.os.Build;

import android.os.Process;

import android.webkit.WebView;

import android.widget.Toast;

import androidx.multidex.MultiDex;

import com.alibaba.sdk.android.push.common.util.AppInfoUtil;

import com.growingio.android.sdk.collection.Configuration;

import com.growingio.android.sdk.collection.GrowingIO;

import com.squareup.leakcanary.LeakCanary;

import com.squareup.leakcanary.RefWatcher;

import com.tencent.bugly.Bugly;

import com.tencent.bugly.beta.Beta;

import com.tencent.bugly.beta.interfaces.BetaPatchListener;

import com.tencent.bugly.crashreport.CrashReport;

import com.tencent.bugly.proguard.P;

import com.tencent.smtt.sdk.QbSdk;

import com.tencent.tinker.entry.DefaultApplicationLike;

import java.util.Locale;

import io.reactivex.plugins.RxJavaPlugins;

import static android.os.Build.VERSION_CODES.P;

/**

* Tinker

*/

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();

initBugly();

}

private void initBugly() {

Beta.betaPatchListener = new BetaPatchListener() {// 补丁回调接口

@Override

public void onPatchReceived(String patchFile) {

LogUtils.i(TAG, "补丁下载地址" + patchFile);

}

@Override

public void onDownloadReceived(long savedLength, long totalLength) {

LogUtils.i(TAG, String.format(Locale.getDefault(), "%s %d%%",

Beta.strNotificationDownloading,

(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)));

}

@Override

public void onDownloadSuccess(String msg) {

LogUtils.i(TAG, "补丁下载成功" + msg);

}

@Override

public void onDownloadFailure(String msg) {

LogUtils.i(TAG, "补丁下载失败" + msg);

}

@Override

public void onApplySuccess(String msg) {

LogUtils.i(TAG, "补丁应用成功" + msg);

}

@Override

public void onApplyFailure(String msg) {

LogUtils.i(TAG, "补丁应用失败" + msg);

}

@Override

public void onPatchRollback() {}

};

CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(getApplication());

strategy.setUploadProcess(true);

// CrashReport.initCrashReport(getApplicationContext(), BuildConfig.BUGLY_APP_ID, BuildConfig.DEBUG, strategy);

Bugly.init(getApplication(), BuildConfig.BUGLY_APP_ID, BuildConfig.DEBUG, strategy);

Bugly.setIsDevelopmentDevice(getApplication(), BuildConfig.DEBUG);//是否为开发设备

}

@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);

// 安装tinker

// TinkerManager.installTinker(this); 替换成下面Bugly提供的方法

Beta.installTinker(this);

}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)

public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {

getApplication().registerActivityLifecycleCallbacks(callbacks);

}

}

7.混淆:

# 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.**{*;}

8.打基础包:

1aa836fa3733

image

PS:这里的打包策略(debug,preview,release)是../app/build.gradle里面配置的

...

android{

buildTypes {

release {

}

...

}

}

成功后将会在文件夹..\app\build\bakApk\app-xxxx-xx-xx-xx下生成基准包,如果报错,回到前几个步骤检查配置问题。

9.修改代码后打差分包:

将tinker-support.gradle的baseApkDir变量修改为第8步生成的文件夹app-xxxx-xx-xx-xx名称,运行对应的打包命令:

1aa836fa3733

在这里插入图片描述

1aa836fa3733

在这里插入图片描述

差分包成功打包后,会在..app/build/outputs/patch/debug目录下生成对应的差分包patch_signed_7zip.apk;

1aa836fa3733

在这里插入图片描述

10.上传:

官网:bugly热更新

1aa836fa3733

在这里插入图片描述

选择第9步生成的patch_signed_7zip.apk上传,如果基准包已联网自动上传过tinkid了,不会报错,否则不能上传成功。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值