tinker
tinker copied to clipboard
AndroidManifest清单中application的name属性自定义Application无法被自动添加到 loader 问题。
异常类型:编译异常
手机型号:无
手机系统版本:无
tinker版本:1.9.14.20
gradle版本:Gradle 7.4.2 / AGP 7.1.2
是否使用热更新SDK: 无
系统:win11-64、ubuntu
堆栈/日志:
TinkerManifestTask#readManifestApplicationName 方法在如上环境中运行时获取到清单文件中 application 的 name 值是空。
问题本质原因分析如下:
static String readManifestApplicationName(def project, String manifestPath) {
def isr = null
try {
isr = new InputStreamReader(new FileInputStream(manifestPath), "utf-8")
def xml = new XmlParser().parse(isr)
def ns = new Namespace("http://schemas.android.com/apk/res/android", "android")
def application = xml.application[0]
def applicationName = null
if (application) {
applicationName = application.attributes()[ns.name]
application.attributes().each { k, v->
project.logger.error("FROM XmlParser: ${k.getClass()}---${k.namespaceURI}, ${k.localPart}")
project.logger.error("FROM Namespace: ${ns.name.getClass()}---${ns.name.namespaceURI}, ${ns.name.localPart}")
if (k.namespaceURI.equals(ns.name.namespaceURI) && k.localPart.equals(ns.name.localPart)) {
project.logger.error("=============matched 1")
}
if (k.equals(ns.name)) {
project.logger.error("=============matched 2")
}
}
}
return applicationName
} finally {
IOHelper.closeQuietly(isr)
}
}
如上代码在高版本 gradle 配合 agp 中输出:
FROM XmlParser: class groovy.xml.QName---http://schemas.android.com/apk/res/android, name
FROM Namespace: class groovy.namespace.QName---http://schemas.android.com/apk/res/android, name
=============matched 1
低版本中没问题,分析发现,高低版本 gradle 依赖的 groovy 版本不一样。
低版本: groovy.util.XmlParser 内部对应 groovy.xml.QName groovy.xml.Namespace 内部对应 groovy.xml.QName 所以从 application.attributes() 的 map 中通过 QName key 去获取是可以找到对应 hashkey 的 value。
高版本: groovy.util.XmlParser 内部对应 groovy.xml.QName groovy.xml.Namespace 内部对应 groovy.namespace.QName 所以从 application.attributes() 的 map 中通过 QName key 去获取是无法找到对应 hashkey 的 value,因为类名 QName 相同,但是 package name 已经不同了,导致 equals 方法无法相等,除非 XmlParser 也使用 groovy.xml 包下的,但是高版本 groovy 才有这个。
因此修复方案换成 XmlSlurper 即可兼容高低不同版本 groovy。