-
Notifications
You must be signed in to change notification settings - Fork 0
/
tinker.gradle
executable file
·335 lines (303 loc) · 13.4 KB
/
tinker.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
// 备份主目录
def bakPath = file("${project.projectDir}/bakApk/")
// 备份目录名称
def backDir = "${bakPath}/${baseApkDir}"
//文件名
def appName = "${versionName}"
def tinkerBuildId = new Date().format("MMddHHmmss")
def tinkerOutId = "${versionName}.${versionCode}-${tinkerBuildId}"
ext {
//for some reason, you may want to ignore tinkerBuild, such as instant run debug build?
tinkerEnabled = true
//for normal build
//old apk file to build patch apk
tinkerOldApkPath = "${backDir}/${appName}.apk"
//proguard mapping file to build patch apk
tinkerApplyMappingPath = "${backDir}/${appName}-mapping.txt"
//resource R.txt to build patch apk, must input if there is resource changed
tinkerApplyResourcePath = "${backDir}/${appName}-R.txt"
//only use for build all flavor, if not, just ignore this field
tinkerBuildFlavorDirectory = "${backDir}/${appName}"
outTinkerId = "${tinkerOutId}"
}
def getOldApkPath() {
return ext.tinkerOldApkPath
}
def getApplyMappingPath() {
return ext.tinkerApplyMappingPath
}
def getApplyResourceMappingPath() {
return ext.tinkerApplyResourcePath
}
def getTinkerIdValue() {
return ext.outTinkerId
}
def buildWithTinker() {
return ext.tinkerEnabled
}
def getTinkerBuildFlavorDirectory() {
return ext.tinkerBuildFlavorDirectory
}
android {
defaultConfig {
buildConfigField "String", "TINKER_ID", "\"${tinkerOutId}\""
buildConfigField "String", "PLATFORM", "\"all\""
}
}
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 = true
/**
* 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 = true
/**
* optional, default 'false'
* Whether tinker should support component hotplug (add new component dynamically).
* If this attribute is true, the component added in new apk will be available after
* patch is successfully loaded. Otherwise an error would be announced when generating patch
* on compile-time.
*
* <b>Notice that currently this feature is incubating and only support NON-EXPORTED Activity</b>
*/
supportHotplugComponent = true
}
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 = []
}
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.
* andresguard 混淆需要添加“r/*“
*/
pattern = ["res/*", "r/*","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:${ANDRESGUARD_VERSION}"
/**
* optional,default '7za'
* you can specify the 7za path yourself, it will overwrite the zipArtifact value
*/
// path = "/usr/local/bin/7za"
}
}
project.afterEvaluate {
/**
* bak apk and mapping
*/
android.applicationVariants.all { variant ->
/**
* task type, you want to bak
*/
def taskName = variant.name
def versionName = variant.versionName
// find resguard task first
def resguardTask = project.tasks.findByName("resguard${taskName.capitalize()}")
if (resguardTask == null) {
println("resguardTask not found, just return")
return
}
def tinkerPatchTask = project.tasks.findByName("tinkerPatch${taskName.capitalize()}")
if (tinkerPatchTask == null) {
println("resguardTask not found, just return")
return
}
tinkerPatchTask.doFirst {
def buildApkPath = "${buildDir}/outputs/apk/${taskName}/AndResGuard_${project.getName()}-${taskName}-${versionName}/${project.getName()}-${taskName}-${versionName}_7zip_aligned_signed.apk"
println("change tinkerPatchTask buildApkPath to resugurad output ${buildApkPath}")
tinkerPatchTask.buildApkPath = buildApkPath
}
tinkerPatchTask.dependsOn resguardTask
resguardTask.doLast {
copy {
def bakResguardDir = bakPath.absolutePath + "/${tinkerOutId}"
from "${buildDir}/outputs/apk/${taskName}/AndResGuard_${project.getName()}-${taskName}-${versionName}/${project.getName()}-${taskName}-${versionName}_7zip_aligned_signed.apk"
into file(bakResguardDir)
rename { String fileName ->
fileName.replace("${project.getName()}-${taskName}-${versionName}_7zip_aligned_signed.apk", "${versionName}.apk")
}
from "${buildDir}/outputs/mapping/${taskName}/mapping.txt"
into file(bakResguardDir)
rename { String fileName ->
fileName.replace("mapping.txt", "${versionName}-mapping.txt")
}
from "${buildDir}/intermediates/symbols/${taskName}/R.txt"
into file(bakResguardDir)
rename { String fileName ->
fileName.replace("R.txt", "${versionName}-R.txt")
}
from "${buildDir}/outputs/apk/${taskName}/AndResGuard_${project.getName()}-${taskName}/resource_mapping_${project.getName()}-release.txt"
into file(bakResguardDir)
rename { String fileName ->
fileName.replace("resource_mapping_${project.getName()}-release.txt", "${versionName}-resource_mapping.txt")
}
}
}
tinkerPatchTask.doLast {
copy {
def patchApkPath = "${buildDir}/outputs/apk/tinkerPatch/${taskName}/patch_signed_7zip.apk"
println("change tinkerPatchTask patchApkPath to resugurad output ${patchApkPath}")
from patchApkPath
into file(backDir)
rename { String fileName ->
fileName.replace("patch_signed_7zip.apk", "${tinkerOutId}.apk")
}
// 删除打patch包时候产生的新基线包
def delBackDir = "${bakPath}/${tinkerOutId}"
println("delete new tinker patch baseApkPath :${delBackDir}")
delete delBackDir
}
}
}
}
}