Gradle-动态移除清单文件中的权限

Gradle-动态移除清单文件中的权限

RT, 项目中有这样一个需求,需要将A项目中的界面添加到另一个项目B中,因为A项目中的界面需要用到某些权限,而B项目中也定义了这些权限,B项目中的权限受版本或其它关系,不能被A项目中的权限覆盖,所以希望在对A项目打aar包时,把aar包中的清单文件里的所有关于权限定义的部分删除掉,简单的说,就是这样:

image-20221101171356626

这边想了不少办法,有一种做法是将权限声明成“tools:remove”, 这是Google新支持的特性,但问题是如果将这些权限都声明成“tools:remove”,那A项目就用不了这些权限了,所以想了想还是从Gradle入手,翻了不少资料,终于解决了这个需求,这里通过自定义Gradle插件的方式来解决这个问题,具体步骤如下:

  1. 在当前项目的根目录下新建一个模块,命名为 buildSrc, 然后添加指定的文件:

    image-20221101172205197

    注意:这个module的名称必须为buildSrc.因为我们创建的这个module是AS专门用来写插件的,会自动参与编译.创建好之后删除Android那一堆东西,什么java代码,res,清单文件等.只剩下build.gradle.gitignore

    build.gradle文件内容改成:

    repositories {
        google()
        jcenter()
    }
    apply {
        plugin 'groovy'
        plugin 'java-gradle-plugin'
    }
    dependencies {
        implementation gradleApi()
        implementation localGroovy()
        implementation "commons-io:commons-io:2.6"
    }
    
  2. main 文件夹下面创建文件夹groovy, 然后使用Gradle sync一下.没啥问题的话,应该能编译过.然后在groovy文件夹下面创建包名com.test.xxx, 包名可以任意指定,然后创建一个空文件,名字叫 ManifestFormatPlugin.groovy

    package com.test.xxx
    
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    
    class ManifestFormatPlugin implements Plugin<Project> {
        @Override
        void apply(Project project) {
            project.afterEvaluate {
                // 1. Find the specified task
                def processManifestTask = project.tasks.findByName("processReleaseManifest")
                if (processManifestTask != null) {
                    // 2. Create a new Gradle task to remove permissions in the "AndroidManifest.xml"
                    def parseDebugTask = project.tasks.create("RemovePermissionTask", RemovePermissionTask.class)
    
                    // 3. Set to execute immediately after the specified task
                    processManifestTask.finalizedBy(parseDebugTask)
                } else {
                    println("can not found specified task [processReleaseManifest]")
                }
            }
        }
    }
    

    这里声明了一个插件,名字叫做:ManifestFormatPlugin, 它会在Gradle构建 processReleaseManifest 这个任务之后,自动执行我们新定义的Task: RemovePermissionTask,

    RemovePermissionTask 这个文件的内容如下:

    package com.test.xxx
    
    import groovy.xml.XmlSlurper
    import groovy.xml.slurpersupport.NodeChild;
    import org.gradle.api.DefaultTask;
    import org.gradle.api.tasks.TaskAction;
    
    class RemovePermissionTask extends DefaultTask {
    
        @TaskAction
        void doAction() {
            // 1. Find the merged manifest file
            def file = new File(project.buildDir, "/intermediates/merged_manifest/release/AndroidManifest.xml")
            if (!file.exists()) {
                println("can not found merged manifest file")
                return
            }
    
            // 2. Get the content of the manifest file
            def manifestContent = file.getText()
    
            println("prepare to remove all permissions in the merged Manifest...")
            removePermission(file, manifestContent)
        }
    
    
        /**
         * Remove all permissions defined in the manifest file
         * @param file The "AndroidManifest.xml" file
         * @param manifestContent Content of the "AndroidManifest.xml"
         */
        static void removePermission(File file, String manifestContent) {
            def manifestXML = new XmlSlurper(false, false).parseText(manifestContent)
            manifestXML.'*'.each { node ->
                if (node.name() == "uses-permission") {
                    node.replaceNode {}
                }
            }
    
            def serializeContent = groovy.xml.XmlUtil.serialize(manifestXML)
            file.write(serializeContent)
    
    //        // use XMLParser to parse the manifest file
    //        def manifestXML = new XmlParser().parseText(manifestContent)
    //        manifestXML.'**'.each { node ->
    //            if (node.name() == "uses-permission") {
    //                node.replaceNode {}
    //            }
    //        }
    //
    //        new XmlNodePrinter().print(manifestXML)
        }
    
    }
    
  3. 然后在你最终想要打aar包的模块上应用该插件,比如我想把项目的app模块打成一个aar包,那就在 app 模块的 build.gradle上方加入下列语句:

    import com.test.xxx.ManifestFormatPlugin
    apply plugin: ManifestFormatPlugin
    

    比如我的加完之后是这个样子:

    image-20221101173505479

  4. 对所在的模块进行aar打包,查看输出结果:

    image-20221101173636230

    可以看到清单文件中关于 权限声明的部分已经被顺利删除掉了。

参考链接

  1. Gradle系列(四) Gradle插件
  2. Gradle 插件练习-动态移除权限
  3. Android Gradle 插件开发入门指南
  4. StackOverFlow: How to dynamically edit Android Manifest ...
  5. Groovy: Get XML Tag first level
  6. 简书:1.5_任务依赖关系和排序
  7. 删除第三方AAR多请求的权限
posted @ 2022-11-01 17:43  夜行过客  阅读(440)  评论(0编辑  收藏  举报