[关闭]
@lovesosoi 2018-04-08T09:29:17.000000Z 字数 21234 阅读 960

Tinker接入妙果Android项目

1.在项目根build.gradle中新增tinker插件

2.修改app下的build.gradle

(1)新增红框内容

(2)将dependencies提至android标签上面,并添加tinker依赖库

注意:1、若项目中有butterknife依赖且版本号高于8.4.0,修改butterknife版本号为8.4.0。
2、tinker还需要分包库,此处baselib中已有依赖所以app中没有再次依赖。compile'com.android.support:multidex:1.0.2'

(3)在Android.defaultConfig中添加红框内容内

(4)和buildTypes同级新增红框内容

(5)新增以下主要代码内容,可直接复制粘贴
  1. def getOldApkPath() {
  2. return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath
  3. }
  4. def getApplyMappingPath() {
  5. return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath
  6. }
  7. def getApplyResourceMappingPath() {
  8. return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath
  9. }
  10. def buildWithTinker() {
  11. return hasProperty("TINKER_ENABLE") ? Boolean.parseBoolean(TINKER_ENABLE) : ext.tinkerEnabled
  12. }
  13. def getTinkerBuildFlavorDirectory() {
  14. return ext.tinkerBuildFlavorDirectory
  15. }
  16. if (buildWithTinker()) {
  17. apply plugin: 'com.tencent.tinker.patch'
  18. tinkerPatch {
  19. /**
  20. * necessary,default 'null'
  21. * the old apk path, use to diff with the new apk to build
  22. * add apk from the build/bakApk
  23. */
  24. oldApk = getOldApkPath()
  25. /**
  26. * optional,default 'false'
  27. * there are some cases we may get some warnings
  28. * if ignoreWarning is true, we would just assert the patch process
  29. * case 1: minSdkVersion is below 14, but you are using dexMode with raw.
  30. * it must be crash when load.
  31. * case 2: newly added Android Component in AndroidManifest.xml,
  32. * it must be crash when load.
  33. * case 3: loader classes in dex.loader{} are not keep in the main dex,
  34. * it must be let tinker not work.
  35. * case 4: loader classes in dex.loader{} changes,
  36. * loader classes is ues to load patch dex. it is useless to change them.
  37. * it won't crash, but these changes can't effect. you may ignore it
  38. * case 5: resources.arsc has changed, but we don't use applyResourceMapping to build
  39. */
  40. ignoreWarning = false
  41. /**
  42. * optional,default 'true'
  43. * whether sign the patch file
  44. * if not, you must do yourself. otherwise it can't check success during the patch loading
  45. * we will use the sign config with your build type
  46. */
  47. useSign = true
  48. /**
  49. * optional,default 'true'
  50. * whether use tinker to build
  51. */
  52. tinkerEnable = buildWithTinker()
  53. /**
  54. * Warning, applyMapping will affect the normal android build!
  55. */
  56. buildConfig {
  57. /**
  58. * optional,default 'null'
  59. * if we use tinkerPatch to build the patch apk, you'd better to apply the old
  60. * apk mapping file if minifyEnabled is enable!
  61. * Warning:
  62. * you must be careful that it will affect the normal assemble build!
  63. */
  64. applyMapping = getApplyMappingPath()
  65. /**
  66. * optional,default 'null'
  67. * It is nice to keep the resource id from R.txt file to reduce java changes
  68. */
  69. applyResourceMapping = getApplyResourceMappingPath()
  70. /**
  71. * necessary,default 'null'
  72. * because we don't want to check the base apk with md5 in the runtime(it is slow)
  73. * tinkerId is use to identify the unique base apk when the patch is tried to apply.
  74. * we can use git rev, svn rev or simply versionCode.
  75. * we will gen the tinkerId in your manifest automatic
  76. */
  77. tinkerId = getTinkerIdValue()
  78. /**
  79. * if keepDexApply is true, class in which dex refer to the old apk.
  80. * open this can reduce the dex diff file size.
  81. */
  82. keepDexApply = false
  83. /**
  84. * optional, default 'false'
  85. * Whether tinker should treat the base apk as the one being protected by app
  86. * protection tools.
  87. * If this attribute is true, the generated patch package will contain a
  88. * dex including all changed classes instead of any dexdiff patch-info files.
  89. */
  90. isProtectedApp = false
  91. /**
  92. * optional, default 'false'
  93. * Whether tinker should support component hotplug (add new component dynamically).
  94. * If this attribute is true, the component added in new apk will be available after
  95. * patch is successfully loaded. Otherwise an error would be announced when generating patch
  96. * on compile-time.
  97. *
  98. * <b>Notice that currently this feature is incubating and only support NON-EXPORTED Activity</b>
  99. */
  100. supportHotplugComponent = false
  101. }
  102. dex {
  103. /**
  104. * optional,default 'jar'
  105. * only can be 'raw' or 'jar'. for raw, we would keep its original format
  106. * for jar, we would repack dexes with zip format.
  107. * if you want to support below 14, you must use jar
  108. * or you want to save rom or check quicker, you can use raw mode also
  109. */
  110. dexMode = "jar"
  111. /**
  112. * necessary,default '[]'
  113. * what dexes in apk are expected to deal with tinkerPatch
  114. * it support * or ? pattern.
  115. */
  116. pattern = ["classes*.dex",
  117. "assets/secondary-dex-?.jar"]
  118. /**
  119. * necessary,default '[]'
  120. * Warning, it is very very important, loader classes can't change with patch.
  121. * thus, they will be removed from patch dexes.
  122. * you must put the following class into main dex.
  123. * Simply, you should add your own application {@code tinker.sample.android.SampleApplication}
  124. * own tinkerLoader, and the classes you use in them
  125. *
  126. */
  127. loader = [
  128. //use sample, let BaseBuildInfo unchangeable with tinker
  129. getTinkerAppliactionName()
  130. ]
  131. }
  132. lib {
  133. /**
  134. * optional,default '[]'
  135. * what library in apk are expected to deal with tinkerPatch
  136. * it support * or ? pattern.
  137. * for library in assets, we would just recover them in the patch directory
  138. * you can get them in TinkerLoadResult with Tinker
  139. */
  140. pattern = ["lib/*/*.so"]
  141. }
  142. res {
  143. /**
  144. * optional,default '[]'
  145. * what resource in apk are expected to deal with tinkerPatch
  146. * it support * or ? pattern.
  147. * you must include all your resources in apk here,
  148. * otherwise, they won't repack in the new apk resources.
  149. */
  150. pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
  151. /**
  152. * optional,default '[]'
  153. * the resource file exclude patterns, ignore add, delete or modify resource change
  154. * it support * or ? pattern.
  155. * Warning, we can only use for files no relative with resources.arsc
  156. */
  157. ignoreChange = ["assets/sample_meta.txt"]
  158. /**
  159. * default 100kb
  160. * for modify resource, if it is larger than 'largeModSize'
  161. * we would like to use bsdiff algorithm to reduce patch file size
  162. */
  163. largeModSize = 100
  164. }
  165. packageConfig {
  166. /**
  167. * optional,default 'TINKER_ID, TINKER_ID_VALUE' 'NEW_TINKER_ID, NEW_TINKER_ID_VALUE'
  168. * package meta file gen. path is assets/package_meta.txt in patch file
  169. * you can use securityCheck.getPackageProperties() in your ownPackageCheck method
  170. * or TinkerLoadResult.getPackageConfigByName
  171. * we will get the TINKER_ID from the old apk manifest for you automatic,
  172. * other config files (such as patchMessage below)is not necessary
  173. */
  174. configField("patchMessage", "tinker is sample to use")
  175. /**
  176. * just a sample case, you can use such as sdkVersion, brand, channel...
  177. * you can parse it in the SamplePatchListener.
  178. * Then you can use patch conditional!
  179. */
  180. configField("platform", "all")
  181. /**
  182. * patch version via packageConfig
  183. */
  184. configField("patchVersion", "1.0")
  185. }
  186. //or you can add config filed outside, or get meta value from old apk
  187. //project.tinkerPatch.packageConfig.configField("test1", project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test"))
  188. //project.tinkerPatch.packageConfig.configField("test2", "sample")
  189. /**
  190. * if you don't use zipArtifact or path, we just use 7za to try
  191. */
  192. sevenZip {
  193. /**
  194. * optional,default '7za'
  195. * the 7zip artifact path, it will use the right 7za with your platform
  196. */
  197. zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
  198. /**
  199. * optional,default '7za'
  200. * you can specify the 7za path yourself, it will overwrite the zipArtifact value
  201. */
  202. // path = "/usr/local/bin/7za"
  203. }
  204. }
  205. List<String> flavors = new ArrayList<>();
  206. project.android.productFlavors.each { flavor ->
  207. flavors.add(flavor.name)
  208. }
  209. boolean hasFlavors = flavors.size() > 0
  210. def date = new Date().format("MMdd-HH-mm-ss")
  211. /**
  212. * bak apk and mapping
  213. */
  214. android.applicationVariants.all { variant ->
  215. /**
  216. * task type, you want to bak
  217. */
  218. def taskName = variant.name
  219. tasks.all {
  220. if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
  221. it.doLast {
  222. copy {
  223. def fileNamePrefix = "${project.name}-${variant.baseName}"
  224. def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}"
  225. def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath
  226. from variant.outputs.first().outputFile
  227. into destPath
  228. rename { String fileName ->
  229. fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")
  230. }
  231. from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"
  232. into destPath
  233. rename { String fileName ->
  234. fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")
  235. }
  236. from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"
  237. into destPath
  238. rename { String fileName ->
  239. fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")
  240. }
  241. }
  242. }
  243. }
  244. }
  245. }
  246. project.afterEvaluate {
  247. //sample use for build all flavor for one time
  248. if (hasFlavors) {
  249. task(tinkerPatchAllFlavorRelease) {
  250. group = 'tinker'
  251. def originOldPath = getTinkerBuildFlavorDirectory()
  252. for (String flavor : flavors) {
  253. def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release")
  254. dependsOn tinkerTask
  255. def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest")
  256. preAssembleTask.doFirst {
  257. String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15)
  258. project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk"
  259. project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt"
  260. project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt"
  261. }
  262. }
  263. }
  264. task(tinkerPatchAllFlavorDebug) {
  265. group = 'tinker'
  266. def originOldPath = getTinkerBuildFlavorDirectory()
  267. for (String flavor : flavors) {
  268. def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug")
  269. dependsOn tinkerTask
  270. def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest")
  271. preAssembleTask.doFirst {
  272. String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13)
  273. project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk"
  274. project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt"
  275. project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt"
  276. }
  277. }
  278. }
  279. }
  280. }
  281. }
