Unity gradle 动态修改android:launchMode 问题记录

unity

Unity version Gradle version Android Gradle Plugin version
2023.1 7.3.3 7.2.1
2022.2 7.2 7.1.2
2022.1
2021.3
2021.2
2021.1 starting from 2021.1.16f1
2020.3 starting from 2020.3.15f1
6.1.1 4.0.1
2021.1 up to and including 2021.1.15f1
2020.1, 2020.2, 2020.3 up to and including 2020.3.14f1
5.6.4 4.0.1
2019.4 5.1.1 3.4.0

android:

插件版本 所需的 Gradle 版本
1.0.0 - 1.1.3 2.2.1 - 2.3
1.2.0 - 1.3.1 2.2.1 - 2.9
1.5.0 2.2.1 - 2.13
2.0.0 - 2.1.2 2.10 - 2.13
2.1.3 - 2.2.3 2.14.1+
2.3.0+ 3.3+
3.0.0+ 4.1+
3.1.0+ 4.4+
3.2.0 - 3.2.1 4.6+
3.3.0 - 3.3.3 4.10.1+
3.4.0 - 3.4.3 5.1.1+
3.5.0 - 3.5.4 5.4.1+
3.6.0 - 3.6.4 5.6.4+
4.0.0+ 6.1.1+
4.1.0+ 6.5+
4.2.0+ 6.7.1+
7.0 7.0+
7.1 / 7.1.2 7.2+
7.2 7.3+
7.3 / 7.3.0 7.4+

网上找的版本:

android.applicationVariants.all { variant ->
    variant.outputs.all { output ->
        def processResources = output.hasProperty("processResourcesProvider") ?
                output.processResourcesProvider.get() : output.processResources
        processResources.doFirst { pm ->
            String manifestPath = processResources.manifestFile
            println "=====change manifestPath=====$manifestPath"
            def manifestContent = file(manifestPath).getText()

            def android = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
            def xml = new XmlParser().parseText(manifestContent)
            def mainActivity = xml.application[0].activity.findAll() { ac ->
                def action = ac.depthFirst().findAll() { node ->
                    return node.attribute(android.name) == 'android.intent.action.MAIN'
                }
                return action.size() > 0;
            }
            println "=====found main activity=====${mainActivity.size()} $mainActivity"
            mainActivity[0].attributes().put(android.launchMode, 'singleTop')

            def serialize = groovy.xml.XmlUtil.serialize(xml)
            file(manifestPath).write(serialize)
        }
    }
}

支持apk 跟AAB 的版本,摘自android:LaunchMode. Why does Unity have it as singleTask? - Unity Forum

// Override LibraryManifest.xml values and switch launchMode to standard
android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def processManifest = output.getProcessManifestProvider().get()
        processManifest.doLast { task ->
            def outputDir = task.getManifestOutputDirectory()
            File outputDirectory
            if (outputDir instanceof File) {
                outputDirectory = outputDir
            } else {
                outputDirectory = outputDir.get().asFile
            }
   
            File manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
 
            if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
                def newManifest = manifestOutFile.getText().replace("android:launchMode=\"singleTask\"", "android:launchMode=\"standard\"")
                manifestOutFile.write(newManifest, 'UTF-8')
            }
   
            // Make sure to modify bundle_manifest as well
            outputDir = task.getBundleManifestOutputDirectory();
   
            if (outputDir instanceof File) {
                outputDirectory = outputDir
            } else {
                outputDirectory = outputDir.get().asFile
            }
                   
            manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
 
            if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
                def bundleManifest = manifestOutFile.getText().replace("android:launchMode=\"singleTask\"", "android:launchMode=\"standard\"")
                manifestOutFile.write(bundleManifest, 'UTF-8')
            }
        }
    }
}

本人优化版本如下(仅支持 unity2022.2 以前):

// Override LibraryManifest.xml values and switch launchMode to singleTop
android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def processManifest = output.getProcessManifestProvider().get()
        processManifest.doLast { task ->
            def outputDir = task.getManifestOutputDirectory()
            println "=====change manifestPath==A===$outputDir"
            File outputDirectory
            if (outputDir instanceof File) {
                outputDirectory = outputDir
            } else {
                outputDirectory = outputDir.get().asFile
            }
   
            File manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
            println "=====change manifestPath==B===$outputDirectory"
            if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
       /*          def newManifest = manifestOutFile.getText().replace("android:launchMode=\"singleTask\"", "android:launchMode=\"standard\"")
                manifestOutFile.write(newManifest, 'UTF-8') */
                 def manifestContent = file(manifestOutFile).getText()
                def android = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
                def xml = new XmlParser().parseText(manifestContent)
                def mainActivity = xml.application[0].activity.findAll() { ac ->
                    def action = ac.depthFirst().findAll() { node ->
                        return node.attribute(android.name) == 'android.intent.action.MAIN'
                    }
                    return action.size() > 0;
                }
                println "=====found main activity=====${mainActivity.size()} $mainActivity"
                mainActivity[0].attributes().put(android.launchMode, 'singleTop')
    
                def serialize = groovy.xml.XmlUtil.serialize(xml)
                file(manifestOutFile).write(serialize)
            }
   
            // Make sure to modify bundle_manifest as well
            outputDir = task.getBundleManifestOutputDirectory();
   
            if (outputDir instanceof File) {
                outputDirectory = outputDir
            } else {
                outputDirectory = outputDir.get().asFile
            }
          println "=====change manifestPath==C===$outputDirectory"  
            manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
             
            if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
      /*           def bundleManifest = manifestOutFile.getText().replace("android:launchMode=\"singleTask\"", "android:launchMode=\"standard\"")
                manifestOutFile.write(bundleManifest, 'UTF-8') */
                 def manifestContent = file(manifestOutFile).getText()
                def android = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
                def xml = new XmlParser().parseText(manifestContent)
                def mainActivity = xml.application[0].activity.findAll() { ac ->
                    def action = ac.depthFirst().findAll() { node ->
                        return node.attribute(android.name) == 'android.intent.action.MAIN'
                    }
                    return action.size() > 0;
                }
                println "=====found main activity=====${mainActivity.size()} $mainActivity"
                mainActivity[0].attributes().put(android.launchMode, 'singleTop')
    
                def serialize = groovy.xml.XmlUtil.serialize(xml)
                file(manifestOutFile).write(serialize)
            }
        }
    }
}

