Android笔记(二十四):gradle写一个android12自动适配exported脚本,支持aab

背景

由于Google play的政策,提审aab的时候需要适配android12,适配android12最大的工作就是在AndroidManifesst.xml文件中声明的四大组件,都要显式声明exported字段。如果手动添加,在遇到第三方sdk时就会比较麻烦,所以只能使用gradle脚本自动添加,而网上给的gradle脚本例子都是只对apk生效,所以自己手动改造一下,以支持aab。

步骤

定义修改manifest文件的方法

遍历AndroidManifest.xml文件的每一个节点,识别到activity,receiver,service节点时,如果未声明exported字段则添加上去,入口类为true,其他默认为false

def fixManifest(File mainManifestFile) {
    
    
    try {
    
    
        def xml = new XmlParser(false, true).parse(mainManifestFile)
        def exportedTag = "android:exported"
        def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')

        def nodes = xml.application[0].'*'.findAll {
    
    
            (it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(androidSpace.exported) == null
        }
        nodes.each {
    
    
            def exportedValue = false
            it.each {
    
    
                if (it.name() == "intent-filter") {
    
    
                    it.each {
    
    
                        if (it.name() == "action") {
    
    
                            if (it.attributes().get(androidSpace.name) == "android.intent.action.MAIN") {
    
    
                                exportedValue = true
                            }
                        }
                    }
                }
            }
            it.attributes().put(exportedTag, "${
      
      exportedValue}")
        }

        PrintWriter pw = new PrintWriter(mainManifestFile)
        pw.write(groovy.xml.XmlUtil.serialize(xml))
        pw.close()

    } catch (Exception e) {
    
    
    }
}

打包流程中在特定task中插入代码段

  1. 打包debug/release apk时,会执行processDebugResources/processReleaseResources task将合并后的manifest打包进最终产物中,可以在gradle执行该task之前拦截,调用上面定义的方法修改manifest
    在这里插入图片描述
  2. 打包debug/release aab时,会执行processDebugManifest/processReleaseManifest task将所有依赖的aar或library module中AndroidManifest.xml中的节点,合并到项目的AndroidManifest.xml中,可以在gradle执行该task之后拦截,调用上面定义的方法修改manifest
    在这里插入图片描述

配置variant

获取打包的variant名称,以及打apk/bundle包时,manifest输出目录

project.afterEvaluate {
    
    
    android.applicationVariants.all {
    
     variant ->
        variant.outputs.all {
    
     output ->
            def s1 = output.processManifest.manifestOutputDirectory.get().asFile.absolutePath
            def s2 = output.processManifest.bundleManifestOutputDirectory.get().asFile.absolutePath
            def variantName = variant.name.capitalize()
            checkPackageType(project, variantName, s1, s2)
        }
    }
}

效果

查看打包后的aab manifest文件,第三方activity被自动添加上exported字段
在这里插入图片描述

完整代码

project.afterEvaluate {
    
    
    android.applicationVariants.all {
    
     variant ->
        variant.outputs.all {
    
     output ->
            def s1 = output.processManifest.manifestOutputDirectory.get().asFile.absolutePath
            def s2 = output.processManifest.bundleManifestOutputDirectory.get().asFile.absolutePath
            def variantName = variant.name.capitalize()
            addManifestTask(project, variantName, s1, s2)
        }
    }
}

def addManifestTask(Project project, String variantName, manifestPath, bundleManifestPath) {
    
    
    try {
    
    
        def mergeResourcesTask = project.getTasks().getByName(String.format("process%sManifest", variantName))
        mergeResourcesTask.doLast {
    
    
            File mainManifestFile = new File(bundleManifestPath + "/AndroidManifest.xml")
            fixManifest(mainManifestFile)
        }
        def processResourcesTask = project.getTasks().getByName(String.format("process%sResources", variantName))
        processResourcesTask.doFirst {
    
    
            File mainManifestFile = new File(manifestPath + "/AndroidManifest.xml")
            fixManifest(mainManifestFile)
        }
    } catch (Exception e) {
    
    
    }
}

def fixManifest(File mainManifestFile) {
    
    
    try {
    
    
        def xml = new XmlParser(false, true).parse(mainManifestFile)
        def exportedTag = "android:exported"
        def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')

        def nodes = xml.application[0].'*'.findAll {
    
    
            (it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(androidSpace.exported) == null
        }
        nodes.each {
    
    
            def exportedValue = false
            it.each {
    
    
                if (it.name() == "intent-filter") {
    
    
                    it.each {
    
    
                        if (it.name() == "action") {
    
    
                            if (it.attributes().get(androidSpace.name) == "android.intent.action.MAIN") {
    
    
                                exportedValue = true
                            }
                        }
                    }
                }
            }
            it.attributes().put(exportedTag, "${exportedValue}")
        }

        PrintWriter pw = new PrintWriter(mainManifestFile)
        pw.write(groovy.xml.XmlUtil.serialize(xml))
        pw.close()

    } catch (Exception e) {
    
    
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40855673/article/details/128338961