私は現在、Androidの小さなゲームをプログラミングしようとしています。ステータスバーを表示したいので、プロジェクトフォルダー(C:\ Users\Public\Documents\Unity ProjectsのAndroidManifestを変更しました\ ProjectName\Temp\StagingArea)は次のようになります。
<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を生成するたびに、団結は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は変更されたマニフェストを毎回変更しますか?
間違ったAndroidManifest
ファイルを変更しています。変更する<ProjectName>\Temp\StagingArea
からのAndroidManifest
は、プロジェクトをビルドするたびにUnityによって生成されます。
カスタムAndroidManifest
ファイルを使用するには、カスタムAndroidManifest
ファイルを<ProjectName>Assets\Plugins\Android
に配置する必要があります。
1. <UnityInstallationDirecory>\Editor\Data\PlaybackEngines\AndroidPlayer\Apk
に移動し、AndroidManifest.xml
ファイルを<ProjectName>Assets\Plugins\Android
にコピーします
2 .<ProjectName>Assets\Plugins\Android
からコピーしたマニフェストファイルを開き、マニフェストを追加します。
特定のケースでは、<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">
を追加します。保存、ビルド、実行。
UnityはそのAndroidManifest
ファイルを使用します。クラッシュやその他の問題が発生した場合、Unityはそれを変更することを望んでいません。
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);
}
}
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);
}