💩

Unityで開発するAndroid11以降の共有フォルダへのアクセス方法について

2023/11/05に公開

TL;DR

  • Android11(API30以降)では、共有フォルダ(Downloadなど)のファイルにアクセスするために特別な権限が必要
  • Android(Java、Kotlin)での権限付与の方法は記事が見つかったが、Unity(C#)での権限付与の実装方法が見つからなかったため調査し記事化

手順

  • 権限が付与されているか確認
  • 付与されていなければ、権限の付与を切り替える画面を表示するIntentを実行
  • AndroidManifestにPermissionを追記

プログラム

下記のクラスを作成

RuntimeAndroidSettingHelper.cs

using System.Collections.Generic;
using UnityEngine;
using System;
public class RuntimeAndroidSettingHelper
{
    private RuntimeAndroidSettingHelper() { }
    private static AndroidJavaObject GetActivity()
    {
        using (var UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
        {
            return UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        }
    }
    public static void Request_SettingsIntent()
    {
        using (var activity = GetActivity())
        {
            using (var intentObject = new AndroidJavaObject("android.content.Intent", "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION"))
            {
                activity.Call("startActivity", intentObject);
            }
        }
    }
    //https://developer.android.com/reference/android/os/Environment#isExternalStorageManager()
    public static bool HasUserAuthorizedPermission()
    {
        var isExternalStorageManager = false;
        try
        {
            // Androidの外部ストレージマネージャのパーミッションチェック
            AndroidJavaClass environmentClass = new AndroidJavaClass("android.os.Environment");
            isExternalStorageManager = environmentClass.CallStatic<bool>("isExternalStorageManager");
        }
        catch (Exception e)
        {
            return false;
        }

        return isExternalStorageManager;
    }
}

AndroidManifest.xmlに以下の1行を追記( <application>の上)

AndroidManifest.xml

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

実行

HasUserAuthorizedPermission関数で権限の付与がされているか確認し、falseであればRequest_SettingsIntentを実行する。
実機では下記のような画面が表示される。

  1. すべてのファイルへのアクセス権限を操作することができるアプリ一覧が表示される

  2. 今回作成した「Android_ALLFile_Permission」を選択

  3. トグルボタンを押下

4.「許可する」に変更した場合

感想

ユーザにPersistendDataPathなどにファイルを置いてもらうのはハードルが高いので、ウェブからファイルダウンロード時に共有フォルダ(DownloadやDocument)にファイルを置いてもらって、そのディレクトリからアプリがファイルを読み込むみたいな使い方ができると思います。

参考文献

https://kazupon.org/unity-android-app-detail-open/
https://developer.android.com/reference/android/os/Environment#isExternalStorageManager()
https://developer.android.com/reference/android/provider/Settings#ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION
https://developer.android.com/reference/android/Manifest.permission#MANAGE_EXTERNAL_STORAGE
https://qiita.com/kiito1000/items/46bd861c3c3dd3220366
https://docs.unity3d.com/ja/2023.2/ScriptReference/AndroidJavaClass.html
https://qiita.com/s_Pure/items/8b7ef9e36de3167c4ca0

追記

設定画面(トグルボタンが表示されている画面)を直接開くには、下記の関数を実行します

RuntimeAndroidSettingHelper.cs

    public static void Request_SettingsIntent()
    {
        // var actionConstant = ActionConstant[(int)actionIntent];
        var actionConstant = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
	var packageName = "";
	using (var activity = GetActivity()){
		var context = activity.Call<AndroidJavaObject>("getApplicationContext");
                packageName = context.Call<string>("getPackageName");
	}
	
	
        using (var activity = GetActivity())
        {
            var uri = new AndroidJavaObject("android.net.Uri");
            var uriObject = uri.CallStatic<AndroidJavaObject>("fromParts", "package", packageName, null);

            using (var intent = new AndroidJavaObject("android.content.Intent", "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", uriObject))
            {
                activity.Call("startActivity", intent);
            }
        }
    }
	
	
	

Discussion