- 2020/03/27 【Unity】【Android】マルチウィンドウを禁止する
- 2018/07/15 【Android】【Java】パーミッションの付与(許可)のチェックと要求をする
« prev next »
【Unity】【Android】マルチウィンドウを禁止する 
2020/03/27 Fri [edit]
Android 7.0 以降からは画面を分割してアプリを起動できるマルチウィンドウがサポートされているが、Unity で作っている場合、絶対座標で配置されているものは「分割画面←→フルスクリーン画面」に変更したりすると、レイアウトがおかしくなってしまうことがある。もちろん自動でレイアウトを再計算するように作られていれば問題ないのだが、ゲーム画面などで縦または横の長さ固定で考えられている場合、画面分割で正方形に近くなってしまうので、全てのオブジェクトが中央に寄ってしまう、なんてこともある。そして困ったことに、マルチウィンドウのサポートは Android 7.0 以降、デフォルト状態でオンなのである。
・マルチウィンドウのサポート
なのでいっそのことマルチウィンドウを禁止した方が早い場合も多い(可変レイアウトを考えるのには結構手間がかかる)。まぁ、Android 開発に詳しい人ならググればすぐにわかると思うが、Unity のみで開発している人にとってはわかりずらい部分であり、「なぜかたまにレイアウトが崩れる」なんて困っている人もいるかもと思ったので、とりあえず記事にしておくことにした。
(※) Unity 2019.2.21f1 / Android 8.0 で確認
■AndroidManifest.xml でマルチウィンドウを禁止設定する
マルチウィンドウのサポートを設定する AndroidManifest.xml のタグは application または activity タグである(アプリ全体なら application タグ、アクティビティごとなら activity タグだが、Unity の場合、複数アクティビティを使うことは少ないので、機械的に application タグでも良い)。
Unity の場合、「Assets/Plugins/Android/」フォルダ以下に AndroidManifest.xml が置かれるので、それを適当なテキストエディタで開き、application または activity タグを見つけて、「android:resizeableActivity="false"」(禁止) を入れておく(許可にしたいなら true)。
・application タグ
・activity タグ
・アクティビティ

もし、プラグインなど全く使ってないのなら、デフォルトでは AndroidManifest.xml は用意されていないので、フォルダを含めて自分で作る必要がある。テンプレは Windows の場合「(インストールした Unity のフォルダ)\Editor\Data\PlaybackEngines\AndroidPlayer\src\com\unity3d\player」にあり、Mac の場合「(アプリケーションフォルダ)/Unity.app/Contents/PlaybackEngines/AndroidPlayer/src/com/unity3d/player 」にあるので、コピーして手を加えれば良いだろう。詳細は公式マニュアルを参照して欲しい。
・Android 用のプラグインをビルド
ここでは簡略した例を書いておこう。
●AndroidManifest.xml に resizeableActivity="false" を入れ、マルチウィンドウを禁止する
<?xml version="1.0" encoding="utf-8"?>
<manifest ~(中略)~
<application ~(中略)~ android:resizeableActivity="false">
~(中略)~
</application>
</manifest>
あとは Android ビルドをして、実機で試していると良い。
簡単な手順としては、例えば Google Chrome を起動し、メニューボタンを長押し→画面が分割されるので、空白の方のウィンドウをタップして、マルチウィンドウを禁止したアプリを立ち上げてみる、なんて感じでできるだろう。
上手くいったなら「マルチウィンドウ表示では、このアプリを使用できません」等のトースト(メッセージ)が出る。確認してみよう。