后续:

参考链接:

Android 12 自动适配 exported 深入解析避坑_沙滩捡贝壳的小孩的博客-CSDN博客

Android 12 自动适配 exported 深入解析避坑 - 专栏 - 声网 RTE 开发者社区

以上脚本在unity 2022.2 不再生效,参考以上链接,编写不同脚本组合,经在 android studio(plugs 7.4.1)实验及unity2022 实验三个脚本写法,最后得出最有效的脚本

扫描二维码关注公众号,回复: 14875278 查看本文章

脚本一(unity 有效,android studio 无效)

android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            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
            }
            ///你的自定义名字
            project.getTasks().getByName(taskName).doFirst {
                it.getManifests().getFiles().each {
                    if (it.exists() && it.canRead() && it.canWrite()) {
                        def manifestFile = it
                        ///这里第二个参数是 false ,所以 namespace 是展开的,所以下面不能用 androidSpace,而是用 nameTag
                        def xml = new XmlParser(false, false).parse(manifestFile)
                        if (xml.application != null && xml.application.size() > 0) {
                            def mainActivity = xml.application[0].activity.findAll { ac ->
                                def action = ac.depthFirst().findAll() { node ->
                                    if(node != null){
                                        return node.attributes().get("android:name") == 'android.intent.action.MAIN'
                                    }
                                }

                                return action.size() > 0;
                            }
                            println "=====found main1 activity=====${mainActivity.size()} $mainActivity"
                            if(mainActivity[0]!=null){
                                mainActivity[0].attributes().put("android:launchMode", 'singleTop')
                            }
                            //mainActivity[0].attributes().put(android.launchMode, 'singleTop')
                            println "=====found main2 activity=====${mainActivity.size()} $mainActivity"
                            def serialize = groovy.xml.XmlUtil.serialize(xml)
                            file(it).write(serialize)
                        }
                    }
                }
            }
        }
    }

脚本二(android studio 及UNITY  均无效)

android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.processResources.doLast {
                String manifestPath = output.processResources.manifestFile
                println "=====found manifestPath activity=====${manifestPath}"
                def manifestOutFile = new File(manifestPath)
                if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
                    ///这里第二个参数是 false ,所以 namespace 是展开的,所以下面不能用 androidSpace,而是用 nameTag
                    def xml = new XmlParser(false, false).parse(manifestOutFile)
                    def nameTag = "android:name"
                    println "=====found xml activity=====${xml}"
                    if (xml.application != null && xml.application.size() > 0) {
                        def mainActivity = xml.application[0].activity.findAll { ac ->
                            def action = ac.depthFirst().findAll() { node ->
                                if (node != null) {
                                    return node.attributes().get(nameTag) == 'android.intent.action.MAIN'
                                }
                            }

                            return action.size() > 0;
                        }
                        println "=====found main1 activity=====${mainActivity.size()} $mainActivity"
                        if (mainActivity[0] != null) {
                            mainActivity[0].attributes().put("android:launchMode", 'singleTop')
                        }
                        //mainActivity[0].attributes().put(android.launchMode, 'singleTop')
                        println "=====found main2 activity=====${mainActivity.size()} $mainActivity"
                        def serialize = groovy.xml.XmlUtil.serialize(xml)
                        file(manifestOutFile).write(serialize)
                    }
                }
            }
        }
    }

脚本三(android stuido unity 均有效)

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def processManifest = output.getProcessManifestProvider().get()
        println("=============== processManifest ${processManifest} ===============")
        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()) {
                ///这里第二个参数是 false ,所以 namespace 是展开的,所以下面不能用 androidSpace,而是用 nameTag
                def xml = new XmlParser(false, false).parse(manifestOutFile)
                println "=====found xml activity=====${xml}"
                if (xml.application != null && xml.application.size() > 0) {
                    def mainActivity = xml.application[0].activity.findAll { ac ->
                        def action = ac.depthFirst().findAll() { node ->
                            if (node != null) {
                                return node.attributes().get('android:name') == 'android.intent.action.MAIN'
                            }
                        }

                        return action.size() > 0;
                    }
                    println "=====found main1 activity=====${mainActivity.size()} $mainActivity"
                    if (mainActivity[0] != null) {
                        mainActivity[0].attributes().put('android:launchMode', 'singleTop')
                    }
                    println "=====found main2 activity=====${mainActivity.size()} $mainActivity"
                    def serialize = groovy.xml.XmlUtil.serialize(xml)
                    file(manifestOutFile).write(serialize)
                }
            }

        }
    }
}

猜你喜欢

转载自blog.csdn.net/daweibalang717/article/details/125936568