ロコガイド テックブログ

「地域のくらしを、かしこく、たのしく」する、株式会社ロコガイドの社員がいろいろな記事を書いています。

「地域のくらしを、かしこく、たのしく」する、株式会社ロコガイドの社員がいろいろな記事を書いています。

Android11の新機能Bubblesさわってみた!

f:id:iaiaie:20201201202217p:plain

この記事はロコガイド Advent Calendar 2020の9日目です。

Androidアプリエンジニアのiaiaです。

今回はAndroid11で正式にユーザにリリースされたBubblesについて触れていきます。

概要

Bubblesについて

BubblesはAndroid10からデベロッパープレビューとして導入されており、今回Android11で正式にユーザ向けに解放されました。

https://1.bp.blogspot.com/-2EjlXajlrbs/XvmjDbCrAxI/AAAAAAAAEak/u5TrIa19NcouxQSTPV_aESUTkaQvGbbMQCK4BGAsYHg/s1000/image1.gif

引用元: Android の注目機能を 11 週連続でご紹介する「11 Weeks of Android」: 人と ID

他のアプリを使っているときでもスムーズにチャットし合う、というユースケースを想定しているようです。 チャットを全面に押し出しているように見えるので、チャットが無いアプリでは使わないかな?
と思ってしまいますが実はそんなことはなく、開発者向けドキュメント を眺めてみると、 他のアプリの上に自アプリのActivityをシームレスに起動できるマルチタスクな機能であることが分かります。

ですが、いきなり自社アプリにマルチタスクな機能を追加するのは難しいでしょう。

そもそもAndroid11でリリースされたとはいえ、

ことを考えると、今すぐにBubblesを使った機能をユーザリリースするのはあまりインパクトが無さそうです。

とはいえ、事前に触っておくことで「今度追加する機能、Bubblesでやってみましょう」という提案も出来ますし、
触ってみてはじめて「あれに使える」「これに使える」ということに気づくこともあります。

せっかくの新機能だし使ってみるぜ!

Furufuruについて

前述したとおり、Bubblesを自社アプリの一機能として使うのも難しいですし、使わない機能に会社のリソースを割くのも難しそうです。
ですが開発時専用のデバッグ機能として使うのはどうでしょう?
弊社アプリのトクバイにはFurufuruというバグレポーティングライブラリを載せています。

techblog.locoguide.co.jp

※ 注 iOS: Huruhuru, Android: Furufuru

Furufuruはその名の通り、端末を「振る」ことでバグレポート画面を起動させることが出来ますが、振る感度の調整が難しく、人によっては「振ってもなかなか起動してくれない」という問題がありました。

「振る」以外の導線を組み込むことでその問題を解決したいとは思ってはいたものの、

  1. 「通知一覧を開いて通知をタップして起動」というのも操作が増える
  2. 一度対象の画面から離れてしまう
  3. スクショのタイミングが難しくなる

という問題があり、なかなか開発へ取り組めずにいました。

Bubblesではシームレスに通知から起動できるので、1と2の問題は解決できそうです。

スクショのタイミングはなんとかするからええねん!

Bubblesの作り方

※ 記事用に実際のコードを一部抜き出し、編集しています。実際のコードは こちら

1. 通知から直接開きたい画面(Activity)を作る

これは既にあるActivityで構いません。

ですが、ベストプラクティスにあるように通知から起動することになるので、なるべく1画面で済むようなシンプルなActivityにしましょう。

2. AndroidManifest.xml の設定変更

2点パラメータを追加する必要があります。

画面全体を専有する通常の起動と違いますので、対象のActivityはサイズが変更可能で無ければなりません。
分割画面モードなどで使われる resizeableActivitytrue にする必要があります。

allowEmbeddedtrue にします。こちらはウェアラブルデバイスで使われるフラグのようです。 (参考: https://developer.android.com/guide/topics/manifest/activity-element?hl=ja#embedded)

以上を踏まえてmanifestを変更すると以下のようになります。

<activity
    android:name=".feature.ui.issue.IssueActivity"
    android:launchMode="singleTask"
    android:exported="false"
    android:documentLaunchMode="always"
    android:theme="@style/Theme.AppCompat.NoActionBar"
    android:taskAffinity=""
    android:excludeFromRecents="true"
    android:allowEmbedded="true"       <-- 追加
    android:resizeableActivity="true"  <-- 追加
    tools:targetApi="n" />

3. 通知チャンネルでBubblesを有効化

特定の通知チャンネルにBubblesで通知することを許可させます。
既存の通知チャンネルをgetしてくるか、新規に通知チャンネルを作成する際にフラグをセットしておきます。

val notificationChannel = NotificationChannel(
    channel.channelId,
    channel.channelName,
    NotificationManager.IMPORTANCE_LOW
)
// Android 10以上でBubblesを有効にする
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    notificationChannel.setAllowBubbles(true)
}

