Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

生成release版本时没有生成tinker_proguard.pro混淆文件导致报错 #1760

Open
2284990886 opened this issue Dec 11, 2024 · 0 comments

Comments

@2284990886
Copy link

使用官方demo可以正常打包release版,自己项目集成时打包混淆出现错误,后来发现是打包时没有自动生成tinker_proguard.pro混淆文件导致混淆出错,请问有没有人出现过相关问题下面是接入代码

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url "https://jitpack.io" }
google()
jcenter()

}
dependencies {

    classpath 'com.android.tools.build:gradle:3.5.2'
    classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
}

}

allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
maven { url "https://jitpack.io" }
google()
jcenter()

}

}

task clean(type: Delete) {
delete rootProject.buildDir
}


apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
multiDexEnabled true
multiDexKeepProguard file("tinker_multidexkeep.pro")
applicationId "com.gdxn.myapplication"
minSdkVersion 19
targetSdkVersion 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    /**
     * buildConfig can change during patch!
     * we can use the newly value when patch
     */
    buildConfigField "String", "MESSAGE", "\"I am the base apk\""

// buildConfigField "String", "MESSAGE", ""I am the patch apk""
/**
* client version would update with patch
* so we can get the newly git version easily!
*/
buildConfigField "String", "TINKER_ID", ""${getTinkerIdValue()}""
buildConfigField "String", "PLATFORM", ""all""
}
signingConfigs {
config {
keyAlias 'android'
keyPassword 'xyq123456'
storeFile file('../sign/xyq.jks')
storePassword 'xyq123456'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled true
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled false
signingConfig signingConfigs.config
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

    }
}
dexOptions {
    // 支持大工程模式
    jumboMode = true
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.annotation:annotation:1.0.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
//腾讯热更新
implementation "com.android.support:multidex:1.0.1"
//tinker的核心库
implementation("com.tencent.tinker:tinker-android-lib:1.9.1")
//可选,用于生成application类
annotationProcessor("com.tencent.tinker:tinker-android-anno:1.9.1")
compileOnly("com.tencent.tinker:tinker-android-anno:1.9.1")

}

// Tinker配置与任务
def bakPath = file("${buildDir}/bakApk/")
ext {
// 是否使用Tinker(当你的项目处于开发调试阶段时,可以改为false)
tinkerEnabled = true
// 基础包文件路径(名字这里写死为old-app.apk。用于比较新旧app以生成补丁包,不管是debug还是release编译)
tinkerOldApkPath = "${bakPath}/old-app.apk"
// 基础包的mapping.txt文件路径(用于辅助混淆补丁包的生成,一般在生成release版app时会使用到混淆,所以这个mapping.txt文件一般只是用于release安装包补丁的生成)
tinkerApplyMappingPath = "${bakPath}/old-app-mapping.txt"
// 基础包的R.txt文件路径(如果你的安装包中资源文件有改动,则需要使用该R.txt文件来辅助生成补丁包)
tinkerApplyResourcePath = "${bakPath}/old-app-R.txt"
//only use for build all flavor, if not, just ignore this field
tinkerBuildFlavorDirectory = "${bakPath}/flavor"
}

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 : android.defaultConfig.versionName
}

def buildWithTinker() {
return hasProperty("TINKER_ENABLE") ? TINKER_ENABLE : ext.tinkerEnabled
}

def getTinkerBuildFlavorDirectory() {
return ext.tinkerBuildFlavorDirectory
}