(関連記事)
【Unity】【Android】自動バックアップの対象/除外設定をする
【Unity】Android アプリでパーミッション(権限)要求をする
【Unity】【C#】プロジェクト内で Android(Java)プラグインをビルドする
【Unity】標準以外のセンサー(歩数計や心拍数など)を使う(Android)
【Unity】Androidで音声認識を使う
【Unity】Firebase のプッシュ通知と FantomPlugin の共存(Firebase と他のプラグインの共存方法)
【Unity】Unity2019.3 で Android / iOS ネイティブの構成が変わるらしい
- 関連記事
category: Unity
thread: ゲーム開発
janre: コンピュータ
tag: Unityトラブルシューティング Unityプラグイン Androidリファレンス【Android】【Java】パーミッションの付与(許可)のチェックと要求をする 
2018/07/15 Sun [edit]
Android 6.0 以降からは実行時のパーミッションリクエストができるが、ググったら「ContextCompat」(または「ActivityCompat」)での例がほとんどだったので、敢えて「~Compat」を使わない実装を書いておこうと思った。実際に「~Compat」はサポートライブラリが必要となるので、使えない環境で書きたい場合もあるだろう。もちろん Android6.0(API 23)以降になってしまうが、私も Unity のプラグインでは今回の方法を用いている(サポートライブラリ等、他のライブラリを入れるとファイルサイズも大きくなるため、ほぼ全ての実装を自前でやっている)。
なので「~Compat」で書きたい場合は、公式のデベロッパーマニュアルに載っているので、そちらの方を見れば良いだろう(基本的には同じ内容である)。
(参考)
・実行時のパーミッション リクエスト
(※) Android Studio 3.1.2 / Galaxy S7 Edge (Android 7.0) / Windows10(x64) で確認
■パーミッションの許可/拒否をチェックする(static メソッド)
ここでは汎用的に使えるように、static で定義したものを書いておこう。ライブラリとして保存しておけば使い回しも簡単にできる。
●パーミッションの許可/拒否をチェックする(static メソッド)
import android.content.Context;
import android.content.pm.PackageManager;
//パーミッションの許可(付与)チェック
public static final boolean checkPermission(final Context context, final String permission) {
final PackageManager pm = context.getPackageManager();
return (pm.checkPermission(permission, context.getPackageName()) == PackageManager.PERMISSION_GRANTED);
}
●使用例(メインでのコードなど)
import android.util.Log;
//※アクティビティでの使用例
boolean granted = checkPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE"); //this は Context
Log.d("DebugTag", "granted = " + granted);
ここでの結果はパーミッションが許可(付与)されてない状態として false が返ってきているが、元々許可されている場合は true になる。ちなみに「READ_EXTERNAL_STORAGE」(ストレージのファイル読み取り権限)というものもあるが、これは「WRITE_EXTERNAL_STORAGE」(ストレージのファイル読み書き権限)が許可されていれば、true になる。
また「AndroidManifedt.xml」での書き方は、基本的に <manifest>~</manifest> タグの中に書く。以下に例を挙げておこう。
●AndroidManifedt.xml に「WRITE_EXTERNAL_STORAGE」パーミッションを書く例
<manifest ~・・・(略)・・・ >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
・・・(略)・・・
</manifest>
パーミッション自体の文字列定数は公式のデベロッパーマニュアルを見て欲しい。
(参考)
・Manifest.permission (Constant Value を使う)
・<uses-permission> (name 属性だけでも良い)
■パーミッションのチェックとその理由→要求をする(インスタンス メソッド)
次にリアルタイムにパーミッションをチェックし、必要なら(許可されてなければ)そのパーミッションが必要な理由と要求ダイアログを出す方法をやってみよう。またここでは前述した static な checkPermission() を使っても良いが、単一のアクティビティ上での実装として、インスタンスメソッドで書くことにしよう。実際には static で書いても構わない(ちなみに Unity のプラグインは static で書いてある)。
●パーミッションのチェックとその理由→要求をする(※アクティビティでの実装例)
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.widget.Toast;
//定数など
//https://developer.android.com/reference/android/Manifest.permission.html
private static final String PERMISSION_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE"; //ストレージの読み書き権限
private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 1; //※番号は任意:onRequestPermissionsResult() で合わせる
//パーミッションの許可(付与)チェック
//https://developer.android.com/training/permissions/requesting#perm-check
private boolean checkPermission(String permission) {
final PackageManager pm = getPackageManager();
return pm.checkPermission(permission, getPackageName()) == PackageManager.PERMISSION_GRANTED;
}
//パーミッションの根拠と要求(API 23 [Android 6.0])
//https://developer.android.com/training/permissions/requesting#make-the-request
private void showPermissionRationaleAndRequest(final String permission, final int requestCode) {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android 6.0
//パーミッション要求の根拠の説明を必要とするか?「今後表示しない」をチェックすると常に false になる。
boolean isShouldRationale = shouldShowRequestPermissionRationale(permission); //API 23 (Android 6.0)
if (isShouldRationale) {
//根拠の説明ダイアログを必要とするとき
AlertDialog.Builder builder = new AlertDialog.Builder(this); //this は Context //※この実装では画面回転で消えるので注意
builder.setTitle("以下の理由で○○の権限が必要です。")
.setMessage("・説明1\n・説明2\n・説明3")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermission(permission, requestCode);
}
})
.show();
} else {
//根拠の説明ダイアログ不要のとき
requestPermission(permission, requestCode);
}
}
}
//パーミッションを要求する(API 23 [Android 6.0])
private void requestPermission(String permission, int requestCode) {
if (android.os.Build.VERSION.SDK_INT >= 23) { //Android 6.0
requestPermissions(new String[]{ permission }, requestCode);
}
}
//パーミッション要求の結果コールバックハンドラ(API 23 [Android 6.0])
//https://developer.android.com/training/permissions/requesting#handle-response
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "ユーザーによってストレージ読み書き権限が許可されました。", Toast.LENGTH_SHORT).show(); //this は Context
} else {
Toast.makeText(this, "ユーザーによってストレージ読み書き権限が拒否されました。", Toast.LENGTH_SHORT).show(); //this は Context
}
return;
}
}
}
●使用例(メインでのコードなど)
import android.util.Log;
//※アクティビティでの使用例
boolean isGranted = checkPermission(PERMISSION_WRITE_EXTERNAL_STORAGE); //現在のパーミッションをチェック
Log.d("DebugTag", PERMISSION_WRITE_EXTERNAL_STORAGE + "\nisGranted = " + isGranted);
if (!granted) {
//パーミッションが付与されてないとき、根拠の説明と要求をする(ダイアログを出す)
Log.d("DebugTag", PERMISSION_WRITE_EXTERNAL_STORAGE + ", requestCode = " + REQUEST_WRITE_EXTERNAL_STORAGE);
showPermissionRationaleAndRequest(PERMISSION_WRITE_EXTERNAL_STORAGE, REQUEST_WRITE_EXTERNAL_STORAGE); //API 23 (Android 6.0)
}
![]() | ![]() |
![]() | ![]() |
注意して欲しいのはあくまでも、あらかじめ「AndroidManifest.xml」に書かれているパーミッションでしか要求はできないという点だ。その書き方は前述の「AndroidManifest.xml にパーミッションを書く例」を参考にして欲しい。
根拠の説明ダイアログは「AlertDialog」を利用しているが、このままでは画面回転などで消えるので注意して欲しい。今回はテーマから外れるので必要あればデベロッパーマニュアルなどを参照して欲しい。またダイアログ内のメッセージも手抜きしているが(笑)、権限によって内容を変えるにはあらかじめメッセージを定義しておくことも必要だろう。リクエストコード(requestCode)は任意なので、その辺りで紐づけしても良いかも知れない。
またこの実装では2つ以上同時に権限要求すると、ダイアログが重なってしまうという欠点もある。もしそういう必要があるなら、要求を Queue のようなもので管理すると良い(LinkedList 等でも可)。ちょっと難しいかも知れないが、挑戦してみるのも良いだろう。
(参考)
・ダイアログを表示する
・実行時のパーミッション リクエスト
・パーミッションの確認
・必要なパーミッションのリクエスト
・パーミッション リクエストへの応答の処理
(関連記事)
【Android】【Java】AlertDialog を使ってみる
【Android】【Java】WIFI接続ONを取得する
【Android】【Java】WIFI, Bluetooth 接続の暗黙的Intent
【Android】【Java】SDカードからテキストファイルを読み込む
【Android】【Java】SDカードから画像ファイルを読み込む
【Android】【Java】SDカードに画像ファイルを保存する(png)
【Android】【Java】SDカードに画像ファイルを保存する(jpg)
【Android】【Java】SDカードのファイルを削除する
| h o m e |