Unity 打包前,通过代码对 AndroidManifest 增删改查

为了实现不同Android渠道,采用不同的 AndroidManifest 配置。

需要在Unity打包前,通过代码自动修改 AndroidManifest.xml 文件的内容,实现自动化一键生成,减少了生成 android studio 工程后再修改的麻烦。

首先,Unity 提供了打包前和打包后调用的接口(interface)

IPreprocessBuildWithReport.OnPreprocessBuild
​
IPostprocessBuildWithReport.OnPostprocessBuild

其次,C# 提供了修改 XML 文件的库 System.Xml

方便了我们对 AndroidManifest.xml 文件进行增删改查

最后,为了实现灵活配置,采用了 Json 文件作为配置文件

独立的 Json 文件便于管理,保存在工程特定目录。

我这里使用的为 Newtonsoft.Json 库,小巧

实现的代码如下,如有疑问,欢迎留言!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using System.IO;
using System.Xml;
using Newtonsoft.Json;

/// <summary>
/// created by lymancao @ 2023.08.23
/// 说明:
///     为了针对不同Android渠道,进行 AndroidManifest 文件的不同配置,特意实现此功能。
///     利用 Unity 提供的打包前调用接口,C#的XML库
///     引入 Newtonsoft.Json 库 处理Json格式的配置文件
///     实现了打包前自动根据渠道修改android清单文件的功能。
/// </summary>
public class CustomBuildProcesser : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
    // 调用顺序,数值越小,调用越早
    public int callbackOrder
    {
        get { return 0; }
    }

    public const string AndroidManifest_Config_Google = "Assets/Config/Android/google.json";
    public const string AndroidManifest_Config_Amazon = "Assets/Config/Android/amazon.json";

    // build 开始时
    public void OnPreprocessBuild(BuildReport report)
    {
        //throw new System.NotImplementedException();
        if (report.summary.platform == BuildTarget.Android)
        {
            // 读取配置,一定要保证配置的正确性
            string configPath;
            if (PackageTool.targetPlatform == TargetPlatform.GooglePlay)
                configPath = AndroidManifest_Config_Google;
            else if (PackageTool.targetPlatform == TargetPlatform.Amazon)
                configPath = AndroidManifest_Config_Amazon;
            else
                return;

            OnPreprocessBuildForAndroid(report, configPath);
        }
    }

    // build 完成时
    public void OnPostprocessBuild(BuildReport report)
    {
        if (report.summary.platform == BuildTarget.Android)
        {
            OnPostprocessBuildForAndroid(report);
        }
    }
    /// <summary>
    /// 在生成android apk前,将一些配置写入AndroidManifest.xml
    /// </summary>
    /// <param name="report"></param>
    public static void OnPreprocessBuildForAndroid(BuildReport report, string configPath)
    {
        Debug.Log("========== ========== OnPreprocessBuildForAndroid Start ========== ==========");

        // 判断 Json 配置文件是否存在
        if (!File.Exists(configPath))
        {
            Debug.LogError("OnPostprocessBuildForAndroid Error: " + configPath + " doesn't exist.");
            return;
        }
        string jsonContent = File.ReadAllText(configPath);
        // 将 json 解析为一个字典
        Dictionary<string, string> jsonDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonContent);
        // 将 json 映射到一个类 
        //AndroidManifestConfig config = JsonConvert.DeserializeObject<AndroidManifestConfig>(configContent);

        ModifyAndroidManifest();

        AssetDatabase.Refresh();

        Debug.Log("========== ========== OnPreprocessBuildForAndroid Done ========== ==========");
    }

    public static void ModifyAndroidManifest()
    {
		// 读取xml
		string xmlPath = Application.dataPath + "/Plugins/Android/AndroidManifest.xml";
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlPath);

        // 包名
        XmlNode rootNode = xmlDoc.SelectSingleNode("/manifest");
        Debug.Log("package name = " + rootNode.Attributes["package"].Value);
        // 修改
        //rootNode.Attributes["package"].Value = jsonDict["app_package_name"].ToString();

        // 遍历所有权限
        XmlNodeList nodeList = rootNode.SelectNodes("/manifest/uses-permission");
        for (int i = 0; i < nodeList.Count; i++)
        {
            Debug.Log(" <" + nodeList[i].Name + " " + nodeList[i].LocalName + " " + nodeList[i].Attributes["android:name"].Value + ">");
			// 删除特定权限
			if (nodeList[i].Attributes["android:name"].Value == "android.permission.TEST")
			{
				Debug.Log("Remove Node " + nodeList[i].Name + " " + nodeList[i].Attributes["android:name"].Value);
				rootNode.RemoveChild(nodeList[i]);
			}
		}

        // 添加
        XmlNode newNode = xmlDoc.CreateElement("uses-permission");
        string ns = rootNode.GetNamespaceOfPrefix("android");
        XmlAttribute newAttr = newNode.Attributes.Append(xmlDoc.CreateAttribute("name", ns));
        newAttr.Value = "android.permission.TEST";
        Debug.Log("Append Node " + newNode.Name + " " + newAttr.Name + " in "+ns);
        rootNode.AppendChild(newNode);

        // 获取指定位置节点
        XmlNode node = FindNode(xmlDoc, "/manifest/application/activity/intent-filter/data", "android:scheme", "com.funtriolimited.slots.casino.free");
        if (node != null)
        {
            Debug.Log("android:scheme = "+ node.Attributes["android:scheme"].Value);
            // 修改
            //node.Attributes["android:scheme"].Value = jsonDict["url_schemes_name"].ToString();
        }

        // 保存
        xmlDoc.Save(xmlPath);
    }
    /// <summary>
    /// 在生成android apk后,将一些配置写入AndroidManifest.xml
    /// </summary>
    /// <param name="report"></param>
    static void OnPostprocessBuildForAndroid(BuildReport report)
    {
        Debug.Log("OnPostprocessBuildForAndroid Start");

        // TODO

        Debug.Log("OnPostprocessBuildForAndroid Done");
    }

    static XmlNode FindNode(XmlDocument xmlDoc, string xpath, string attributeName, string attributeValue)
    {
        XmlNodeList nodes = xmlDoc.SelectNodes(xpath);
        for (int i = 0; i < nodes.Count; i++)
        {
            XmlNode node = nodes.Item(i);
            string _attributeValue = node.Attributes[attributeName].Value;
            if (_attributeValue == attributeValue)
            {
                return node;
            }
        }
        return null;
    }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值