4. BubbleMetadataを作る

Bubbles対応のメインです。

NotificationCompat.BubbleMetadata のBuilderがあるので、それを使います。

@RequiresApi(Build.VERSION_CODES.Q)
private fun createBubbleMetaData(context: Context): NotificationCompat.BubbleMetadata {
    val targetActivityIntent = IssueActivity.createIntent(context)
    val contentIntent = PendingIntent.getActivity(context, 0, targetActivityIntent, 0)
    return NotificationCompat.BubbleMetadata
        .Builder()
        .setIcon(IconCompat.createWithResource(context, R.drawable.ic_send))  <-- どのアイコンを表示させるか
        .setIntent(contentIntent)           <-- 対象となるActivityへのPendingIntentをセット
        .setDesiredHeight(600)              <-- Activityを表示するのに必要な高さ
        .setAutoExpandBubble(false)         <-- Bubblesを最初から開いた状態にするかどうか
        .setSuppressNotification(false)     <-- autoExpandBubble == trueのときこちらもtrueにセットする必要がある
        .build()
}

5. 通知にBubbleMetadataをセット

fun createSensorNotification(context: Context): Notification {
  return NotificationCompat
      .Builder(context, Channels.FURUFURU.channelId)
      .setSmallIcon(R.drawable.ic_send)
      .setContentTitle("Furufuru is running")
      .setContentIntent(contentIntent)
      .apply {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
              setBubbleMetadata(createBubbleMetaData(context, contentIntent))
          }
      }
      .build()
}

6. ローカル通知を送信

NotificationManagerCompat.from(context).notify(
    0,
    FurufuruNotification.createSensorNotification(applicationContext)
)

これだけ! 超簡単!

f:id:iaiaie:20201201195727g:plain
トクバイ上でBubblesを使ったFurufuruイメージ

実際に触ってみて

  • どんな機能に使えそうか?

実際にBubblesが使われるのはチャットアプリくらいになりそうです。
というのも通知として常駐することになる上、アイコンが画面に常駐することとなるので、(ユーザが位置を調整できるとはいえ) ユーザからは邪魔な機能として思われてしまいそうでした。

f:id:iaiaie:20201201195738p:plain
Bubblesが画面の要素に被ってしまう

そのデメリットを上回る『別のアプリを開いているときでもシームレスに使いたい機能』があれば使えるチャンスはありそう。

ぱっと思いつくのはメモ機能で、トクバイにもメモ機能があるのでもしかしたらBubblesに対応する日が来るかもしれません。

  • finish() させるとBubbles消える問題

Furufuruではバグレポートが完了したら finish() してActivityを閉じていましたが、Bubbles経由で起動したActivityを finish() してしまうとBubblesも一緒に消えてしまう問題が見つかりました。

チャットをBubblesで起動しているような場合は finish() せず、ユーザにバックキーで戻ってもらうのが確かに正しそうですが、Furufuruでそれをするのはひと手間増えて嫌なので誰か助けてほしい...。

  • (Bubblesとは厳密に関係ないんだけど) スクショタイミング大変問題

Furufuruはフォアグラウンドサービスとして『振る』動作に反応して、そのサービスの中でスクショを撮ってからバグレポート画面を表示するようにしているのですが、
通知から起動することを考えるとActivityがstopしたときに毎回スクショを撮るようにしています。これはちょっと辞めたい仕様なんですが、他の手段が思いつきませんでした。

まとめ

現状ではBubbles対応は様子見しておいた方が良さそうです。また、必要となる機能も少なさそうです。

デバッグメニューなどで使うのには便利そうなので、活用していきたいですね。

@社内のandroid10or11ユーザ 誰も使っていない疑惑があって悲しいのでフィードバックください...