LoginSignup
4

More than 3 years have passed since last update.

【Unity】ハードウェアアクセラレーションが有効にならない、AndroidManifestを書き換えても無効になってしまう問題の解決

Last updated at Posted at 2019-04-18

問題の概要

AndroidManifestで有効にしたHardware accelerationが反映されない問題。
AndroidManifestでHardware accelerationのactivityをtrueにしても反映されない。

あまり日本語の記事が無かったので投稿。

予備知識

https://developer.android.com/guide/topics/graphics/hardware-accel
https://usedoor.jp/howto/web/code/android-dev-webview-scroll-kousokuka-hardwareaccelerated/
https://www.teradas.net/archives/12229/

Hardware accelerationがOFFになっているとHTML5のビデオ再生が使えなくなったり、WebViewのスクロールが重くなってガクガクになる。
ただこれをONにすることによってGPUレンダリングされることになるので、パフォーマンスが落ちたりするケースがある。(電池消費が激しくなったり)

問題の原因

Unity2018から?強制的に、Hardware accelerationがfalseに書き換わっているとのこと。
Unityの中の人がパフォーマンスが低下してしまうため、強制的に無効化するようにしたらしい。 (えぇ....)

そのことについてのフォーラムページ
https://forum.unity.com/threads/android-hardwareaccelerated-is-forced-false-in-all-activities.532786/?gq=NativeActivity

どのように解決したか

If you are absolutely sure you need the hardware acceleration, you can to the following:
- Extract your native UI into a separate activity and enable hardware acceleration there (preferred way)
- Modify the Unity manifest, for examply by utilizing IPostGenerateGradleAndroidProject interface (sample here: https://github.com/Over17/UnityAndroidManifestCallback)
※フォーラムから抜粋

Gradleビルドするときに呼ばれるインターフェース(IPostGenerateGradleAndroidProject)を実装して、そのコールバックにアクセラレーションを有効にするManifestを書き換えればOK。このインターフェースはAndroidManifestをUnityが強制的に書き換えた後に呼ばれるので、書き換えが可能になる。
BuildSystemが「Internal」だったら「Gradle」にすること。

このインターフェースを実装しているsampleがgithubにあるので、参考にしました。
GitHub - Over17/UnityAndroidManifestCallback: Apply your changes to Android Manifest in Unity 2018.1+ without having to override the main manifest of the whole project

以下のスクリプトをAssets/Editor/に入れる。

ModifyUnityAndroidAppManifest.cs
public class ModifyUnityAndroidAppManifest : IPostGenerateGradleAndroidProject
{
    public readonly string ActivityName = "com.hoge.ui.UiActivity";
    public readonly string ThemeName = "@style/FloatingActivityTheme";

    public void OnPostGenerateGradleAndroidProject(string basePath)
    {
        var androidManifest = new AndroidManifest(GetManifestPath(basePath));

        Debug.LogFormat("**************OnPostGenerateGradleAndroidProject BasePath={0}, ManifestPath={1}**************", basePath, GetManifestPath(basePath));
        // 必要であれば
        //androidManifest.SetApplicationTheme(ThemeName);
        //androidManifest.SetStartingActivityName(ActivityName);

        // manifestを書き換えるハードウェアアクセラレーションを有効にする
        androidManifest.SetHardwareAccel(); 
        // Add your XML manipulation routines

        androidManifest.Save();
        Debug.LogFormat("**************OnPostGenerateGradleAndroidProject Done!**************");
    }

    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 SetHardwareAccel()
    {
        GetActivityWithLaunchIntent().Attributes.Append(CreateAndroidAttribute("hardwareAccelerated", "true"));
    }
}

備考

  • VoxelBustersの中の人が上記のフォーラムページにて「いいね!良い情報をもらったので、修正できるよ!!」と言っているが今現在実装してなさそう。(2019/4/18)
  • IPostGenerateGradleAndroidProject は2018.3からしか使えないらしい。 これ以外のバージョンはアップデートをするかパッケージを用意してAndroidプロジェクトにエクスポートしないといけない(面倒くさい)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4