1. 程式人生 > >Tinker熱修復(gradle接入--成功)

Tinker熱修復(gradle接入--成功)

官方的接入指南真的很坑,對於沒有用過AndFix的人來說,可以說是一頭霧水,我到現在也不知道命令列接入的.jar檔案是在哪下載的。這裡講解一下gradle接入,經測試.java檔案可以實現完美接入,命令列接入的BUG完美繞過。(application的設定,和patch包的引用參考筆記Tinker熱修復(命令列接入——未知BUG--.java檔案修改不成功) ) (一)修改專案的build.gradle,新增依賴(版本按官方最新) dependencies { classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.8.0') } (二)修改app下的
app/build.gradle
,新增庫依賴和外掛(對於...隱藏的內容在下面詳解 dependencies {//可選,用於生成application類 provided('com.tencent.tinker:tinker-android-anno:1.8.0') //tinker的核心庫 compile('com.tencent.tinker:tinker-android-lib:1.8.0') }......//apply tinker外掛apply plugin: 'com.tencent.tinker.patch' (三)安裝apk到手機--可以是直接studio安裝的debug版本,也可以是打包的release版本 這時候在build資料夾下的bakApk檔案找到對應生成的.apk檔案,同時修改gradle中的tinkerOldApkPath名稱與上面的檔名保持一致(不要點Sync Now
) (四)修改你要修改的部分,在Gradle指令碼中找到'app:/tinker/tinkerPatchDebug'這條命令然後執行 (如果上面手機安裝的是debug包就是這個,安裝的是簽名正式包就選對應的,很重要 對應的位置 (五)找到生成的差異apk,路徑在/build/outputs/tinkerPatch/,然後推送到手機sdcard中 adb push ./app/build/outputs/tinkerPatch/debug/patch_signed_7zip.apk /storage/sdcard0/ 首先添加簽名檔案路徑 signingConfigs { release { try { //把簽名檔案放在gradle的同級目錄下
storeFile file("release.keystore") storePassword "testres" keyAlias "testres" keyPassword "testres" } catch (ex) { throw new InvalidUserDataException(ex.toString()) } } } 然後設定打包 buildTypes { release { minifyEnabled true signingConfig signingConfigs.release proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { debuggable true minifyEnabled true signingConfig signingConfigs.release proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } 其他設定:詳細講解參考官方規則 //相當於命令列的時候在manifest設定的TinkerID。 def gitSha() { try { String gitRev = 'git rev-parse --short HEAD'.execute(null, project.rootDir).text.trim() if (gitRev == null) { throw new GradleException("can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'") } return "6235657" } catch (Exception e) { throw new GradleException("can't get git rev, you should add git to system path or just input test value, such as 'testTinkerId'") } } //這個就是你第一次打包的時候生成的old.apk的存放路徑 def bakPath = file("${buildDir}/bakApk/") /** * you can use assembleRelease to build you base apk * use tinkerPatchRelease -POLD_APK= -PAPPLY_MAPPING= -PAPPLY_RESOURCE= to build patch * add apk from the build/bakApk */ ext { //for some reason, you may want to ignore tinkerBuild, such as instant run debug build? //是否使用tinker的標記。如果是true的話,在生成一次patch apk以後每次除錯執行的就會是上次修改後的內容,不會對你後面的程式碼進行同步。所以在執行完tinkerPatchDebug以後,要把它設定為false,才能在除錯時同步上最新程式碼 tinkerEnabled = true //for normal build //old apk file to build patch apk //這個就是當外掛生成patch apk的時候尋找的old.apk的路徑,每次執行完old.apk的時候,要修改名字,以保持一致性 tinkerOldApkPath = "${bakPath}/app-debug-0908-17-48-5.apk" //proguard mapping file to build patch apk tinkerApplyMappingPath = "${bakPath}/app-debug-0908-17-48-53-mapping.txt" //resource R.txt to build patch apk, must input if there is resource changed tinkerApplyResourcePath = "${bakPath}/app-debug-0908-17-48-53-R.txt" //only use for build all flavor, if not, just ignore this field tinkerBuildFlavorDirectory = "${bakPath}/app-0908-17-48-53" } def getOldApkPath() { return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath } def getApplyMappingPath() { return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath } def getApplyResourceMappingPath() { return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath } def getTinkerIdValue() { return hasProperty("TINKER_ID") ? TINKER_ID : gitSha() } def buildWithTinker() { return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled } def getTinkerBuildFlavorDirectory() { return ext.tinkerBuildFlavorDirectory } if (buildWithTinker()) { //外掛引用 apply plugin: 'com.tencent.tinker.patch' tinkerPatch { /** * necessary,default 'null' * the old apk path, use to diff with the new apk to build * add apk from the build/bakApk */ oldApk = getOldApkPath() /** * optional,default 'false' * there are some cases we may get some warnings * if ignoreWarning is true, we would just assert the patch process * case 1: minSdkVersion is below 14, but you are using dexMode with raw. * it must be crash when load. * case 2: newly added Android Component in AndroidManifest.xml, * it must be crash when load. * case 3: loader classes in dex.loader{} are not keep in the main dex, * it must be let tinker not work. * case 4: loader classes in dex.loader{} changes, * loader classes is ues to load patch dex. it is useless to change them. * it won't crash, but these changes can't effect. you may ignore it * case 5: resources.arsc has changed, but we don't use applyResourceMapping to build */ //看要求而定 ignoreWarning = false /** * optional,default 'true' * whether sign the patch file * if not, you must do yourself. otherwise it can't check success during the patch loading * we will use the sign config with your build type */ useSign = true /** * optional,default 'true' * whether use tinker to build */ tinkerEnable = buildWithTinker() /** * Warning, applyMapping will affect the normal android build! */ buildConfig { /** * optional,default 'null' * if we use tinkerPatch to build the patch apk, you'd better to apply the old * apk mapping file if minifyEnabled is enable! * Warning: * you must be careful that it will affect the normal assemble build! */ applyMapping = getApplyMappingPath() /** * optional,default 'null' * It is nice to keep the resource id from R.txt file to reduce java changes */ applyResourceMapping = getApplyResourceMappingPath() /** * necessary,default 'null' * because we don't want to check the base apk with md5 in the runtime(it is slow) * tinkerId is use to identify the unique base apk when the patch is tried to apply. * we can use git rev, svn rev or simply versionCode. * we will gen the tinkerId in your manifest automatic */ tinkerId = getTinkerIdValue() /** * if keepDexApply is true, class in which dex refer to the old apk. * open this can reduce the dex diff file size. */ keepDexApply = false /** * optional, default 'false' * Whether tinker should treat the base apk as the one being protected by app * protection tools. * If this attribute is true, the generated patch package will contain a * dex including all changed classes instead of any dexdiff patch-info files. */ isProtectedApp = false } dex { /** * optional,default 'jar' * only can be 'raw' or 'jar'. for raw, we would keep its original format * for jar, we would repack dexes with zip format. * if you want to support below 14, you must use jar * or you want to save rom or check quicker, you can use raw mode also */ dexMode = "jar" /** * necessary,default '[]' * what dexes in apk are expected to deal with tinkerPatch * it support * or ? pattern. */ pattern = ["classes*.dex", "assets/secondary-dex-?.jar"] /** * necessary,default '[]' * Warning, it is very very important, loader classes can't change with patch. * thus, they will be removed from patch dexes. * you must put the following class into main dex. * Simply, you should add your own application {@code tinker.sample.android.SampleApplication} * own tinkerLoader, and the classes you use in them * */ loader = [ //use sample, let BaseBuildInfo unchangeable with tinker "tinker.sample.android.app.BaseBuildInfo" ] } lib { /** * optional,default '[]' * what library in apk are expected to deal with tinkerPatch * it support * or ? pattern. * for library in assets, we would just recover them in the patch directory * you can get them in TinkerLoadResult with Tinker */ pattern = ["lib/*/*.so"] } res { /** * optional,default '[]' * what resource in apk are expected to deal with tinkerPatch * it support * or ? pattern. * you must include all your resources in apk here, * otherwise, they won't repack in the new apk resources. */ pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"] /** * optional,default '[]' * the resource file exclude patterns, ignore add, delete or modify resource change * it support * or ? pattern. * Warning, we can only use for files no relative with resources.arsc */ ignoreChange = ["assets/sample_meta.txt"] /** * default 100kb * for modify resource, if it is larger than 'largeModSize' * we would like to use bsdiff algorithm to reduce patch file size */ largeModSize = 100 } packageConfig { /** * optional,default 'TINKER_ID, TINKER_ID_VALUE' 'NEW_TINKER_ID, NEW_TINKER_ID_VALUE' * package meta file gen. path is assets/package_meta.txt in patch file * you can use securityCheck.getPackageProperties() in your ownPackageCheck method * or TinkerLoadResult.getPackageConfigByName * we will get the TINKER_ID from the old apk manifest for you automatic, * other config files (such as patchMessage below)is not necessary */ configField("patchMessage", "tinker is sample to use") /** * just a sample case, you can use such as sdkVersion, brand, channel... * you can parse it in the SamplePatchListener. * Then you can use patch conditional! */ configField("platform", "all") /** * patch version via packageConfig */ configField("patchVersion", "1.0") } //or you can add config filed outside, or get meta value from old apk //project.tinkerPatch.packageConfig.configField("test1", project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test")) //project.tinkerPatch.packageConfig.configField("test2", "sample") /** * if you don't use zipArtifact or path, we just use 7za to try */ sevenZip { /** * optional,default '7za' * the 7zip artifact path, it will use the right 7za with your platform */ zipArtifact = "com.tencent.mm:SevenZip:1.1.10" /** * optional,default '7za' * you can specify the 7za path yourself, it will overwrite the zipArtifact value */ // path = "/usr/local/bin/7za" } } List<String> flavors = new ArrayList<>(); project.android.productFlavors.each {flavor -> flavors.add(flavor.name) } boolean hasFlavors = flavors.size() > 0 def date = new Date().format("MMdd-HH-mm-ss") /** * bak apk and mapping */ android.applicationVariants.all { variant -> /** * task type, you want to bak */ def taskName = variant.name tasks.all { if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) { it.doLast { copy { def fileNamePrefix = "${project.name}-${variant.baseName}" def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}" def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath from variant.outputs.outputFile into destPath rename { String fileName -> fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk") } from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt" into destPath rename { String fileName -> fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt") } from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt" into destPath rename { String fileName -> fileName.replace("R.txt", "${newFileNamePrefix}-R.txt") } } } } } } project.afterEvaluate { //sample use for build all flavor for one time if (hasFlavors) { task(tinkerPatchAllFlavorRelease) { group = 'tinker' def originOldPath = getTinkerBuildFlavorDirectory() for (String flavor : flavors) { def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release") dependsOn tinkerTask def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest") preAssembleTask.doFirst { String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15) project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk" project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt" project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt" } } } task(tinkerPatchAllFlavorDebug) { group = 'tinker' def originOldPath = getTinkerBuildFlavorDirectory() for (String flavor : flavors) { def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug") dependsOn tinkerTask def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest") preAssembleTask.doFirst { String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13) project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk" project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt" project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt" } } } } } }

相關推薦

Tinker修復gradle接入--成功

官方的接入指南真的很坑,對於沒有用過AndFix的人來說,可以說是一頭霧水,我到現在也不知道命令列接入的.jar檔案是在哪下載的。這裡講解一下gradle接入,經測試.java檔案可以實現完美接入,命令列接入的BUG完美繞過。(application的設定,和patch

android--------微信 Tinker 修復

什麼是熱修復熱修復補丁(hotfix),又稱為patch,指能夠修復軟體漏洞的一些程式碼,是一種快速、低成本修復產品軟體版本缺陷的方式。熱修復有多種,如:Tinker ,QZone,Andfix, In

最新微信Tinker 修復平臺接入教程超詳細

目錄 Tinker接入文件 1 Tinker簡介 1.1Tinker優點 1.2 Tinker缺點 1.Tinker不支援修改AndroidManifest.xml,Tinker不支援新增四大元件(1.9.0支援新增非export的A

Tinker修復接入詳解入坑並出坑篇

注:當然一開始要參考Tinker的詳細說明,連結如下: https://github.com/Tencent/tinker/wiki 下面就是我自己一步一步操作,並完成接入Tinker,而且入坑並出坑的過程。 一:android studio自己建立個工程 二:工程的b

騰訊Tinker 修復 Andriod studio 3.0 配置和整合Bugly整合

騰訊Tinker 熱修復 Andriod studio 3.0 Bugly整合和多渠道補丁管理髮布 本文說明 上一篇我說完了騰訊Tinker 熱修復之多渠道打包,這篇我們來初步瞭解下騰訊Tinker和Bugly結合來做熱修復多渠道補丁管理和整合。(其實在上週我已經整合測試完了dem

騰訊Tinker 修復 Andriod studio 3.0 配置和整合多渠道打包和補丁釋出

騰訊Tinker 熱修復 Andriod studio 3.0 多渠道打包和釋出補丁方式推薦 本文說明 在之前我已經分享了Tinker 熱修復的 Andriod studio3.0 初次配置和整合,時隔這麼久來寫一下我對Thinker多渠道打包的理解和記錄,希望對大家有幫助。這篇文

騰訊Tinker 修復 Andriod studio 3.0 配置和整合

本文說明 面試的時候經常問我有沒有用過熱修復?用誰的?能說下原理嗎?當時我回答得不好,畢竟以前的專案都沒有用,又不敢裝逼,mmp,但是基本流程還是知道的,所以我們來初探下Tinker 這個熱修復,如果我是Andriod studio 2.3的話,我還不怎麼想寫這個文章,畢竟太多了,沒有

一步一步教你實現阿里巴巴的Sophix修復

1.0 整合準備 gradle遠端倉庫依賴, 開啟專案找到app的build.gradle檔案,新增如下配置: 新增maven倉庫地址: repositories { maven { url "http://maven.ali

Tinker修復框架接入

Tinker熱修復框架接入 Android現在開發App基本都開始接入熱修復框架,為的就是能夠修復一些線上緊急Bug。熱門的熱修復框架以及對比,網上介紹的也很多,個人而言就用過騰訊的tinker以及阿里的sophix。 騰訊tinkerTinker簡介,根據官方文件接入tinke

Android Dex 分包+修復QQ空間技術方案

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException;

Android修復:以DexClassLoader類載入原理編寫demo實現類替換修復

上一篇文章簡易總結了熱修復實現的幾大原理,並詳細介紹了Android中的類載入機制及原始碼探索,Android的類載入機制涉及到ClassLoader、DexClassLoader 、PathClassLoader 、BaseDexClassLoader 、De

Nginx+keepalived雙機主主模式

實現 nginx keepalived Nginx+keepalived實現高可用負載均衡的主主模式由於網站的訪問需求不斷加大,負載越來越高。現需要在web前端放置nginx負載均衡,同時結合keepalived對前端nginx實現HA高可用。1、nginx進程基於Master+Slave(wor

cocos creator android studio 實現遊戲微信登入功能官方接入方式

一:cocos creator端js呼叫java程式碼實現微信登入功能:JS部分  廢話不多說直接上程式碼: wechatLogin : function(){ jsb.reflection.callStaticMethod("org/cocos2dx/javascri

select 三級聯動,載入選定親測成功

自己在專案中遇到的問題,預設載入三級聯動不成功。 在網上找了很多文章,都沒有滿足需求。 直接上程式碼,親測成功,寫得不好的,還請指教。 thinkphp 框架中使用  ,使用頁面  .tpl <tr> <th width="10%">地區

Spring boot實現部署親測有效

  1.pom引入tools <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifa

modelsim-win64-10.4-se 下載、安裝、破解一次成功

本教程包括軟體下載、破解檔案下載、安裝破解方法,助你一次成功。 軟體安裝好了卻不能用,想必大家都有過這樣的痛苦和無奈。這款軟體的破解花了我整整一個下午的時間,期間在網上找了各種方法嘗試均以失敗告終,差點讓我放棄破解而著手去換作業系統。網上的方法多存在著疏漏和差錯,所以這也是我寫次教程的初衷,希望能幫

資料預處理:獨編碼One-Hot Encoding和 LabelEncoder標籤編碼

一、問題由來 在很多機器學習任務中,特徵並不總是連續值,而有可能是分類值。 離散特徵的編碼分為兩種情況:   1、離散特徵的取值之間沒有大小的意義,比如color:[red,blue],那麼就使用one-hot編碼   2、離散特徵的取值有大小的意義,比如size:[

hadoop單機偽分佈安裝HBase-1.4.8詳細步驟親測成功

---------前提:安裝hadoop、yarn、jdk 1.下載解壓 1.1使用wget下載 1.2解壓到/usr/local目錄下 1.3.修改hbase資料夾許可權 chown -R hadoop:hadoop /usr/local/hbase-

python + mod_wsgi + apache 部署用flask框架的py程式----window環境親測成功

先說一下我花了多久,距離上一篇搭建好apache之後,花了我一天的時間搞定,現在回想起來其實也就5個部分,按我下列的幾個步驟來不出錯僅僅只需要15分鐘,這就是程式設計師的極易禿頂的原因,錯誤能把你磨到崩潰!!! 成功之後,我差點激動的要把電腦砸了!!!真特麼喜極而泣(誇張一

react 模組更新Hot Module Replacement

1  修改package.json中的設定 2   修改index.js  當模組更新的時候, 通知index.js 3  使用npm start  修改頁面的內容發現不會再重新整理頁面,只是替換了修改的部分 tip