前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

アプリチューザーからどのアプリが選択されたかを知る

課題

アプリのシェア機能を実装するにあたり、どのアプリが選択されたかをGoogle Analyticsに送信したい。

対応

あるIntentのActionに対応するアプリチューザー を表示するには Intent.createChooser を使用するが、 Android API Level 22 (LOLLIPOP_MR1) から第3引数にIntentSenderが渡せるようなっている。 この IntentSender て何やねんというのは正直よく分からないが、BroadcastReceiverと組み合わせることで 一覧からアプリを選択した時点でBroardcastReceiverのonReceiveが受け取れるようになる。

実装

  1. Receiverを作る
  2. AndroidManifestにReceiver登録する
  3. ChooserDialogを表示する
  4. 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未満の端末では分からないのが欠点ではあるが、 端末シェアを考え無視に割り切ってしまって良いのではないかと思う。

参考