官方文檔:Bugly Android熱更新使用指南, 補(bǔ)丁打包配置詳解
官方Demo: Bugly-Android-Demo
應(yīng)用配置
1.添加插件依賴
buildscript {
repositories {
jcenter()
}
dependencies {
// tinkersupport插件, 其中l(wèi)astest.release指拉取最新版本秩冈,也可以指定明確版本號蕴潦,例如1.0.4
classpath "com.tencent.bugly:tinker-support:1.1.2"
}
}
2.app module 添加SDK
// 依賴插件腳本
apply from: 'tinker-support.gradle'
android {
defaultConfig {
...
// 開啟multidex
multiDexEnabled true
/*ndk {
//設(shè)置支持的SO庫架構(gòu)
abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}*/
}
// 簽名配置
signingConfigs {
release {
try {
storeFile file("G:/workspace/key/huiming.jks")
storePassword "test123"
keyAlias "huiming"
keyPassword "test123"
} catch (ex) {
throw new InvalidUserDataException(ex.toString())
}
}
debug {
//storeFile file("G:/workspace/key/huiming.jks")
}
}
buildTypes {
release {
minifyEnabled true
signingConfig signingConfigs.release
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
minifyEnabled false
// signingConfig signingConfigs.debug
}
}
}
dependencies {
compile "com.android.support:multidex:1.0.1" // 多dex配置
//注釋掉原有bugly的倉庫
//compile 'com.tencent.bugly:crashreport:latest.release'//其中l(wèi)atest.release指代最新版本號布蔗,也可以指定明確的版本號瘦锹,例如1.3.4
compile 'com.tencent.bugly:crashreport_upgrade:1.3.5'
// 指定tinker依賴版本(注:應(yīng)用升級1.3.5版本起放棒,不再內(nèi)置tinker)
compile 'com.tencent.tinker:tinker-android-lib:1.9.6'
//按需要添加,如有需要native支持
//compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中l(wèi)atest.release指代最新版本號,也可以指定明確的版本號,例如2.2.0
}
3. app gradle同級目錄下新建 tinker-support.gradle
文件
apply plugin: 'com.tencent.bugly.tinker-support'
def bakPath = file("${buildDir}/bakApk/")
/**
* 此處填寫每次構(gòu)建生成的基準(zhǔn)包目錄
*/
def baseApkDir = "app-0726-11-48-25"
/**
* 對于插件各參數(shù)的詳細(xì)解析請參考
*/
tinkerSupport {
// 開啟tinker-support插件邓线,默認(rèn)值true
enable = true
// 自動生成tinkerId, 你無須關(guān)注tinkerId,默認(rèn)為false
autoGenerateTinkerId = true
// 指定歸檔目錄煌恢,默認(rèn)值當(dāng)前module的子目錄tinker
autoBackupApkDir = "${bakPath}"
// 是否啟用覆蓋tinkerPatch配置功能骇陈,默認(rèn)值false
// 開啟后tinkerPatch配置不生效,即無需添加tinkerPatch
overrideTinkerPatchConfiguration = true
// 編譯補(bǔ)丁包時瑰抵,必需指定基線版本的apk你雌,默認(rèn)值為空
// 如果為空,則表示不是進(jìn)行補(bǔ)丁包的編譯
// @{link tinkerPatch.oldApk }
baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
// baseApk = "${bakPath}/${baseApkDir}/app-debug.apk"
// 對應(yīng)tinker插件applyMapping
baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
// baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-debug-mapping.txt"
// 對應(yīng)tinker插件applyResourceMapping
baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
// baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-debug-R.txt"
// 構(gòu)建基準(zhǔn)包跟補(bǔ)丁包都要修改tinkerId二汛,主要用于區(qū)分
// tinkerId = "1.0.3-ccc"
// 打多渠道補(bǔ)丁時指定目錄
// buildAllFlavorsDir = "${bakPath}/${baseApkDir}"
// 是否使用加固模式婿崭,默認(rèn)為false
// isProtectedApp = true
// 是否采用反射Application的方式集成,無須改造Application
enableProxyApplication = true
// 支持新增Activity
supportHotplugComponent = true
}
/**
* 一般來說,我們無需對下面的參數(shù)做任何的修改
* 對于各參數(shù)的詳細(xì)介紹請參考:
* https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
*/
tinkerPatch {
tinkerEnable = true
ignoreWarning = false
useSign = false
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 = "base-2.0.1"
}
}
4.初始化SDK
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
initUpdate()
}
fun initUpdate() {
setStrictMode()
// 設(shè)置是否開啟熱更新能力肴颊,默認(rèn)為true
Beta.enableHotfix = true
// 設(shè)置是否自動下載補(bǔ)丁
Beta.canAutoDownloadPatch = true
// 設(shè)置是否提示用戶重啟
Beta.canNotifyUserRestart = true
// 設(shè)置是否自動合成補(bǔ)丁
Beta.canAutoPatch = true
/**
* 全量升級狀態(tài)回調(diào)
*/
Beta.upgradeStateListener = object : UpgradeStateListener {
override fun onUpgradeFailed(b: Boolean) {
}
override fun onUpgradeSuccess(b: Boolean) {
}
override fun onUpgradeNoVersion(b: Boolean) {
Toast.makeText(applicationContext, "最新版本", Toast.LENGTH_SHORT).show()
}
override fun onUpgrading(b: Boolean) {
Toast.makeText(applicationContext, "onUpgrading", Toast.LENGTH_SHORT).show()
}
override fun onDownloadCompleted(b: Boolean) {
}
}
/**
* 補(bǔ)丁回調(diào)接口氓栈,可以監(jiān)聽補(bǔ)丁接收、下載苫昌、合成的回調(diào)
*/
Beta.betaPatchListener = object : BetaPatchListener {
override fun onPatchReceived(patchFileUrl: String) {
Toast.makeText(applicationContext, patchFileUrl, Toast.LENGTH_SHORT).show()
}
override fun onDownloadReceived(savedLength: Long, totalLength: Long) {
Toast.makeText(applicationContext, String.format(Locale.getDefault(),
"%s %d%%",
Beta.strNotificationDownloading,
(if (totalLength == 0L) 0 else savedLength * 100 / totalLength).toInt()), Toast.LENGTH_SHORT).show()
}
override fun onDownloadSuccess(patchFilePath: String) {
Toast.makeText(applicationContext, patchFilePath, Toast.LENGTH_SHORT).show()
// Beta.applyDownloadedPatch();
}
override fun onDownloadFailure(msg: String) {
Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
}
override fun onApplySuccess(msg: String) {
Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
}
override fun onApplyFailure(msg: String) {
Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
}
override fun onPatchRollback() {
Toast.makeText(applicationContext, "onPatchRollback", Toast.LENGTH_SHORT).show()
}
}
val start = System.currentTimeMillis()
Bugly.setUserId(this, "falue")
Bugly.setUserTag(this, 123456)
Bugly.putUserData(this, "key1", "123")
Bugly.setAppChannel(this, "bugly")
// 這里實現(xiàn)SDK初始化颤绕,appId替換成你的在Bugly平臺申請的appId,調(diào)試時將第三個參數(shù)設(shè)置為true
Bugly.init(this, "你的APPID", true)
val end = System.currentTimeMillis()
Log.e("init time--->", (end - start).toString() + "ms")
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
// you must install multiDex whatever tinker is installed!
MultiDex.install(base)
// 安裝tinker
Beta.installTinker()
}
@TargetApi(9)
protected fun setStrictMode() {
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().permitAll().build())
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build())
}
}
5.AndroidManifest.xml配置
-
權(quán)限配置
<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" />
補(bǔ)丁打包
1.編譯基準(zhǔn)包
注意:請確認(rèn)
tinker-support.gradle
文件中是否有配置 autoGenerateTinkerId = true 自動生成tinkerId如果沒有,請手動修改tinkerId
打開AS右邊的Gradle 執(zhí)行assembleRelease
編譯生成基準(zhǔn)包:
1532585447385
這個會在build/outputs/bakApk路徑下生成每次編譯的基準(zhǔn)包祟身、混淆配置文件奥务、資源Id文件,如下圖所示:
image
注意:app-release-mapping如果沒有生成袜硫,請檢查是否配置了簽名
請先安裝好并啟動一次基準(zhǔn)包apk
否則發(fā)布上傳補(bǔ)丁包時會出現(xiàn)未找到包的情況
2.生成升級補(bǔ)丁
-
修改
tinker-support.gradle
文件下基準(zhǔn)包目錄地址/** * 此處填寫每次構(gòu)建生成的基準(zhǔn)包目錄 */ def baseApkDir = "app-0726-11-48-25"
-
使用
buildTinkerPatchRelase
進(jìn)行編譯生成補(bǔ)丁包1532585447385
-
編譯完成后氯葬,將會在./build/outputs/patch/release目錄下生成補(bǔ)丁包
補(bǔ)丁包路徑.png
- 將補(bǔ)丁包上傳至bugly中下發(fā)補(bǔ)丁
問題記錄
1. 錯誤:Tinker.DefaultLoadReporter: patch loadReporter onLoadPatchListenerReceiveFail: patch receive fail: /data/user/0/xxxxxxxx/app_tmpPatch/tmpPatch.apk, code: -5
這個是因為這個手機(jī)在6.0的時候編譯選項打開了JIT,可能會對patch產(chǎn)生影響婉陷,會對這部分手機(jī)關(guān)閉patch功能
2.assembleRelease編譯時出現(xiàn)錯誤 BUILD FAILED
Warning: com.qihancloud.opensdk.function.unit.MediaManager: can't find referenced class org.jetbrains.annotations.NotNull
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
Warning: okhttp3.internal.platform.ConscryptPlatform: can't find referenced class org.conscrypt.Conscrypt
...
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
> Job failed, see logs for details
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 45s
解決方案:在proguard-rules.pro
中添加相對應(yīng)的混淆
-keep class com.qihancloud.opensdk.** {*;}
-dontwarn okio.**
-dontwarn retrofit2.Call
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
#忽略所有警告
-ignorewarnings