AndroidQからはファイルを保存してギャラリーで見るだけなら WRITE_EXTERNAL_STORAGE
が必要ではなくなりました。
AndroidManifest
Q(29)からは必要でない -> 28までは必要ということで、 AndroidManifest.xml
で以下を指定します。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
https://developer.android.com/guide/topics/manifest/uses-permission-element
実装
AndroidQ未満は省きます。
contentResolver
の取得部分は省いてあります。
val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) // 書き込みたい画像の情報をInsertして、書き込むべきUriを取得します。 // この時IS_PENDINGを1にし、書き込みが終了したら `0` にします。 // 書き込み途中で他のアプリに参照されたらまずいですからね。 val writeUri= contentResolver.insert( collection, ContentValues().also { values -> values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") values.put(MediaStore.Images.Media.TITLE, fileName) values.put(MediaStore.Images.Media.IS_PENDING, 1) } )!! // 書き込みを行います contentResolver.openFileDescriptor(writeUri, "w").use { it!! // よしなに処理してください FileOutputStream(it.fileDescriptor).use { out -> URL(url).openStream().copyTo(out) } } // IS_PENDINGを0にして書き込みを終わらせます contentResolver.update( writeUri, ContentValues().also { values -> values.put(MediaStore.Images.Media.IS_PENDING, 0) }, null, null )
おまけ
IS_PENDINGを1、IS_PENDINGを0にするというペアが存在するので、これは処理をまとめたくなってしまいます。
@RequiresApi(Build.VERSION_CODES.Q) inline fun writeImage(fileName: String, block: (Uri) -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } val collection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) val uri = contentResolver.insert( collection, ContentValues().also { values -> values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") values.put(MediaStore.Images.Media.TITLE, fileName) values.put(MediaStore.Images.Media.IS_PENDING, 1) } )!! block(uri) contentResolver.update( uri, ContentValues().also { values -> values.put(MediaStore.Images.Media.IS_PENDING, 0) }, null, null ) }