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

unity

Unity versionGradle versionAndroid Gradle Plugin version
2023.17.3.37.2.1
2022.27.27.1.2
2022.1
2021.3
2021.2
2021.1 starting from 2021.1.16f1
2020.3 starting from 2020.3.15f1
6.1.14.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.44.0.1
2019.45.1.13.4.0

android:

插件版本所需的 Gradle 版本
1.0.0 - 1.1.32.2.1 - 2.3
1.2.0 - 1.3.12.2.1 - 2.9
1.5.02.2.1 - 2.13
2.0.0 - 2.1.22.10 - 2.13
2.1.3 - 2.2.32.14.1+
2.3.0+3.3+
3.0.0+4.1+
3.1.0+4.4+
3.2.0 - 3.2.14.6+
3.3.0 - 3.3.34.10.1+
3.4.0 - 3.4.35.1.1+
3.5.0 - 3.5.45.4.1+
3.6.0 - 3.6.45.6.4+
4.0.0+6.1.1+
4.1.0+6.5+
4.2.0+6.7.1+
7.07.0+
7.1 / 7.1.27.2+
7.27.3+
7.3 / 7.3.07.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 实验三个脚本写法,最后得出最有效的脚本

脚本一(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)
                }
            }

        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值