As we all know, starting from Android 12, after using TargetSDK 31, four major components using Intent-filter without explicitly configured properties will fail to install and even fail to compile.
For example, activities that are started need to be set to True exported, and other components need to be set to True depending on whether they need to be called by other applications.
However, this is the state of affairs:
- If something goes wrong
AndroidManifest
The file is your local, that manual modification can; - But if the problem is a third-party remote dependency that doesn’t provide the source code and updates, you can’t change it directly.
- If a third party relies on too much, finding out what went wrong can be time-consuming and laborious.
The script
As a result, a set of exported scripts for Android 12 that do not have the ability to compile or install Android :exported are provided in the previous Article Android 12 Quick Fit Tips.
Com. Android. Tools. Build: gradle: 4.0.0 and its version
Gradle :4.0.0 & gradle-6.1.1-all.zip
/** * Modify Android 12 because of exported build issues */
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"
/ / / designated space
def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android'.'android')
def nodes = xml.application[0].The '*'.findAll {
// Select nodes to be modified. Those that are not specified need to be added
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(androidSpace.exported) == null
}
/// Add exported, default is 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()
}
}
}
Copy the code
Com. Android. Tools. Build: gradle: 4.0.0 above
The following scripts have been tested for supported versions: Gradle :4.1.0 & gradle-6.5.1-all.zip
/** * Modify Android 12 because of exported build issues */
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
/// The second argument is false, so the namespace is expanded, so androidSpace is not used, nameTag is used instead
def xml = new XmlParser(false.false).parse(manifestFile)
def exportedTag = "android:exported"
def nameTag = "android:name"
/ / / designated space
//def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
def nodes = xml.application[0].The '*'.findAll {
// Select nodes to be modified. Those that are not specified need to be added
Exported. Attribute (androidSpace. Exported)
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(exportedTag) == null
}
/// Add exported, default is false
nodes.each {
def isMain = false
it.each {
if (it.name() == "intent-filter") {
it.each {
if (it.name() == "action") {
// If nameTag is not available, try 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()
}
}
}
}
Copy the code
Gradle: gradle: gradle: gradle: gradle: gradle: gradle: gradle: gradle: gradle: gradle
Retrieve all exported components during the packaging process and dynamically configure them to be exported. There is a special point to note here, because the default to start an Activity is to start it with a Launcher. So “android intent. Action. MAIN” need to be exported is set to true. (PS: It’s more formal to use the LAUNCHER category, intentionally using MAIN.)
Then comprehensive questions, specific feedback questions are as follows:
-
Label is written to Chinese directly, not by reference to @string, so it can run normally in the 3.x version, but cannot be packaged;
-
Class XmlParser couldn’t find the first determine whether AGP version and Gradle version match, the concrete Gradle – the plugin, XmlParser or groovy.xml.XmlParser. If the gradle file is red, it does not affect running.
-
Android: Exported needs
Error: android:exported needs to be explicitly specified for <xxxx>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined.
Copy the code
Based on the above scripted tests and feedback, the conclusions so far are:
Starting from gradle:4.2.0 & gradle-6.7.1-all.zip, TargetSDK 31 script should be abnormal because at the stage of processDebugMainManifest (with Main), Androidmanifest.xml will be scanned directly from the dependent library and thrown with a direct error, stopping the compilation before proceeding to the processDebugManifest task phase, so the script is not actually running successfully.
Androidmanifest.xml in mergerd_manifest has not been created successfully, so the task cannot be entered. Is the script is currently available only for gradle: 4.1.0 and its version to install the apk Android12 machine, are intent – filter but not exoprted adaptation problems, based on this problem, I do not know if you have any good Suggestions?
A new script
Gradle :4.2.0 & Gradle-6.7.1 -all.zip: gradle:4.2.0 & Gradle-6.7.1 -all.zip: gradle:4.2.0 & Gradle-6.7.1 -all.zip: gradle:4.2.0 & Gradle-6.7.1 -all.zip: 7.0
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
//println("=============== ${variant.getBuildType().name.toUpperCase()} ===============")
//println("=============== ${variant.getFlavorName()} ===============")
def vn
if(variant.getFlavorName() ! =null&& variant.getFlavorName() ! ="") {
vn = variant.name;
} else {
if (variant.getBuildType().name == "release") {
vn = "Release"
} else {
vn = "Debug"}}def taskName = "process${vn}MainManifest";
try {
println("=============== taskName ${taskName} ===============")
project.getTasks().getByName(taskName)
} catch (Exception e) {
return
}
/// Your custom name
project.getTasks().getByName(taskName).doFirst {
//def method = it.getClass().getMethods()
it.getManifests().getFiles().each {
if (it.exists() && it.canRead()) {
def manifestFile = it
def exportedTag = "android:exported"
def nameTag = "android:name"
/// The second argument is false, so the namespace is expanded, so androidSpace is not used, nameTag is used instead
def xml = new XmlParser(false.false).parse(manifestFile)
if(xml.application ! =null && xml.application.size(a) >0) {
def nodes = xml.application[0].The '*'.findAll {
// Select nodes to be modified. Those that are not specified need to be added
Exported. Attribute (androidSpace. Exported)
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(exportedTag) == null
}
if(nodes.application ! =null && nodes.application.size(a) >0) {
nodes.each {
def t = it
it.each {
if (it.name() == "intent-filter") {
println("$manifestFile \n ..................... ${t.attributes().get(nameTag)}......................")}}}}}}}}}}Copy the code
As shown in the figure below, because the current official information in red is not pointing correctly, which is easy to mislead the direction of the problem, the above script can be printed to quickly find the point where the problem is, and then use tool: Replace to temporarily solve the problem.
Specific script before why can’t use under high version AGP, the reason is that the new version in processDebugMainManifest, or processXXXXXXMainManifest processing logic has changed, By finding the implementation class for processDebugMainManifest, we can see that the problem arises by Merging the library manifest.
The realization of the processDebugMainManifest in ProcessApplicationManifest, The corresponding path is ProcessApplicationManifest – > MainfestHelper mergeManifestsForApplication – > MainfestMerger2
The error is that an exception occurs in the Merging library manifest stage, but the input of third-party dependent paths in the task at this stage mainly starts from the private Fun computeFullProviderList method. So the input to the third party in the mergeManifestsForApplication path is generated by this private method.
It feels like the only thing to consider is the internal sse object to change the path, but it is private and does not reproduce its contents well inside.
AndroidManifset = AndroidManifset; AndroidManifset = AndroidManifset; AndroidManifset = AndroidManifset; AndroidManifset = AndroidManifset; Do not know everybody has what quite good idea.
If there is a good solution, update later.
The last
If you are using a lower version of Gradle, you will be able to install Gradle successfully. If you are running Android12, you will be able to install Gradle successfully without any exported files.
1. If you are in the emulator 12, you may see an error message like the following, which tells you that android:exported questions:
* What went wrong:
Execution failed for task ':app:installDebug'.
> java.util.concurrent.ExecutionException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI: /data/app/vmdl487461761.tmp/base.apk (at Binary XML file line #358): xxxxx.Activity: Targeting S+ (version 31 and above) requires that an explicit value for android:exported be defined when intent filters are present
Copy the code
2. If you are a real machine 12, you may be prompted with INSTALL_FAILED_USER_RESTRICTED. I have to say that the failure to install miui system is misleading. On Xiaomi, also INSTALL_FAILED_USER_RESTRICTED:
Basically, that’s all. How to further optimize it needs to be tested in the future. So, do you have any questions or ideas about script implementation