(6)以下为妙果app下的build.gradle
  1. apply plugin: 'com.android.application'
  2. apply plugin: 'com.tencent.tinker.patch'
  3. def javaVersion=JavaVersion.VERSION_1_7
  4. def bakPath = file("${buildDir}/bakApk/")//指定基准文件(oldApk)存放位置
  5. def getTinkerIdValue() {//和版本号一致
  6. return "2.0.1"
  7. }
  8. def getTinkerAppliactionName(){//继承TinkerApplication的类名
  9. return "com.lookbi.miaoguo.AppContext"
  10. }
  11. ext {
  12. tinkerEnabled = true
  13. tinkerOldApkPath = "${bakPath}/app-offLine-debug.apk"
  14. tinkerApplyMappingPath = "${bakPath}/app-offLine-debug-mapping.txt"
  15. tinkerApplyResourcePath = "${bakPath}/app-offLine-debug-R.txt"
  16. tinkerBuildFlavorDirectory = "${bakPath}/app-0408-15-13-44"
  17. }
  18. dependencies {
  19. implementation fileTree(include: ['*.jar'], dir: 'libs')
  20. implementation 'com.android.support:appcompat-v7:27.+'
  21. implementation 'com.android.support.constraint:constraint-layout:1.0.2'
  22. testImplementation 'junit:junit:4.12'
  23. androidTestImplementation 'com.android.support.test:runner:1.0.1'
  24. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
  25. implementation 'com.jakewharton:butterknife:8.4.0'
  26. annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
  27. implementation("com.tencent.tinker:tinker-android-lib:1.9.5") { changing = true }
  28. annotationProcessor("com.tencent.tinker:tinker-android-anno:1.9.5") { changing = true }
  29. compileOnly("com.tencent.tinker:tinker-android-anno:1.9.5") { changing = true }
  30. implementation project(':baselib')
  31. implementation project(':deckview')
  32. implementation project(':jiaozivideoplayer')
  33. implementation project(':mzbanner')
  34. implementation('com.github.gzu-liyujiang.AndroidPicker:WheelPicker:1.5.5') {
  35. exclude group: 'com.android.support'
  36. }
  37. implementation files('libs/MobCommons-2017.0412.1554.jar')
  38. }
  39. android {
  40. signingConfigs {
  41. key {
  42. keyAlias RELEASE_KEY_ALIAS
  43. keyPassword RELEASE_STORE_PASSWORD
  44. storeFile file(RELEASE_STORE_FILE)
  45. storePassword RELEASE_KEY_PASSWORD
  46. }
  47. }
  48. compileSdkVersion 26
  49. defaultConfig {
  50. applicationId "com.lookbi.miaoguo"
  51. minSdkVersion 17
  52. targetSdkVersion 26
  53. versionCode 201
  54. versionName "2.0.1"
  55. flavorDimensions "versionCode"
  56. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  57. multiDexEnabled true
  58. buildConfigField "String", "MESSAGE", "\"I am the base apk\""
  59. buildConfigField "String", "TINKER_ID", "\"${getTinkerIdValue()}\""
  60. buildConfigField "String", "PLATFORM", "\"all\""
  61. }
  62. //执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。
  63. lintOptions {
  64. checkReleaseBuilds false
  65. abortOnError false
  66. }
  67. repositories {
  68. flatDir {
  69. dirs 'libs'
  70. }
  71. }
  72. //java版本
  73. compileOptions {
  74. sourceCompatibility javaVersion
  75. targetCompatibility javaVersion
  76. }
  77. //建议 recommend Tinker相关配置
  78. dexOptions {
  79. //启动矩形模式
  80. jumboMode = true
  81. }
  82. buildTypes {
  83. debug {
  84. minifyEnabled true
  85. //是否移除无用资源
  86. zipAlignEnabled true
  87. // 移除无用的resource文件
  88. shrinkResources true
  89. signingConfig signingConfigs.key
  90. //混淆配置
  91. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  92. multiDexEnabled true
  93. }
  94. release {
  95. //是否混淆
  96. minifyEnabled true
  97. //是否移除无用资源
  98. zipAlignEnabled true
  99. // 移除无用的resource文件
  100. shrinkResources true
  101. signingConfig signingConfigs.key
  102. //混淆配置
  103. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  104. multiDexEnabled true
  105. }
  106. }
  107. productFlavors {
  108. //测试环境
  109. offLine {
  110. applicationId 'com.lookbi.miaoguo'
  111. manifestPlaceholders = [
  112. app_name: "测-妙果"
  113. ]
  114. resValue("string" , "baseUrl","http://mg.ketao.com/")
  115. }
  116. //生产环境
  117. onLine {
  118. applicationId 'com.lookbi.miaoguo'
  119. manifestPlaceholders = [
  120. app_name: "妙果"
  121. ]
  122. resValue("string" , "baseUrl","http://miaoguo.cn/")
  123. }
  124. }
  125. }
  126. def getOldApkPath() {
  127. return hasProperty("OLD_APK") ? OLD_APK : ext.tinkerOldApkPath
  128. }
  129. def getApplyMappingPath() {
  130. return hasProperty("APPLY_MAPPING") ? APPLY_MAPPING : ext.tinkerApplyMappingPath
  131. }
  132. def getApplyResourceMappingPath() {
  133. return hasProperty("APPLY_RESOURCE") ? APPLY_RESOURCE : ext.tinkerApplyResourcePath
  134. }
  135. def buildWithTinker() {
  136. return hasProperty("TINKER_ENABLE") ? Boolean.parseBoolean(TINKER_ENABLE) : ext.tinkerEnabled
  137. }
  138. def getTinkerBuildFlavorDirectory() {
  139. return ext.tinkerBuildFlavorDirectory
  140. }
  141. if (buildWithTinker()) {
  142. apply plugin: 'com.tencent.tinker.patch'
  143. tinkerPatch {
  144. /**
  145. * necessary,default 'null'
  146. * the old apk path, use to diff with the new apk to build
  147. * add apk from the build/bakApk
  148. */
  149. oldApk = getOldApkPath()
  150. /**
  151. * optional,default 'false'
  152. * there are some cases we may get some warnings
  153. * if ignoreWarning is true, we would just assert the patch process
  154. * case 1: minSdkVersion is below 14, but you are using dexMode with raw.
  155. * it must be crash when load.
  156. * case 2: newly added Android Component in AndroidManifest.xml,
  157. * it must be crash when load.
  158. * case 3: loader classes in dex.loader{} are not keep in the main dex,
  159. * it must be let tinker not work.
  160. * case 4: loader classes in dex.loader{} changes,
  161. * loader classes is ues to load patch dex. it is useless to change them.
  162. * it won't crash, but these changes can't effect. you may ignore it
  163. * case 5: resources.arsc has changed, but we don't use applyResourceMapping to build
  164. */
  165. ignoreWarning = false
  166. /**
  167. * optional,default 'true'
  168. * whether sign the patch file
  169. * if not, you must do yourself. otherwise it can't check success during the patch loading
  170. * we will use the sign config with your build type
  171. */
  172. useSign = true
  173. /**
  174. * optional,default 'true'
  175. * whether use tinker to build
  176. */
  177. tinkerEnable = buildWithTinker()
  178. /**
  179. * Warning, applyMapping will affect the normal android build!
  180. */
  181. buildConfig {
  182. /**
  183. * optional,default 'null'
  184. * if we use tinkerPatch to build the patch apk, you'd better to apply the old
  185. * apk mapping file if minifyEnabled is enable!
  186. * Warning:
  187. * you must be careful that it will affect the normal assemble build!
  188. */
  189. applyMapping = getApplyMappingPath()
  190. /**
  191. * optional,default 'null'
  192. * It is nice to keep the resource id from R.txt file to reduce java changes
  193. */
  194. applyResourceMapping = getApplyResourceMappingPath()
  195. /**
  196. * necessary,default 'null'
  197. * because we don't want to check the base apk with md5 in the runtime(it is slow)
  198. * tinkerId is use to identify the unique base apk when the patch is tried to apply.
  199. * we can use git rev, svn rev or simply versionCode.
  200. * we will gen the tinkerId in your manifest automatic
  201. */
  202. tinkerId = getTinkerIdValue()
  203. /**
  204. * if keepDexApply is true, class in which dex refer to the old apk.
  205. * open this can reduce the dex diff file size.
  206. */
  207. keepDexApply = false
  208. /**
  209. * optional, default 'false'
  210. * Whether tinker should treat the base apk as the one being protected by app
  211. * protection tools.
  212. * If this attribute is true, the generated patch package will contain a
  213. * dex including all changed classes instead of any dexdiff patch-info files.
  214. */
  215. isProtectedApp = false
  216. /**
  217. * optional, default 'false'
  218. * Whether tinker should support component hotplug (add new component dynamically).
  219. * If this attribute is true, the component added in new apk will be available after
  220. * patch is successfully loaded. Otherwise an error would be announced when generating patch
  221. * on compile-time.
  222. *
  223. * <b>Notice that currently this feature is incubating and only support NON-EXPORTED Activity</b>
  224. */
  225. supportHotplugComponent = false
  226. }
  227. dex {
  228. /**
  229. * optional,default 'jar'
  230. * only can be 'raw' or 'jar'. for raw, we would keep its original format
  231. * for jar, we would repack dexes with zip format.
  232. * if you want to support below 14, you must use jar
  233. * or you want to save rom or check quicker, you can use raw mode also
  234. */
  235. dexMode = "jar"
  236. /**
  237. * necessary,default '[]'
  238. * what dexes in apk are expected to deal with tinkerPatch
  239. * it support * or ? pattern.
  240. */
  241. pattern = ["classes*.dex",
  242. "assets/secondary-dex-?.jar"]
  243. /**
  244. * necessary,default '[]'
  245. * Warning, it is very very important, loader classes can't change with patch.
  246. * thus, they will be removed from patch dexes.
  247. * you must put the following class into main dex.
  248. * Simply, you should add your own application {@code tinker.sample.android.SampleApplication}
  249. * own tinkerLoader, and the classes you use in them
  250. *
  251. */
  252. loader = [
  253. //use sample, let BaseBuildInfo unchangeable with tinker
  254. getTinkerAppliactionName()
  255. ]
  256. }
  257. lib {
  258. /**
  259. * optional,default '[]'
  260. * what library in apk are expected to deal with tinkerPatch
  261. * it support * or ? pattern.
  262. * for library in assets, we would just recover them in the patch directory
  263. * you can get them in TinkerLoadResult with Tinker
  264. */
  265. pattern = ["lib/*/*.so"]
  266. }
  267. res {
  268. /**
  269. * optional,default '[]'
  270. * what resource in apk are expected to deal with tinkerPatch
  271. * it support * or ? pattern.
  272. * you must include all your resources in apk here,
  273. * otherwise, they won't repack in the new apk resources.
  274. */
  275. pattern = ["res/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
  276. /**
  277. * optional,default '[]'
  278. * the resource file exclude patterns, ignore add, delete or modify resource change
  279. * it support * or ? pattern.
  280. * Warning, we can only use for files no relative with resources.arsc
  281. */
  282. ignoreChange = ["assets/sample_meta.txt"]
  283. /**
  284. * default 100kb
  285. * for modify resource, if it is larger than 'largeModSize'
  286. * we would like to use bsdiff algorithm to reduce patch file size
  287. */
  288. largeModSize = 100
  289. }
  290. packageConfig {
  291. /**
  292. * optional,default 'TINKER_ID, TINKER_ID_VALUE' 'NEW_TINKER_ID, NEW_TINKER_ID_VALUE'
  293. * package meta file gen. path is assets/package_meta.txt in patch file
  294. * you can use securityCheck.getPackageProperties() in your ownPackageCheck method
  295. * or TinkerLoadResult.getPackageConfigByName
  296. * we will get the TINKER_ID from the old apk manifest for you automatic,
  297. * other config files (such as patchMessage below)is not necessary
  298. */
  299. configField("patchMessage", "tinker is sample to use")
  300. /**
  301. * just a sample case, you can use such as sdkVersion, brand, channel...
  302. * you can parse it in the SamplePatchListener.
  303. * Then you can use patch conditional!
  304. */
  305. configField("platform", "all")
  306. /**
  307. * patch version via packageConfig
  308. */
  309. configField("patchVersion", "1.0")
  310. }
  311. //or you can add config filed outside, or get meta value from old apk
  312. //project.tinkerPatch.packageConfig.configField("test1", project.tinkerPatch.packageConfig.getMetaDataFromOldApk("Test"))
  313. //project.tinkerPatch.packageConfig.configField("test2", "sample")
  314. /**
  315. * if you don't use zipArtifact or path, we just use 7za to try
  316. */
  317. sevenZip {
  318. /**
  319. * optional,default '7za'
  320. * the 7zip artifact path, it will use the right 7za with your platform
  321. */
  322. zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
  323. /**
  324. * optional,default '7za'
  325. * you can specify the 7za path yourself, it will overwrite the zipArtifact value
  326. */
  327. // path = "/usr/local/bin/7za"
  328. }
  329. }
  330. List<String> flavors = new ArrayList<>();
  331. project.android.productFlavors.each { flavor ->
  332. flavors.add(flavor.name)
  333. }
  334. boolean hasFlavors = flavors.size() > 0
  335. def date = new Date().format("MMdd-HH-mm-ss")
  336. /**
  337. * bak apk and mapping
  338. */
  339. android.applicationVariants.all { variant ->
  340. /**
  341. * task type, you want to bak
  342. */
  343. def taskName = variant.name
  344. tasks.all {
  345. if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {
  346. it.doLast {
  347. copy {
  348. def fileNamePrefix = "${project.name}-${variant.baseName}"
  349. def newFileNamePrefix = hasFlavors ? "${fileNamePrefix}" : "${fileNamePrefix}-${date}"
  350. def destPath = hasFlavors ? file("${bakPath}/${project.name}-${date}/${variant.flavorName}") : bakPath
  351. from variant.outputs.first().outputFile
  352. into destPath
  353. rename { String fileName ->
  354. fileName.replace("${fileNamePrefix}.apk", "${newFileNamePrefix}.apk")
  355. }
  356. from "${buildDir}/outputs/mapping/${variant.dirName}/mapping.txt"
  357. into destPath
  358. rename { String fileName ->
  359. fileName.replace("mapping.txt", "${newFileNamePrefix}-mapping.txt")
  360. }
  361. from "${buildDir}/intermediates/symbols/${variant.dirName}/R.txt"
  362. into destPath
  363. rename { String fileName ->
  364. fileName.replace("R.txt", "${newFileNamePrefix}-R.txt")
  365. }
  366. }
  367. }
  368. }
  369. }
  370. }
  371. project.afterEvaluate {
  372. //sample use for build all flavor for one time
  373. if (hasFlavors) {
  374. task(tinkerPatchAllFlavorRelease) {
  375. group = 'tinker'
  376. def originOldPath = getTinkerBuildFlavorDirectory()
  377. for (String flavor : flavors) {
  378. def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Release")
  379. dependsOn tinkerTask
  380. def preAssembleTask = tasks.getByName("process${flavor.capitalize()}ReleaseManifest")
  381. preAssembleTask.doFirst {
  382. String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 15)
  383. project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release.apk"
  384. project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-mapping.txt"
  385. project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-release-R.txt"
  386. }
  387. }
  388. }
  389. task(tinkerPatchAllFlavorDebug) {
  390. group = 'tinker'
  391. def originOldPath = getTinkerBuildFlavorDirectory()
  392. for (String flavor : flavors) {
  393. def tinkerTask = tasks.getByName("tinkerPatch${flavor.capitalize()}Debug")
  394. dependsOn tinkerTask
  395. def preAssembleTask = tasks.getByName("process${flavor.capitalize()}DebugManifest")
  396. preAssembleTask.doFirst {
  397. String flavorName = preAssembleTask.name.substring(7, 8).toLowerCase() + preAssembleTask.name.substring(8, preAssembleTask.name.length() - 13)
  398. project.tinkerPatch.oldApk = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug.apk"
  399. project.tinkerPatch.buildConfig.applyMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-mapping.txt"
  400. project.tinkerPatch.buildConfig.applyResourceMapping = "${originOldPath}/${flavorName}/${project.name}-${flavorName}-debug-R.txt"
  401. }
  402. }
  403. }
  404. }
  405. }
  406. }

3.编译后修改Application文件

4.编译基版本(发布到用户手里的版本)

5.编译补丁apk

6.补丁包上传服务器,客户端下载修复



添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注