ストレージ権限を付与せずにカメラ撮影のIntentを投げる
ツイッター公式とかがランタイムパーミッション求めてくるけど、別になくてもいけるよな?って思ってやってみた。
やること
-
READ_EXTERNAL_STORAGE
及びWRITE_EXTERNAL_STORAGE
権限を付与しない
- アプリから
ACTION_IMAGE_CAPTURE
でアプリを起動する
- 撮影された写真(Uri)をBitmapに復元する
実装
FileProviderを定義する
AndroidManigest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider" />
</provider>
res/xml/file_provider.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="image" path="temp/"/>
</paths>
出力先のUriを用意する
READ_EXTERNAL_STORAGE
及びWRITE_EXTERNAL_STORAGE
権限を付与しないACTION_IMAGE_CAPTURE
でアプリを起動するFileProviderを定義する
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider" />
</provider>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="image" path="temp/"/>
</paths>
出力先のUriを用意する
ファイルを作ります
private File createOutputFile() {
File tempFile = new File(context.getFilesDir(), "temp/sample");
if (!tempFile.exists()) {
try {
tempFile.getParentFile().mkdirs();
tempFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return tempFile;
}
ファイルが存在していないと、カメラ側でFileNotFoundException
になるので空ファイルを作ってください。
作ったファイルをFileProvider
を使ってUriに変換します。
FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
Intentを起動する
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, REQUEST_CAPTURE);
結果を受け取る
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAPTURE && resultCode == RESULT_OK) {
Uri uri = outputUri();
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
}
}
ACTION_IMAGE_CAPTURE
では、出力先Uriが返却されない糞仕様なので、出力先Uriは起動側でどうにかして保持しておく必要があります。
Uriを動的に生成する場合、カメラ起動時にメモリ食ってActivityが破棄される可能性も考えるとonSaveInstanceState()
を実装したりとそこそこめんどくさいですが、頑張ってください。
仕組み
出力先ファイルはアプリ領域に用意し、FileProvider
を使ってUri
化しています。
このUri
は通常、当該アプリしかアクセスできませんが、Intent
に FLAG_GRANT_WRITE_URI_PERMISSION
フラグを追加することで、一時的に外部アプリにアクセス権限を与えることができます。
課題
KitKat以前は、暗黙的IntentにFLAG_GRANT_*_PERMISSION
が付与されない
FLAG_GRANT_*_PERMISSION
が付与されない暗黙的IntentにUriのアクセス権限が付与できないようです。
以下のようにすることで、付与できるようですが、ユーザーが起動するアプリ以外にも付与される気がするのでどうなんだろ…
List<ResolveInfo> resolves = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resolves) {
grantUriPermission(resolveInfo.activityInfo.packageName, outputUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
ちなみにgrantUriPermission()
したら、必要に応じてrevoke
してあげたほうがいいみたいです。
revokeUriPermission(outputUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
参考
Author And Source
この問題について(ストレージ権限を付与せずにカメラ撮影のIntentを投げる), 我々は、より多くの情報をここで見つけました https://qiita.com/ushi3_jp/items/115e3c725a9ffa34aed0著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .