投稿する写真をカメラアプリで撮って送るついでにギャラリーアプリから見えるようにする(API Level 22+)
今回やりたいこと
- 投稿する画像をギャラリーから選ぶかカメラで撮るかして取得したいのでIntent Chooserを出したい
- いい機会なので
ActivityResultContract
を使いたい - tweet input: enable sending media · Issue #130 · akihito104/UdonRoad2 · GitHub
前提
- target SDK version: 29
- Android 10で動作を確認した
androidx.activity:activity-ktx:1.2.0-beta01
androidx.fragment:fragment-ktx:1.3.0-beta01
カメラアプリを起動するインテント
カメラアプリのインテントはActivityResultContracts.TakePicture
を使えばよい。
インテントを作るときに渡すUri
はFileProvider.getUriForFile()
を使って作る。content://
からはじまるUri
が取得できる。カメラアプリは撮影に成功してもファイルパスを返しては来ないのでこのUri
は保存しておく。FileProvider
の設定はリファレンスが詳しい。
今回はexternal-media-path
と、古いバージョン(API Level 21未満)のためにexternal-file-path
も指定した。また、authority
の名前にアプリケーションIDを使いたかったのでアプリモジュールで実装してDIで注入する形にした。
カメラアプリにファイルの書き込み権限を渡したい
リファレンスによると二つの方法があるらしい。
FileProvider | Android Developers
結論から言うと二つ目のInclude the Permission in an Intentの方法は、Intent Chooserを出したい場合にはうまく動かない様子。
したがって一つ目のGrant Permission to a Specific Packageの方法で実現することになる*1。ただし、権限を渡したいアプリのパッケージ名が必要なので何とかして入手しなければならない。API Level 22以上であればIntent.createChooser(Intent, CharSequence, IntentSender)
を使うことで、Intent Chooserで選択されたアプリがBroadcastReceiver
で取得できる。
API Level21以下で同じことをしなければならない時は、選択される可能性のあるカメラアプリをPackageManager.queryIntentActivities()
で取得し、それらすべてに対して許可するしかないと思われる。いずれの場合においても権限をrevokeしそびれることが無いよう注意する。
画像をギャラリーから見えるようにする
この記事を書いている現在、公式の Take photos | Android Developers に書いてあるIntent.ACTION_MEDIA_SCANNER_SCAN_FILE
を投げる方法は非推奨になっている。なので、今回はMediaScannerConnection.scanFile()
を使った。これだとContext
が必要なのでActivityResultContract.parseResult()
とかの中でちょろっとやってしまうのは難しいかもしれない。また、これに渡すファイルパスはcontent://の形式のものではなく、FileProvider.getUriForFile()
に渡したFileのパスを渡す。
このほかにも、カスタムのContractを作ったらワケあってDI(Dagger)でFragmentにContractを注入することになり、registerForActivityResult()
をonAttach()
のなか(というかAndroidSupportInjection.inject()
のあと)で呼ぶ羽目になったとかいろいろ細かいことはあるが、細かいのでこの辺にしておく。
*1:StackOverflowの回答ではqueryIntentActivities()をやって明示的なIntentにして解決しているがこっちの方法では試していない。こっちでうまくいくならその方がいいかも。