Android 10で追加されたBubblesについて
中里 直人
本記事はリクルートライフスタイル Advent Calendar 2019の12日目の記事です。
ホットペッパービューティーのネイティブアプリ開発を担当している中里です。この記事では、Android 10で追加されたBubblesの使い方と、使ってみた感想を書きたいと思います。
Bubblesとは?
Bubblesとは、Facebook Messengerのように他のアプリの上に描画する機能で、日本語だと「ふきだし」と訳されています。
https://developer.android.com/guide/topics/ui/bubbles
従来このようなUIを実現するためには、 SYSTEM_ALERT_WINDOW
という権限が必要でしたが、 SYSTEM_ALERT_WINDOW
は強い権限であり、また電池消費の観点からも不利であるため、それを代替するためにAndroid 10から登場しました。
アプリの作成
プロジェクトの作成
まず、いつも通りにプロジェクトを作成します。当然ですが、APIレベルは29以降に設定する必要があります。
1
2
3
4
5
6
7
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 29
targetSdkVersion 29
}
}
Bubble用のActivityを作成
Bubbleの中身として表示したい内容を、Activityとして作成します。
1
2
3
4
5
6
class BubbleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bubble)
}
}
次に、作成したActivityをAndroidManifestに追加します。
1
2
3
4
5
<activity
android:name=".BubbleActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:resizeableActivity="true" />
Bubbleとして表示するためには、以下の3つの値を設定する必要があります。
- allowEmbedded
- Activityを別のActivityの子として起動できるかどうか。
- documentLaunchMode
- Activity起動時のタスクの追加方法。
always
を指定すると、常に新しいタスクを作成する。
- Activity起動時のタスクの追加方法。
- resizeableActivity
- 画面分割のように、サイズ変更が可能なActivityかどうか。
Bubbleの呼び出し
Bubbleの呼び出しは、以下のように基本的には通知と同じような実装になります。
- 通知を送るチャンネルの作成
- 通知の送信
- PendingIntentの作成
- BubbleMetadataの作成
- Notificationの作成
- NotificationManagerによる通知
まず、通知を送るチャンネルを作成します。このとき、Bubblesとして表示するために setAllowBubbles(true)
を設定します。
1
2
3
4
5
6
7
private fun createNotificationChannel() {
val channel = NotificationChannel("Channel Id", "Channel Name", NotificationManager.IMPORTANCE_HIGH)
channel.description = "Channel Description"
channel.setAllowBubbles(true)
val notificationManager: NotificationManager = getSystemService() ?: return
notificationManager.createNotificationChannel(channel)
}
次に、実際に通知を送信する処理です。
そのためにまずは、PendingIntentを作成します。
1
2
val intent = Intent(this, BubbleActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
次に、BubbleMetadataを作成します。ちなみにここで setAutoExpandBubble(false)
にすると、Bubbleが閉じた状態で表示されます。
1
2
3
4
5
6
val bubbleMetadata = Notification.BubbleMetadata.Builder()
.setDesiredHeight(600)
.setIcon(Icon.createWithResource(this, R.drawable.ic_launcher_foreground))
.setIntent(pendingIntent)
.setAutoExpandBubble(true)
.build()
最後に、Notificationを作成します。ドキュメントだとPersonを指定していますが、指定しなくてもBubbleの表示には特に関係ありませんでした。
1
2
3
4
val notification = Notification.Builder(this, "Channel Id")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setBubbleMetadata(bubbleMetadata)
.build()
あとは、作成したNotificationをNotificationManagerに投げます。
1
2
val notificationManager = NotificationManagerCompat.from(this)
notificationManager.notify(0, notification)
ここまで、実装したらあとは実行!と行きたいところですが、このままだと普通の通知として表示されてしまいます。
Bubblesの設定
Bubblesは公式ドキュメントにも書いてある通り、デベロッパープレビューであり、デフォルトでは無効になっています。Bubblesを利用するためには、開発者向けオプションから有効にする必要があります。
あるいは、以下のadbコマンドを実行しても有効にすることができます。
1
adb shell settings put secure notification_bubbles 1
実行結果
以上の実装・設定をすると、以下のように表示することができます。
戻るボタンや暗い部分をタップすることで、小さいアイコンだけの表示になります。
このアイコンは動かすことができ、下の方に持っていけばdismissすることができます。
また、通知IDを変えて複数回呼び出せば、複数表示することもできます。
別の画面への遷移
Bubbleとして表示しているActivityから startActivity
で別のActivityに遷移することもできます。そのためには、遷移先のActivityも同様にAndroidManifestに定義する必要があります。ただし、画面遷移の場合は新しいタスクを作成する必要はないので、 documentLaunchMode
は指定しません。
1
2
3
4
<activity
android:name=".SecondActivity"
android:allowEmbedded="true"
android:resizeableActivity="true" />
戻るボタンを押すことで、前のActivityに戻ることもできます。
ちなみにAndroidManifestを正しく書かないと、Bubbleは閉じて普通に全画面遷移してしまいます。また、このあと再びBubbleを開くと、以下のような真っ黒な表示になってしまいました😅
ライフサイクル
Bubbleとして表示しているActivityのライフサイクルについては、表示時は
1
onCreate → onStart → onResume
と走り、Bubbleを閉じて小さいアイコンの状態に変わるときは、
1
onPause → onStop
となり、再び表示する時はまたonStart(onRestart)から始まりました。また、dismissしたらonDestroyが走りました。ライフサイクルについては特に意外性はなさそうです。
まとめ
実装方法は通常の通知と大きく変わらないため、そこまで新しい知識は必要とせずに実装することができました。ただ、古いユーザー向けには通知として表示されてしまうので、使い方は工夫する必要がありそうです。個人的には、チャットなどのアプリ以外でもBubblesは便利そうだなと感じたので、早く正式版になって欲しいなーと思いました。
それでは良いお年を🎄