概要
Android11から(api30+)自身のアプリ以外のパッケージとプロセス間通信するとき、AndroidManifestの追記をしないと通信できない。
解決した問題の症状
前提
- Android11以上の端末またはエミュレータ
- プロセス間通信を行う2つのアプリ共に自作(Kotlin)
症状
呼び出し元から別アプリのサービスを指定してbindServiceしても返り値がずっとfalseになる(繋がらない)。
時系列順で症状に至るまでの経緯を列挙する。
- targetSdkのバージョンがすべて28のまま二つのアプリを作成
- 接続先のアプリにバインドされるServiceを記載し、ビルドしてインストール
- 接続元から対象ServiceをbindSereviceするコードを書いて、こちらもビルドしてインストール
val intent = Intent("testPackage.server.targetService").setPackage("testPackage.server")
val res = context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
- bindServiceからtrueがくる
ここまでは期待動作だが
- 呼び出し元のtargetSdkバージョンを30以上に指定する
- 改めてbindServiceする部分のコードを変えずに実行
- bindServiceの返り値がずっとfalseで接続できず(ある特定パターンではつながるが非実用的)
- ※ なお、bindServiceからはエラーメッセージが来ない
(実装の詳細説明)バインドされたサービスの概要 | Android デベロッパー
原因
Android でのパッケージの公開設定のフィルタリング
プライバシー強化のため、Android11からアプリが他に入っているアプリを全部覗けなくなくなったから。
改善策
bindServiceを叩く方のアプリにあるAndroidManifest.xmlに、"queries" タグを設け、対象となるアプリケーションのパッケージ名をタグ内に記載する。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="testPackage.client">
<queries>
<package android:name="testPackage.server"/>
</queries>
...
</manifest>
ビルドし実行すると、bindServiceからtrueが来るようになり、接続が成功する。
ServiceConnectionのonServiceConnected関数も呼び出される。
参考元Webページ
Rant over Android (訳:Androidへの憤り)
同じく。
(プライバシー強化はメリットのあるものだと思うが...)