本日はMetaQuest3の技術調査枠です。
MRTKv2.xを使ってMetaQuest3向けのUnityプロジェクト作成を行う手順を記事にします。
本記事はDocumentsフォルダにアクセスする手順です。
Documentsフォルダにアクセスする
QuestのDocumentsフォルダにアクセスするには以下の作業が必要になります。
・AndroidManifestにMANAGE_EXTERNAL_STORAGE権限を付与する
・アクセス権限の許可を取得する
・/sdcard/Documents/フォルダにアクセスする
AndroidManifest.xmlへの権限設定
プロジェクトのアセットフォルダにあるAndroidManifest.xmlを開きます。
Assets/Plugins/Android/AndroidManifest.xml

AndroidManifest.xmlに以下の機能権限を追加します。
<uses-permission androidname="android.permission.MANAGE_EXTERNAL_STORAGE"/>

フォルダアクセスの許可を求める
Documentsフォルダにアクセスするにはアプリ内でフォルダアクセスの許可を得る必要があります。
以下のコードを実行するとアプリ内でアクセス許可のダイアログが表示されます。
<summary>
</summary>
private void AskForManageStoragePermission()
{
try
{
using var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
using AndroidJavaObject currentActivityObject = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
string packageName = currentActivityObject.Call<string>("getPackageName");
using var uriClass = new AndroidJavaClass("android.net.Uri");
using AndroidJavaObject uriObject =
uriClass.CallStatic<AndroidJavaObject>("fromParts", "package", packageName, null);
using var intentObject = new AndroidJavaObject("android.content.Intent",
"android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", uriObject);
intentObject.Call<AndroidJavaObject>("addCategory", "android.intent.category.DEFAULT");
currentActivityObject.Call("startActivity", intentObject);
}
catch (AndroidJavaException e)
{
m_FolderPermissionOverride = true;
Debug.LogError("Java Exception caught and ignored: " + e.Message);
Debug.LogError("Assuming this means we don't need android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION (e.g., Android SDK < 30)");
}
}
フォルダアクセスの許可が得られれば以下のフォルダパスでDocumentsフォルダにアクセスできます。
/sdcard/Documents/
フォルダアクセスの許可を求め、ユーザの許可が行われればDocumentsフォルダにテストフォルダを作成する以下のサンプルスクリプトを作成しました。
using UnityEngine;
public class DocumentAccessTest : MonoBehaviour
{
#if UNITY_ANDROID
async void Start()
{
await GetStoragePermissionAsync();
string documentFolderPath = GetDocumentFolderPathPerAndroid29();
string folderPath = System.IO.Path.Combine(documentFolderPath, "TestFolder");
if(!System.IO.Directory.Exists(folderPath)) System.IO.Directory.CreateDirectory(folderPath);
}
<summary>
</summary>
<returns></returns>
private string GetDocumentFolderPathPerAndroid29()
{
string documentPath = "/sdcard/Documents/";
return documentPath;
}
<summary>
</summary>
<returns></returns>
private async Task<bool> GetStoragePermissionAsync()
{
if (!UserHasManageExternalStoragePermission())
{
AskForManageStoragePermission();
while (!UserHasManageExternalStoragePermission())
{
await Task.Delay(100);
}
}
return true;
}
private bool m_FolderPermissionOverride = false;
<summary>
</summary>
private bool UserHasManageExternalStoragePermission()
{
bool isExternalStorageManager = false;
try
{
AndroidJavaClass environmentClass = new AndroidJavaClass("android.os.Environment");
isExternalStorageManager = environmentClass.CallStatic<bool>("isExternalStorageManager");
}
catch (AndroidJavaException e)
{
Debug.LogError("Java Exception caught and ignored: " + e.Message);
Debug.LogError("Assuming this means this device doesn't support isExternalStorageManager.");
}
return m_FolderPermissionOverride || isExternalStorageManager;
}
<summary>
</summary>
private void AskForManageStoragePermission()
{
try
{
using var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
using AndroidJavaObject currentActivityObject = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
string packageName = currentActivityObject.Call<string>("getPackageName");
using var uriClass = new AndroidJavaClass("android.net.Uri");
using AndroidJavaObject uriObject =
uriClass.CallStatic<AndroidJavaObject>("fromParts", "package", packageName, null);
using var intentObject = new AndroidJavaObject("android.content.Intent",
"android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", uriObject);
intentObject.Call<AndroidJavaObject>("addCategory", "android.intent.category.DEFAULT");
currentActivityObject.Call("startActivity", intentObject);
}
catch (AndroidJavaException e)
{
m_FolderPermissionOverride = true;
Debug.LogError("Java Exception caught and ignored: " + e.Message);
Debug.LogError("Assuming this means we don't need android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION (e.g., Android SDK < 30)");
}
}
#endif
}
任意のオブジェクトにコンポーネントとして設定して起動時に処理が走るようにします。

ビルドと動作確認
これで設定は完了です。
以下の記事を参考にプロジェクトのビルドとQuest3へのデプロイを実行してください。
bluebirdofoz.hatenablog.com
アプリを起動すると、メニューパネルが起動してアクセス許可を求める画面が表示されます。
キャプチャでは撮影できませんでした。

トグルをONにしてアクセス許可を行うとQuestのDocumentsフォルダにテストフォルダが作成されました。
