Use custom Manifest file and permission in Unity?
Solution 1
You are modifying the wrong AndroidManifest
file. That AndroidManifest
from <ProjectName>\Temp\StagingArea
you are modifying is generated by unity each time you build your project.
To use a custom AndroidManifest
file, you have to put your custom AndroidManifest
file at <ProjectName>Assets\Plugins\Android
.
1.Go to <UnityInstallationDirecory>\Editor\Data\PlaybackEngines\AndroidPlayer\Apk
, Copy the AndroidManifest.xml
file to your <ProjectName>Assets\Plugins\Android
2.Open the copied Manifest file from <ProjectName>Assets\Plugins\Android
and add your manifest.
In your particular case, add <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">
to it. Save, Build and Run.
Unity will now use that AndroidManifest
file. If you get crash or any other problem, then Unity does not want you to change that.
Solution 2
Starting with Unity 2018 you should implement the IPostGenerateGradleAndroidProject
interface which will allow you to edit the android manifest after Unity produces it. In the code below I have added methods to set the microphone permission, set hardware acceleration, and set your application theme ( replace SetMicrophonePermission()
to your preferred method, which is called when Unity calls OnPostGenerateGradleAndroidProject()
).
Add the following code to 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);
}
}
genaray
Updated on October 21, 2020Comments
-
genaray over 3 years
Im currently trying to program a little game for android with Unity3D. Because I want a visible status bar, I modified the AndroidManifest in the Project Folder (C:\Users\Public\Documents\Unity Projects\ProjectName\Temp\StagingArea) like this :
<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">
But everytime i generate the APK, unity changes the Android Manifest to this :
<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 does change my modified Manifests everytime?
-
S. Tarık Çetin over 4 yearsI wrote a library that wraps around the code in this answer (in a limited manner): github.com/starikcetin/Eflatun.AndroidManifestHook
-
linojon about 4 yearsi meant my comment below to the main question to actually be a reply to this answer. Thanks for your code.
-
Mokhabadi over 3 yearsFor Step 1 you can simply check ProjectSettings>Player>PublishingSettings>CustomMainManifest