こんにちは、ちゃらいプログラマです。
アプリ内から写真フォルダにアクセスする際に今まではAndroidManifest.xmlに
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
を設定していましたがGoogleのポリシーNGになりました。
上記の定義がなくてもStorage Access Framework(SAF)に置き換えることでポリシーOKとなりましたので変更箇所を纏めます。
AndroidManifest.xml
// Android12(API32)までは権限確認が必要 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
UnityPlayerActivityを継承したActivity.java
private final int INTENT_IMAGE = 1000;
// C#側で実行される関数
public void open( String gameObjectName, String savePath )
{
_gameObjectName = gameObjectName;
_saveFilePath = savePath;
// Android13(API33)以降は権限チェック不要でそのまま開始を実行する
if(Build.VERSION.SDK_INT > 32)
{
startActivity();
}
else
{
if( ContextCompat.checkSelfPermission( UnityPlayer.currentActivity, Manifest.permission.READ_EXTERNAL_STORAGE ) != PackageManager.PERMISSION_GRANTED )
{
ActivityCompat.requestPermissions( UnityPlayer.currentActivity, new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE }, INTENT_PERMISSION_READ_EXTERNAL_STORAGE );
}
else
{
startActivity();
}
}
}
// 開始
private void startActivity()
{
UnityPlayer.currentActivity.runOnUiThread( new Runnable()
{
public void run()
{
// 写真のみに限定しています
Intent intent = new Intent();
intent.setType( "image/*" );
intent.setAction( Intent.ACTION_OPEN_DOCUMENT );
intent.addCategory( Intent.CATEGORY_OPENABLE );
UnityPlayer.currentActivity.startActivityForResult( intent, INTENT_IMAGE );
}
});
}
// 開始結果
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent resultData )
{
super.onActivityResult( requestCode, resultCode, resultData );
String savePath = "";
switch( requestCode )
{
case INTENT_IMAGE:
if( resultCode == RESULT_OK )
{
Uri uri = resultData.getData();
if(uri != null)
{
// 永続アクセス許可を付与(再起動後もアクセス可能にする)
final int takeFlags = resultData.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri, takeFlags);
// ユーザが選択したファイルをコピー
savePath = copySafFileToLocal(uri, _saveFilePath + "/tmpImage");
}
}
// 結果をC#側へ伝える
UnityPlayer.UnitySendMessage( _gameObjectName, "CallbackOpen", savePath );
break;
default:
break;
}
}
// コピー
private String copySafFileToLocal(Uri uri, String destPrefix)
{
String savePath = destPrefix;
try
{
ContentResolver resolver = getContentResolver();
// 拡張子取得
String mimeType = resolver.getType(uri);
String ext = ".png";
if (mimeType != null)
{
String[] parts = mimeType.split("/");
if (parts.length == 2) ext = "." + parts[1];
}
savePath += ext;
try (InputStream inputStream = resolver.openInputStream(uri);
OutputStream outputStream = new FileOutputStream(new File(savePath)))
{
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1)
{
outputStream.write(buffer, 0, len);
}
}
}
catch (Exception e)
{
savePath = e.toString();
}
return savePath;
}
ファイルコピー処理は権限の有無に関係なく共通化できます。
普段Javaを書かないので本当に動くのか…といつもドキドキしながら書きます…
ではまた次回!