Tencent / tinker

Tinker is a hot-fix solution library for Android, it supports dex, library and resources update without reinstall apk.
Other
17.1k stars 3.33k forks source link

Fix failed to write manifest in AGP 4.1. #1583

Open xjy2061 opened 3 years ago

xjy2061 commented 3 years ago

tinker 在 process${variant.name.capitalize()}Manifest 任务的产物 build/intermediates/merged_manifests 目录中的 AndroidManifest.xml 文件中写入了 tinker_id 等信息,而 AGP 4.1 新增了在 process${variant.name.capitalize()}Manifest 任务之后执行的任务 process${variant.name.capitalize()}ManifestForPackage,该任务的产物在 build/intermediates/packaged_manifests 目录中。

如果这 2 个任务命中了 gradle 缓存,执行状态都是 FROM-CACHE,那么最终 APK 中 manifest 文件中的 tinker_id 等信息是以前编译写入的旧信息。因此,对于 AGP 4.1,向 manifest 写入信息的时机应该改为 process${variant.name.capitalize()}ManifestForPackage 执行后,且目标文件应该改为 build/intermediates/packaged_manifests 目录中的 AndroidManifest.xml 文件。

@tomystang

tencent-adm commented 3 years ago

CLA assistant check
All committers have signed the CLA.

SoySauce1024 commented 2 years ago

已解决! 感谢!

eric-lian commented 2 years ago

两种解决方案 :

  1. 有条件的可以自己clone 工程修改 gradle 升级到 7.x TinkerManifestTask 修改 writeManifestMeta 方法的XmlParse 升级到7.0 以后 ,groovy XmlParse api发生变化
  2. // 禁用 tinker tinker_id task 写入 ,自己实现

project.tasks.all { Task task ->
    if (task.name == "processArm32ReleaseManifest") {
        task.doLast {
            def file = new File((task as ProcessMultiApkApplicationManifest).getMultiApkManifestOutputDirectory().get().asFile, "AndroidManifest.xml")
            writeManifestMeta(file.absolutePath, "TINKER_ID", getShortCommitId())
        }
    } else if (task.name == "tinkerProcessArm32ReleaseManifest") {
        task.enabled = false
    }
}

def writeManifestMeta(String manifestPath, String name, String value) {
    def ns = new Namespace("http://schemas.android.com/apk/res/android", "android")
    def isr = null
    def pw = null
    try {
        isr = new InputStreamReader(new FileInputStream(manifestPath), "utf-8")
        def xml = new groovy.xml.XmlParser().parse(isr) as Node
        def application = xml.application[0] as Node
        if (application) {
            def metaDataTags = application['meta-data']

            // remove any old TINKER_ID elements
            def tinkerId = metaDataTags.findAll {
                it.attributes()[ns.name].equals(name)
            }.each {
                it.parent().remove(it)
            }

            // Add the new TINKER_ID element
            application.appendNode('meta-data', [(ns.prefix + ':name'): name, (ns.prefix + ':value'): value])

            // Write the manifest file
            pw = new PrintWriter(manifestPath, "utf-8")
            def printer = new groovy.xml.XmlNodePrinter(pw)
            printer.preserveWhitespace = true
            printer.print(xml)
        }
    } finally {
        IOHelper.closeQuietly(pw)
        IOHelper.closeQuietly(isr)
    }
}
zhbzhbzhbz commented 1 year ago

亲测,使用这篇的配置,打包就没有问题了: Gradle插件版本(3.6.3):classpath 'com.android.tools.build:gradle:3.6.3' Gradle版本(5.6.4):distributionUrl=https://services.gradle.org/distributions/gradle-5.6.4-all.zip Bugly Gradle插件版本(1.2.3):classpath "com.tencent.bugly:tinker-support:1.2.3" Tinker插件版本(1.9.14.16):implementation 'com.tencent.tinker:tinker-android-lib:1.9.14.16'