Logo wizaman's blog (legacy)

UnityでAndroidManifest.xmlを使う

November 13, 2016
10 min read
Table of Contents

前回の記事「AndroidのpersistentDataPathがカオス」の続きです。

UnityでAndroidManifest.xmlを利用する方法のメモです。

前回の記事からの続き

※この節は前回の記事からの誘導なので、UnityでのAndroidManifest.xml利用方法を知りたいだけの人は読み飛ばしてください。

「外部」のアプリ固有パスにしかアクセスしないならば、Android 4.4(KitKat)以降は権限が不要ですが、それより前のバージョンも対象にする場合には、互換性のために権限を持たせることになるという話でした。しかし、これは無駄なので、特定のバージョン以降でその権限を要求しないようにする設定項目が追加されました。

ただ、やはりというか、残念なことにUnity側でそれを指定する設定は存在しないんですね。なので、もう少しAndroid側に寄って、自分で直接設定を書くことにしましょう。そのための手段ならUnityも提供しています。

**Androidアプリの設定は、AndroidManifest.xmlというファイルにまとめられます。**Unityから直接Androidアプリをビルドするときも、プロジェクトのルート直下に一時的に作られるTemp/StagingAreaディレクトリに、自動生成されたAndroidManifest.xmlがあることが確認できます。これだけ見ると、Androidプロジェクトを吐き出させて、AndroidManifest.xmlを編集してから、自前でAndroidのビルドを行わなければいけないようにも思えますが、そこまで不便ではありません。

これから任意のAndroidManifest.xmlをUnityで利用するための方法を説明していきます。

やりたいこと

WRITE_EXTERNAL_STORAGE権限を、Android 4.3以前では要求し、4.4以降では要求しない、という設定を指定したいです。

uses-permissionタグが権限を与える設定ですが、これの属性としてandroid:maxSdkVersionを与えてやればいいです。指定する値は、その権限が有効な最大APIレベルです。

上記記事にも書いてある通り、uses-sdkタグにも同名の属性がありますが、まったく別物なので、調べ物するときには気をつけてください。

WRITE_EXTERNAL_STORAGEをAndroid 4.4(API Level 19)より前のバージョンでのみ要求したい場合、API Level 18を最大として設定すればいいので、下記の設定をAndroidManifest.xmlに書きたいわけです。

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />

独自AndroidManifest.xmlのマージ

Assets/Plugins/Androidディレクトリには、Androidでだけ有効なプラグインやリソースを置くことができます。ここにAndroidManifest.xmlを置くと、Unityが自動生成するAndroidManifest.xmlにマージしてくれます。

Unityが自動で書き出そうとした設定と独自設定が競合する場合は、**基本的には独自設定が採用されます。**一部例外があって、アプリのバージョンなどはUnityのPlayerSettingsが優先されますので、アプリのバージョンを上げるたびにAndroidManifest.xmlも更新しなければいけない、というような二重管理になることはありません。なかなかスマートでいいですね。

但し、設定の上書き追加はできても、削除はできないので、そこは注意ですね。例えば、今回、私がやりたいことで言えば、READ_EXTERNAL_STORAGE権限は不要なので、Write Access設定をInternal Onlyにしておくべきです。

独自AndroidManifest.xmlの配置

手順としては、一度、ビルド時に「Google Android Project」にチェックを入れてAndroidプロジェクトとして吐き出して、そこからUnityが自動生成したAndroidManifest.xmlを取ってくるのが正攻法だと思います。これを手元に残して参考にしつつ、**最低限必要な独自設定を記述したAndroidManifest.xmlをAssets/Plugins/Androidに置きましょう。**自分で書いた設定が基本的に優先されることを考えると、余計な設定は消すべきなのです。

ただ、私も正確な挙動がよくわからないので、つけたり消したりを繰り返してビルドし直し、元々の自動生成とほぼ同じ結果が得られるかを地道に確認しています。

一応、雛形っぽいものは、Windowsなら、Unityのインストールディレクトリ下の「Editor\Data\PlaybackEngines\AndroidPlayer\Apk」にも見つかるのですが、これがどのように利用されるか把握してないのと、他のプラットフォームだとどこに配置されてるか探すのに困りそうなのでアテにならないかな、と思ってます。

AndroidManifest.xmlの一例を下記に示します。

<?xml version="1.0" encoding="utf-8"?>
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android">
 
  <supports-screens
    android:smallScreens="true"
    android:normalScreens="true"
    android:largeScreens="true"
    android:xlargeScreens="true"
    android:anyDensity="true" />
 
  <application
    android:theme="@style/UnityThemeSelector"
    android:icon="@drawable/app_icon"
    android:label="@string/app_name">
 
    <activity
      android:label="@string/app_name"
      android:name="com.unity3d.player.UnityPlayerActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    </activity>
  </application>
 
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
 
</manifest>

Unityが自動生成したAndroidManifest.xmlからコピペしてくると、**何故か起動アクティビティが見つからないという旨のエラーによりアプリが起動しませんでした。**対応としては、activityタグのandroid:name属性で「com.unity3d.player.UnityPlayerActivity」を指定すれば動くことには気付いたので、上記サンプルではそのように修正しています。元々は「net.wizaman.Sandbox.UnityPlayerActivity」のように、そのプロジェクトのパッケージ名を使って指定されていたのですが、色々な例を参考に修正しました。

また、supports-screensタグも省略したら、最終出力に含まれなくなってしまった(自動生成されなくなった)ので、残しています。

どうも独自AndroidManifest.xmlを配置すると、単純にマージするだけでなく、他にも何らかの挙動が変わるようですね。この挙動をちゃんと説明できる人は教えてほしいです・・・。

ちなみに、Android 2.3以降であれば、UnityPlayerActivityの代わりにUnityPlayerNativeActivityを指定することもできます。

UnityPlayerNativeActivity は、UnityPlayerActivity のサブクラスではなく、入力の待ち時間が改善された新しい activity クラスです。ただし、Gingerbread ( Android 2.3 )以降の機能を利用しており、古いデバイスでは動作しません。またタッチ/モーションのイベントをネイティブコードで処理しており、Java ビューからは通常見ることはできません。ただし、DalvikVM メカニズムにイベントを転送しアクセスすることができます。

とのことです。入力レスポンスが改善されるなら、Javaビューでイベント処理が見えなくなることが都合悪くなければ、採用したほうが幸せになれる気がしないでもないですが、どうなんでしょう・・・?

公式ドキュメントでは、他にも、UnityPlayerActivityやUnityPlayerNativeActivityを継承したアクティビティを使用する方法についても簡単に触れられています。このように起動アクティビティの指定を自由にするため、独自AndroidManifest.xmlの有無で細かな挙動の違いが出ているのかな・・・?

ところで、UnityPlayerNativeActivityを継承するときには、meta-dataタグの追加が必要だと説明されていますね。これまでコピペでなんとなく使ってきた下記meta-dataの説明もどっかに欲しいです・・・。ブラックボックス過ぎるのも気持ち悪い・・・。

<meta-data android:name="unityplayer.UnityActivity" android:value="true" />

この辺の情報、少なすぎやしませんかね。