众所周知,从 Android 12 开始,使用了 TargetSDK 31 之后,四大组件如果使用了 intent-filter,但是没显性质配置 exported App 将会无法安装,甚至编译不通过。
比如启动的 Activity 就需要设置 exported 为 true,至于其他组件是否设置为 true 则看它是否需要被其它应用调用。
然而这个事情的状态是这样的:
-
如果出现问题的 AndroidManifest 文件是您本地的,那手动修改即可;
-
但如果出现问题的是第三方远程依赖,并且对方并没有提供源码和更新,您就无法直接修改;
-
如果第三方依赖太多,查找哪些出了问题十分费时费力。
这块网上各个大佬之前都是采取脚本的方式解决的,原理其实也可简单,就是在打包过程中检索所有没有设置 exported
的组件,给他们动态配置上 exported
,这里有个特殊需要注意的是,因为启动 Activity
默认就是需要被 Launcher 打开的,所以 "android.intent.action.MAIN"
需要 exported
设置为 true
。
脚本如下:
以下脚本经过测试最高可到支持的版本: 「gradle:4.0.0 & gradle-6.1.1-all.zip」
/**
* 修改 Android 12 因为 exported 的构建问题
*/
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
output.processResources.doFirst { pm ->
String manifestPath = output.processResources.manifestFile
def manifestFile = new File(manifestPath)
def xml = new XmlParser(false, true).parse(manifestFile)
def exportedTag = "android:exported"
///指定 space
def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
def nodes = xml.application[0].'*'.findAll {
//挑选要修改的节点,没有指定的 exported 的才需要增加
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(androidSpace.exported) == null
}
///添加 exported,默认 false
nodes.each {
def isMain = false
it.each {
if (it.name() == "intent-filter") {
it.each {
if (it.name() == "action") {
if (it.attributes().get(androidSpace.name) == "android.intent.action.MAIN") {
isMain = true
println("......................MAIN FOUND......................")
}
}
}
}
}
it.attributes().put(exportedTag, "${isMain}")
}
PrintWriter pw = new PrintWriter(manifestFile)
pw.write(groovy.xml.XmlUtil.serialize(xml))
pw.close()
}
}
}
com.android.tools.build:gradle:4.0.0 以上版本
以下脚本经过测试支持的版本: 「gradle:4.1.0 & gradle-6.5.1-all.zip」
/**
* 修改 Android 12 因为 exported 的构建问题
*/
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def processManifest = output.getProcessManifestProvider().get()
processManifest.doLast { task ->
def outputDir = task.multiApkManifestOutputDirectory
File outputDirectory
if (outputDir instanceof File) {
outputDirectory = outputDir
} else {
outputDirectory = outputDir.get().asFile
}
File manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
println("----------- ${manifestOutFile} ----------- ")
if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
def manifestFile = manifestOutFile
///这里第二个参数是 false ,所以 namespace 是展开的,所以下面不能用 androidSpace,而是用 nameTag
def xml = new XmlParser(false, false).parse(manifestFile)
def exportedTag = "android:exported"
def nameTag = "android:name"
///指定 space
//def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
def nodes = xml.application[0].'*'.findAll {
//挑选要修改的节点,没有指定的 exported 的才需要增加
//如果 exportedTag 拿不到可以尝试 it.attribute(androidSpace.exported)
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(exportedTag) == null
}
///添加 exported,默认 false
nodes.each {
def isMain = false
it.each {
if (it.name() == "intent-filter") {
it.each {
if (it.name() == "action") {
//如果 nameTag 拿不到可以尝试 it.attribute(androidSpace.name)
if (it.attributes().get(nameTag) == "android.intent.action.MAIN") {
isMain = true
println("......................MAIN FOUND......................")
}
}
}
}
}
it.attributes().put(exportedTag, "${isMain}")
}
PrintWriter pw = new PrintWriter(manifestFile)
pw.write(groovy.xml.XmlUtil.serialize(xml))
pw.close()
}
}
}
}
这段脚本你可以直接放到 app/build.gradle
下执行,也可以单独放到一个 gradle 文件之后 apply
引入
但是问题是到了gradle 4.2+、gradle-6.7.1-all.zip
的时候,这些脚本就不能用了,原因「从 gradle:4.2.0 & gradle-6.7.1-all.zip
开始,TargetSDK 31 下脚本会有异常,因为在 processDebugMainManifest
(带有Main) 的阶段,会直接扫描依赖库的 AndroidManifest.xml
然后抛出直接报错,从而进不去 processDebugManifest
任务阶段就编译停止,所以实际上脚本并没有成功运行 ,针对这个,额,又有个大佬做了这块的处理,下面贴上大佬的解决方法:
manifest-exported-plugin
大佬的插件叫这个名字,使用方法:
依赖方式
添加jitpack仓库
build.gradle
Gradle7.0 以下
buildscript {
repositories {
// ...
maven { url 'https://jitpack.io' }
}
}
Gradle7.0+,并且已经对依赖方式进行过调整,则可能需要添加到如下位置:settings.gradle
pluginManagement {
repositories {
//...
maven { url 'https://jitpack.io' }
}
}
Gradle
dependencies {
classpath 'com.github.xiachufang:manifest-exported-plugin:1.1.1'
}
使用方式
添加插件
在主app Model中添加:
apply plugin: 'com.xiachufang.manifest.exported'
或
plugins {
id 'com.xiachufang.manifest.exported'
}
build.gradle
apply plugin: 'com.xiachufang.manifest.exported'
...
exported {
// 是否写入主Model
enableMainManifest false
// 规则
ruleFile new File("$projectDir/xxx.json")
// 输出文件,默认-app/build/exported/outManifestLog.md
outPutFile null
}
配置参数说明
enableMainManifest
是否对主 model-AndroidManifest 进行修改
对于主model,属于业务可控的,建议开发者自行调整。
插件默认不会对主 model-AndroidManifest 进行修改,如果发现可用匹配上述规则的,即会进行修正。
开发者可根据日志中的提示,进行修改。
注意:这个操作会对Manifest的展示样式造成一定影响,建议一般不要打开。
outPutFile
日志输出目录,默认 app/build/exported/outManifest.md
ruleFile
具体的规则json文件, 格式如下:
{
"actionRules": [
"android.intent.action.MAIN"
],
"whiteNames": [],
"blackPackages": [],
"blackNames": [],
"blackIgnores": []
}
actionRules
默认判断规则,用于当前没有配置 exported 的修改逻辑,如果当前存在exported,则跳过。
具体判断逻辑:
如果 intent-filter
– action
对应的 android:name 与 actionRules 中任意一条匹配,则将 exported
修改为 true ,否则为false 。
whiteNames
白名单类名,如果遇到此类,并且使用了 intent-filter ,则会将 exported
修改为 true
blackPackages
黑名单 包名合集,对于此包名下的类,如果使用了 intent-filter ,则会将 exported
直接修改为 false
blackNames
黑名单 类名合集,如果遇到此合集中的类,并且使用了 intent-filter ,则会将 exported
直接修改为 true 。判断逻辑会与上面 blackPackages
一起判断,两者满足其一即可。
blackIgnores
黑名单 下要忽视的类,在黑名单判断时,如果遇到此类,则使用默认规则 actionRules
判断。
注意的是:
对于主model下的 manifest
,默认不进行适配(可开关 enableManifest ),会通过日志进行输出,建议大家自行对比调整。
为什么默认不对主
model
进行适配?
- 对于业务
model
,我们建议开发者自行适配,这属于我们可控范围,适配来说主要就是为了不可控的,即第三方aar
- 修改之后,会影响原有的
manifest
代码风格,需要重新格式化一下,相比默认的,增加了不少空格,暂时不知道怎么解决。
原理简述
在ProgressXXXMainManifest任务之前进行插入,通过对manifest进行修改,从而实现exported的适配。
通常默认情况下,会在build文件夹下生成个export文件夹,其中有个outManifestLog.md,这个就等于是个插件执行日志之类的东西,嗯,就这样,反正挺6的就是
参考文章:
Android 12 自动适配 exported 深入解析避坑 – 知乎
https://github.com/xiachufang/manifest-exported-plugin
今天的文章android12适配名单_vmos适配安卓11分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/89597.html