在 Unity 中使用自定义清单文件和权限?

Posted

技术标签:

【中文标题】在 Unity 中使用自定义清单文件和权限?【英文标题】:Use custom Manifest file and permission in Unity? 【发布时间】:2017-09-03 17:26:30 【问题描述】:

我目前正在尝试使用 Unity3D 为 android 编写一个小游戏。因为我想要一个可见的状态栏,所以我修改了项目文件夹 (C:\Users\Public\Documents\Unity Projects\ProjectName\Temp\StagingArea) 中的 AndroidManifest,如下所示:

<application android:theme="Theme.Light.NoTitleBar" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner">

但每次我生成 APK 时,unity 都会将 Android Manifest 更改为:

<application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner">

Unity3D 每次都会更改我修改后的清单吗?

【问题讨论】:

你修改的文件的目录是什么? @Programmer 它位于文档中的 Unity Projects 文件夹中的某个位置。我使用了搜索栏并对其进行了修改... 对不起。它不是那样工作的。再次找到它,然后找到目录。更新你的答案。 @Programmer 找到了正确的文件夹并更新了我的问题。 【参考方案1】:

您正在修改错误的AndroidManifest 文件。每次构建项目时,您正在修改的 &lt;ProjectName&gt;\Temp\StagingArea 中的 AndroidManifest 都是由统一生成的。

要使用自定义AndroidManifest 文件,您必须将自定义AndroidManifest 文件放在&lt;ProjectName&gt;Assets\Plugins\Android

1.转到&lt;UnityInstallationDirecory&gt;\Editor\Data\PlaybackEngines\AndroidPlayer\Apk,将AndroidManifest.xml文件复制到你的&lt;ProjectName&gt;Assets\Plugins\Android

2.打开从&lt;ProjectName&gt;Assets\Plugins\Android复制的Manifest文件并添加你的manifest。

在您的特定情况下,将&lt;application android:theme="Theme.Light.NoTitleBar" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="false" android:isGame="true" android:banner="@drawable/app_banner"&gt; 添加到它。保存、构建和运行。

Unity 现在将使用该AndroidManifest 文件。如果您遇到崩溃或任何其他问题,那么 Unity 不希望您更改它。

【讨论】:

对于第 1 步,您只需检查 ProjectSettings>Player>PublishingSettings>CustomMainManifest【参考方案2】:

从 Unity 2018 开始,您应该实现 IPostGenerateGradleAndroidProject interface,这将允许您在 Unity 生成 Android 清单后对其进行编辑。在下面的代码中,我添加了设置麦克风权限、设置硬件加速和设置应用程序主题的方法(将 SetMicrophonePermission() 替换为您的首选方法,当 Unity 调用 OnPostGenerateGradleAndroidProject() 时调用该方法)。

将以下代码添加到Assets/Editor/ModifyUnityAndroidAppManifestSample.cs

using System.IO;
using System.Text;
using System.Xml;
using UnityEditor.Android;

public class ModifyUnityAndroidAppManifestSample : IPostGenerateGradleAndroidProject


    public void OnPostGenerateGradleAndroidProject(string basePath)
    
        // If needed, add condition checks on whether you need to run the modification routine.
        // For example, specific configuration/app options enabled

        var androidManifest = new AndroidManifest(GetManifestPath(basePath));

        androidManifest.SetMicrophonePermission();

        // Add your XML manipulation routines

        androidManifest.Save();
    

    public int callbackOrder  get  return 1;  

    private string _manifestFilePath;

    private string GetManifestPath(string basePath)
    
        if (string.IsNullOrEmpty(_manifestFilePath))
        
            var pathBuilder = new StringBuilder(basePath);
            pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
            pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
            pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
            _manifestFilePath = pathBuilder.ToString();
        
        return _manifestFilePath;
    



internal class AndroidXmlDocument : XmlDocument

    private string m_Path;
    protected XmlNamespaceManager nsMgr;
    public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
    public AndroidXmlDocument(string path)
    
        m_Path = path;
        using (var reader = new XmlTextReader(m_Path))
        
            reader.Read();
            Load(reader);
        
        nsMgr = new XmlNamespaceManager(NameTable);
        nsMgr.AddNamespace("android", AndroidXmlNamespace);
    

    public string Save()
    
        return SaveAs(m_Path);
    

    public string SaveAs(string path)
    
        using (var writer = new XmlTextWriter(path, new UTF8Encoding(false)))
        
            writer.Formatting = Formatting.Indented;
            Save(writer);
        
        return path;
    



internal class AndroidManifest : AndroidXmlDocument

    private readonly XmlElement ApplicationElement;

    public AndroidManifest(string path) : base(path)
    
        ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
    

    private XmlAttribute CreateAndroidAttribute(string key, string value)
    
        XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
        attr.Value = value;
        return attr;
    

    internal XmlNode GetActivityWithLaunchIntent()
    
        return SelectSingleNode("/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and " +
                "intent-filter/category/@android:name='android.intent.category.LAUNCHER']", nsMgr);
    

    internal void SetApplicationTheme(string appTheme)
    
        ApplicationElement.Attributes.Append(CreateAndroidAttribute("theme", appTheme));
    

    internal void SetStartingActivityName(string activityName)
    
        GetActivityWithLaunchIntent().Attributes.Append(CreateAndroidAttribute("name", activityName));
    


    internal void SetHardwareAcceleration()
    
        GetActivityWithLaunchIntent().Attributes.Append(CreateAndroidAttribute("hardwareAccelerated", "true"));
    

    internal void SetMicrophonePermission()
    
        var manifest = SelectSingleNode("/manifest");
        XmlElement child = CreateElement("uses-permission");
        manifest.AppendChild(child);
        XmlAttribute newAttribute = CreateAndroidAttribute("name", "android.permission.RECORD_AUDIO");
        child.Attributes.Append(newAttribute);
    

【讨论】:

我写了一个库,在这个答案中包含了代码(以有限的方式):github.com/starikcetin/Eflatun.AndroidManifestHook 我的意思是我在下面对主要问题的评论实际上是对这个答案的回复。感谢您的代码。【参考方案3】:

对于 Unity 运行时权限,我编写了这个函数来添加跳过权限对话框(如 https://docs.unity3d.com/Manual/android-manifest.html

例如

<manifest>
    <application>
        <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />

代码如下:

internal void SetSkipPermissionsDialog()

    var manifest = SelectSingleNode("/manifest");
    var application = manifest.SelectSingleNode("application");
    XmlElement child = CreateElement("meta-data");
    application.AppendChild(child);
    XmlAttribute newAttribute = CreateAndroidAttribute("name", "unityplayer.SkipPermissionsDialog");
    child.Attributes.Append(newAttribute);
    newAttribute = CreateAndroidAttribute("value", "true");
    child.Attributes.Append(newAttribute);

【讨论】:

【参考方案4】:

要使用自定义 AndroidManifest 文件, 您必须将自定义 AndroidManifest 文件放在&lt;ProjectName&gt;Assets\Plugins\Android

【讨论】:

以上是关于在 Unity 中使用自定义清单文件和权限?的主要内容,如果未能解决你的问题,请参考以下文章

Android清单文件具体解释 ---- 应用程序权限声明

请求清单文件中声明的所有权限

构建 Android 项目时在 Unity3D 中合并清单文件问题

是否可以创建一个包含项目类和项目依赖项的“uber”jar 作为带有自定义清单文件的 jar?

我可以在清单(对于 api < 27)和运行时(对于 API 27+)中注册自定义意图吗?

应用程序的自定义权限