if (buildWithTinker()) {
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'

// 全局信息相关的配置项
tinkerPatch {
    tinkerEnable = buildWithTinker()// 是否打开tinker的功能。
    oldApk = getOldApkPath()        // 基准apk包的路径,必须输入,否则会报错。
    ignoreWarning = true           // 是否忽略有风险的补丁包。这里选择不忽略,当补丁包风险时会中断编译。
    useSign = true                  // 在运行过程中,我们需要验证基准apk包与补丁包的签名是否一致,我们是否需要为你签名。
    // 编译相关的配置项
    buildConfig {
        applyMapping = getApplyMappingPath()
        // 可选参数;在编译新的apk时候,我们希望通过保持旧apk的proguard混淆方式,从而减少补丁包的大小。这个只是推荐设置,不设置applyMapping也不会影响任何的assemble编译。
        applyResourceMapping = getApplyResourceMappingPath()
        // 可选参数;在编译新的apk时候,我们希望通过旧apk的R.txt文件保持ResId的分配,这样不仅可以减少补丁包的大小,同时也避免由于ResId改变导致remote view异常。
        tinkerId = getTinkerIdValue()
        // 在运行过程中,我们需要验证基准apk包的tinkerId是否等于补丁包的tinkerId。这个是决定补丁包能运行在哪些基准包上面,一般来说我们可以使用git版本号、versionName等等。
        keepDexApply = false
        // 如果我们有多个dex,编译补丁时可能会由于类的移动导致变更增多。若打开keepDexApply模式,补丁包将根据基准包的类分布来编译。
        isProtectedApp = false // 是否使用加固模式,仅仅将变更的类合成补丁。注意,这种模式仅仅可以用于加固应用中。
        supportHotplugComponent = true // 是否支持新增非export的Activity(1.9.0版本开始才有的新功能)
    }
    // dex相关的配置项
    dex {
        dexMode = "jar"

// 只能是'raw'或者'jar'。 对于'raw'模式,我们将会保持输入dex的格式。对于'jar'模式,我们将会把输入dex重新压缩封装到jar。如果你的minSdkVersion小于14,你必须选择‘jar’模式,而且它更省存储空间,但是验证md5时比'raw'模式耗时。默认我们并不会去校验md5,一般情况下选择jar模式即可。
pattern = ["classes*.dex",
"assets/secondary-dex-?.jar"]
// 需要处理dex路径,支持*、?通配符,必须使用'/'分割。路径是相对安装包的,例如assets/...
loader = [
// 定义哪些类在加载补丁包的时候会用到。这些类是通过Tinker无法修改的类,也是一定要放在main dex的类。
// 如果你自定义了TinkerLoader,需要将它以及它引用的所有类也加入loader中;
// 其他一些你不希望被更改的类,例如Sample中的BaseBuildInfo类。这里需要注意的是,这些类的直接引用类也需要加入到loader中。或者你需要将这个类变成非preverify。
]
}
// lib相关的配置项
lib {
pattern = ["lib//.so", "src/main/jniLibs//.so"]
// 需要处理lib路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如assets/...
}
// res相关的配置项
res {
pattern = ["res/", "assets/", "resources.arsc", "AndroidManifest.xml"]
// 需要处理res路径,支持*、?通配符,必须使用'/'分割。与dex.pattern一致, 路径是相对安装包的,例如assets/...,务必注意的是,只有满足pattern的资源才会放到合成后的资源包。
ignoreChange = [
// 支持*、?通配符,必须使用'/'分割。若满足ignoreChange的pattern,在编译时会忽略该文件的新增、删除与修改。 最极端的情况,ignoreChange与上面的pattern一致,即会完全忽略所有资源的修改。
"assets/sample_meta.txt"
]
largeModSize = 100
// 对于修改的资源,如果大于largeModSize,我们将使用bsdiff算法。这可以降低补丁包的大小,但是会增加合成时的复杂度。默认大小为100kb
}
// 用于生成补丁包中的'package_meta.txt'文件
packageConfig {
// configField("key", "value"), 默认我们自动从基准安装包与新安装包的Manifest中读取tinkerId,并自动写入configField。
// 在这里,你可以定义其他的信息,在运行时可以通过TinkerLoadResult.getPackageConfigByName得到相应的数值。
// 但是建议直接通过修改代码来实现,例如BuildConfig。
configField("platform", "all")
configField("patchVersion", "1.0")
// configField("patchMessage", "tinker is sample to use")
}
// 7zip路径配置项,执行前提是useSign为true
sevenZip {
zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
}
}
List flavors = new ArrayList<>();
project.android.productFlavors.each { flavor ->
flavors.add(flavor.name)
}
boolean hasFlavors = flavors.size() > 0
def date = new Date().format("yyyy-MM-dd")

/**
 * 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.first().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"
                }

            }
        }
    }
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant