実現したいこと
android webview fileタグでカメラ起動させて撮った写真を渡そうとするとファイルが見つからない例外が発生するのを解決したいです
画像ファイルを選択した場合は fileタグに渡せている状態で、カメラで撮った写真だけ渡せない状態です。
発生している問題・分からないこと
カメラで撮った画像を一時的にアプリ内のストレージに保存して、その URI を ContentResolver で content:// から始まる URI を取得して、onReceiveValue にセットすると、fileタグの右側にファイル名は表示されますが、実際は当該ファイルが見つからない例外が発生します。
Android 10 以降を対象にしているので uses-permission は android.permission.READ_MEDIA_IMAGES を指定しています。
queries には以下を指定してあります。
android.media.action.IMAGE_CAPTURE
android.intent.action.GET_CONTENT
provider 要素も指定してあります。
該当のソースコード
kotlin
1 private fun getPhotoUri(context: Context, file: File): Uri { 2 return FileProvider.getUriForFile(context, context.packageName + ".provider", file) 3 } 4 private fun createImageFile(): File? { 5 @SuppressLint("SimpleDateFormat") val timeStamp = SimpleDateFormat( 6 "yyyyMMdd_HHmmss" 7 ).format(Date()) 8 val imageFileName = "img_" + timeStamp + "_k" 9 // 外部ストレージのディレクトリを取得し、storageDir変数に格納 10 val storageDir = _context?.getExternalFilesDir(Environment.DIRECTORY_PICTURES) 11 // 一時的なJPEGファイルを作成し、外部ストレージ内の一時ディレクトリに作成 12 var file: File? = null 13 try { 14 file = File.createTempFile(imageFileName, ".jpg", storageDir) 15 } catch (ex: Exception) { 16 Log.d(TAG, "exception:$ex") 17 } 18 return file 19 } 20↑まずこの関数で空のファイルをストレージに出力しています。 21この時のファイル URI を保存しておきます。 22 23 private fun registerContentResolver(context: Context, filePath: String): Uri? { 24 val values = ContentValues() 25 values.put(MediaStore.Images.Media.DISPLAY_NAME, filePath) 26 values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") 27 28 var uri = context.contentResolver.insert(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), values) 29 30 return uri 31 } 32↑この関数でカメラで写真を撮ったあと、registerForActivityResult が呼ばれます。 33AndroidStudio の DeviceExploler で撮った写真の実体が保存されていることを確認しています。 34この時に先ほど保存した URI のパスが、写真の実体になっていることを確認しました。 35この URI を ContentResolver に insert すると、content:// から始まる ID 付きのパスで insert されました。 36このパスを onReceiveValue にセットすると、当該ファイルが見つからない例外発生しました。 37 38撮った画像ファイルの書き込みができているので、参照もできると思いますが、このパス (ID 付きのパス) が参照できない問題を解決したいです。
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
FileProvider.getUriForFile で取得できた結果は
content://パッケージ名.provider/files/storage/emulated/0/Android/data/パッケージ名/files/Pictures/img_20240406_114336_k7044656972246031396.jpg
ContentResolver.insert で作成した URI は
content://media/external_primary/images/media/1000001188
です。
(.jpg ファイル名の数字やメディア ID はスクリーンショットを撮る前のビルドで記録したものなのでスクリーンショットと異なります)
補足
特になし
その後ですが、Android 10 だとパーミッションが android.permission.READ_MEDIA_IMAGES ではなく、android.permission.WRITE_EXTERNAL_STORAGE になるのですが、registerForActivityResult の result.data から Intent が取得でき、画像選択時と同じ処理でカメラ画像を fileタグ に渡すことができました。
この場合はフォーム送信時にファイルの実体は送信できていました。(PHP の$_FILES のファイルサイズが 0 ではなかったことで確認)
Android 13 の場合は、result.data が null だったので、空ファイルを作った時のパスから ContentResolver にセットする URI を作成しています。
この URI を作成する元のファイルが添付画像の DeviceExploler の実体はありましたとのパスと一致はしており、そこから content:// スキームから始まるメディア ID の URI に変換できているので、実体があればメディア ID の URI に変換できるのであれば、パス自体は問題ないと思うのですが、InputStream でこの URI を開こうとしても同様にファイルが見つからない例外が発生したので、生成された URI 自体が正しいかを調べてみます。
もし同じような症状を解決した方がいらっしゃれば情報をいただけるとありがたいです。
回答1件
あなたの回答
tips
プレビュー