天天看点

android 热修复 框架,[Android]腾讯Tinker热修复框架简单使用

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

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 = "${bakPath}/app-release-0601-14-29-28.apk"

//proguard mapping file to build patch apk

tinkerApplyMappingPath = "${bakPath}/app-release-0601-14-29-28-mapping.txt"

//resource R.txt to build patch apk, must input if there is resource changed

tinkerApplyResourcePath = "${bakPath}/app-release-0601-14-29-28-R.txt"

//only use for build all flavor, if not, just ignore this field

// tinkerBuildFlavorDirectory = "${bakPath}/app-0526-17-40-51"

}

//这个方法其实就是定义了一个tink_id

def getSha() {

try {

String tinkId = "tink_id_000000000"

if (tinkId == null) {

throw new RuntimeException("you should add tinkeId to system path or just input test value, such as 'testTinkerId'")

}

return tinkId

} catch (Exception e) {

throw new RuntimeException("you should add tinkeId to system path or just input test value, such as 'testTinkerId'")

}

}

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 : getSha()

}

def buildWithTinker() {

return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled

}

def getTinkerBuildFlavorDirectory() {

return ext.tinkerBuildFlavorDirectory

}

if (buildWithTinker()) {

apply plugin: 'com.tencent.tinker.patch'

tinkerPatch {

oldApk = getOldApkPath()

ignoreWarning = false

useSign = true

tinkerEnable = buildWithTinker()

buildConfig {

applyMapping = getApplyMappingPath()

applyResourceMapping = getApplyResourceMappingPath()

tinkerId = getTinkerIdValue()

keepDexApply = false

isProtectedApp = false

}

dex {

dexMode = "jar"

pattern = ["classes*.dex",

"assets/secondary-dex-?.jar"]

loader = [

//use sample, let BaseBuildInfo unchangeable with tinker

"com.tencent.tinker.loader.*",

"com.tencent.tinker.*",

"com.example.myapp.MyApplication"

]

}

lib {

pattern = ["lib

pattern = ["res

ignoreChange = ["assets/sample_meta.txt"]

largeModSize = 100

}

packageConfig {

configField("TINKER_ID", getSha())

configField("app_name", "MyApp")

configField("patchMessage", "这是一个测试");

configField("platform", "all")

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")

sevenZip {

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

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

}

}

List 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")

android.applicationVariants.all { variant ->

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"

}

}

}

}

}

}