課題
アプリのシェア機能を実装するにあたり、どのアプリが選択されたかをGoogle Analyticsに送信したい。
対応
あるIntentのActionに対応するアプリチューザー を表示するには Intent.createChooser
を使用するが、
Android API Level 22 (LOLLIPOP_MR1) から第3引数にIntentSenderが渡せるようなっている。
この IntentSender て何やねんというのは正直よく分からないが、BroadcastReceiverと組み合わせることで
一覧からアプリを選択した時点でBroardcastReceiverのonReceiveが受け取れるようになる。
実装
- Receiverを作る
- AndroidManifestにReceiver登録する
- ChooserDialogを表示する
- BroadcastReceiver.onReceiveでComponentNameを取得する
Receiverを作る
まず選択イベントを受信するためのレシーバを準備する。
class ShareReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (BuildConfig.DEBUG) { Log.d(TAG, "onReceived") } } companion object { private const val TAG = "ShareReceiver" } }
AndroidManifestにReceiverを登録する
マニフェストに登録。exportedはfalse
<receiver android:name=".ShareReceiver" android:exported="false"> </receiver>
ChooserDialogを表示する
例としてACTION_SENDに対応するものを表示する。この例では shareButton
が押された時点でChooserを起動するものとする
IntentSenderは直接インスタンス化できないのでPendingIntentを経由する必要がある。
/** * シェアボタンの設定 */ private fun setupShareButton() { val intent = Intent(Intent.ACTION_SEND) .putExtra(Intent.EXTRA_TEXT, "This is my text to send") .setType("text/plain") shareButton.setOnClickListener { val chooser = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { //Receiverを生成 val receiver = Intent(this, ShareReceiver::class.java) //PendingIntentを得る val pendingIntent = PendingIntent.getBroadcast(this, 0, receiver, PendingIntent.FLAG_UPDATE_CURRENT) //IntentSenderを得る Intent.createChooser(intent, "シェア", pendingIntent.intentSender) } else { Intent.createChooser(intent, "シェア") } startActivity(chooser) } }
BroadcastReceiver.onReceiveでComponentNameを取得する
先程作ったShareReceiverを編集する。
選択されたアプリの情報は Intent.EXTRA_CHOSEN_COMPONENT
で取り出すことができる。
実態は ComponentName
クラスなので、そのpackageNameを得ることで起動されたアプリのパッケージ名が分かる。
override fun onReceive(context: Context, intent: Intent) { if (BuildConfig.DEBUG) { Log.d(TAG, "onReceived") val bundle = intent.extras val componentName = bundle.get(Intent.EXTRA_CHOSEN_COMPONENT) if (componentName is ComponentName) { Log.d(TAG, componentName.packageName) } } }
備考
API Levelが22未満の端末では分からないのが欠点ではあるが、 端末シェアを考え無視に割り切ってしまって良いのではないかと思う。