Android11でsetDataSourceがエラーになる問題の解決策

作成: 2020年09月26日

更新: 2020年09月26日

エラー内容

Android 11でStorage Access Framework(SAF)で取得したURIに対してMediaPlayer.setDataSource(context, uri)やMediaMetadataRetriever.setDataSource(context, uri)を用いると以下のようなエラーになる.

java.lang.RuntimeException: setDataSource failed: status = 0xFFFFFFEA
java.io.IOException: setDataSource failed.: status=0x80000000

おそらく今回の更新で外部ストレージに関する制限が厳しくなったためと思われる.

Android 11 でのストレージに関する更新 | Android デベロッパー | Android Developers

解決策

Storage Access Framework(SAF)でURIを取得した際にそのURIに対して永続読み取り権限を付与する.

    override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
        super.onActivityResult(requestCode, resultCode, resultData)
        if (!Dispatcher.isRegistered(this)) {
            Dispatcher.register(this)
        }
        if (!Dispatcher.isRegistered(SoundStore)) {
            Dispatcher.register(SoundStore)
        }
        if (!Dispatcher.isRegistered(AlarmStore)) {
            Dispatcher.register(AlarmStore)
        }
        if (requestCode == readRequestCode && resultCode == Activity.RESULT_OK) {
            resultData?.data?.also { uri ->
                val fileName = getFileName(uri)
                check(fileName is String) { "FileName must be String" }
                this.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) // 追加した部分
                // 何らかの処理
            }
        }
    }

ContentResolver.takePersistableUriPermissionで読み取り権限を取得することでsetDataSourceなどで情報を読めるようになるらしい.

参考: java - Having trouble implementing ACTION_OPEN_DOCUMENT to my project - Stack Overflow