ショートカットの管理

ショートカットを作成すると、アプリの全期間にわたってショートカットを管理する必要が生じる場合があります。たとえば、アプリを最適化するため、ユーザーがショートカットを使用して特定のアクションを行う頻度を測定する場合などです。また、固定ショートカットを無効にして、アプリが古くなったアクションや存在しなくなったアクションを実行しないようにする場合もあります。このガイドでは、上記をはじめ、ショートカットを管理する一般的な方法について説明します。

ショートカットの動作

ここでは、ショートカットの動作(表示、表示順序、ランク)に関する一般的な情報について説明します。

ショートカットの表示

セキュリティに関する注意事項: すべてのショートカット情報は認証情報が暗号化されたストレージに保存されるため、デバイスがロック解除されるまで、アプリはユーザーのショートカットにアクセスできません。

静的ショートカットと動的ショートカットは、ユーザーが特定の操作や音声コマンドを実行したときに、サポートされているランチャーまたはアシスタントに表示されます。サポートされているランチャーの場合、この操作はアプリのランチャー アイコンの長押しですが、他のランチャー アプリの場合は実際の操作がこれと異なる場合があります。Google アシスタントを使用すると、ショートカットをアシスタント内に表示したり、ユーザーの音声コマンドで起動したりできます。

LauncherApps クラスは、ランチャー アプリがショートカットにアクセスするための API を提供します。

固定ショートカットはランチャー自体に表示されるため、常にユーザーの目に入ります。固定ショートカットは、以下の場合にのみ、ランチャーから削除されます。

  • ユーザーが削除した。
  • ショートカットに関連付けられているアプリがアンインストールされた。
  • ユーザーが [設定] > [アプリと通知] でアプリを選択し、[ストレージ] > [ストレージを消去] をクリックしてアプリのデータを消去した。

ショートカットの表示順序

ランチャーがアプリのショートカットを表示する際は、次の順序で表示します。

  1. 静的ショートカット: isDeclaredInManifest() メソッドが true を返すショートカット。
  2. 動的ショートカット: ShortcutInfo.isDynamic() メソッドが true を返すショートカット。

同じ種類(静的または動的)の中では、ショートカットは ShortcutInfo.getRank() に従って、ランクの昇順で並べられます。Google アシスタントは、ユーザーに表示する状況依存のショートカットを決定する際に、ショートカットのランクも考慮します。

ランクは、負ではない連続した整数です。 updateShortcuts(Context, List) addDynamicShortcuts(Context, List) setDynamicShortcuts(Context, List) のいずれかを呼び出すと、既存のショートカットのランクを更新できます。

注: ランクは、ショートカットの種類(静的または動的)ごとに一意になるように自動調整されます。たとえば、動的ショートカットが 3 つあり、それぞれのランクが 0、1、2 である場合、ランク 1 の別の動的ショートカットを追加すると、このショートカットを 2 番目に配置するようにリクエストしたことになります。これに応じて、3 番目と 4 番目のショートカットがショートカット リストの下位に移動し、それぞれのランクが 2 と 3 に変更されます。

複数のインテントとアクティビティを管理する

ユーザーがショートカットを選択したときにアプリで複数のオペレーションを実行する場合は、連続したアクティビティをトリガーするように設定できます。そのためには、ショートカットの種類に応じて、複数のインテントを割り当てるか、アクティビティから別のアクティビティを開始するか、インテント フラグを設定するかのいずれかを行います。

複数のインテントを割り当てる

ShortcutInfoCompat.Builder を使用してショートカットを作成する場合、 setIntent() の代わりに setIntents() を使用できます。setIntents() を呼び出すことで、ユーザーがショートカットを選択したときにアプリ内で複数のアクティビティを起動し、最後のアクティビティ以外のすべてをバックスタックのリストに配置できます。その後、ユーザーがデバイスの戻るボタンを押すと、デバイスのランチャーに戻る代わりに、アプリの別のアクティビティが表示されます。

注: ユーザーがショートカットを選択して [戻る] キーを押すと、リソース ファイル内のショートカットの最後から 2 番目のインテントに対応するアクティビティがアプリによって起動されます。この動作パターンは、ショートカットが作成したバックスタックをユーザーが消去するまで、戻るボタンが押されるたびに繰り返し行われます。次にユーザーが戻るボタンを押すと、ランチャーに戻ります。

アクティビティから別のアクティビティを開始する

静的ショートカットにカスタム インテント フラグを含めることはできません。 静的ショートカットの最初のインテントには、常に Intent.FLAG_ACTIVITY_NEW_TASK Intent.FLAG_ACTIVITY_CLEAR_TASK を設定します。つまり、アプリがすでに実行中の場合、静的ショートカットが起動されると、アプリ内の既存のアクティビティはすべて破棄されます。この動作が望ましくない場合は、トランポリン アクティビティを使用できます。これは、 Activity.onCreate(Bundle) で別のアクティビティを開始してから Activity.finish() を呼び出す非表示のアクティビティです。

  1. AndroidManifest.xml ファイルで、トランポリン アクティビティに android:taskAffinity="" 属性割り当てを含める必要があります。
  2. ショートカットのリソース ファイルで、静的ショートカット内のインテントがトランポリン アクティビティを参照する必要があります。

トランポリン アクティビティの詳細については、アクティビティから別のアクティビティを開始するをご覧ください。

インテント フラグを設定する

動的ショートカットは、Intent フラグの任意のセットを使用して公開できます。可能であれば、 Intent.FLAG_ACTIVITY_CLEAR_TASK を他のフラグと一緒に指定することをおすすめします。そうしなかった場合、アプリの実行中に別のタスクを開始しようとすると、ターゲット アクティビティが表示されない可能性があります。

タスクとインテント フラグの詳細については、タスクとバックスタックのガイドをご覧ください。

ショートカットを更新する

各アプリのランチャー アイコンには、静的ショートカットと動的ショートカットを組み合わせて getMaxShortcutCountPerActivity() の数まで含めることができます。ただし、アプリで作成できる固定ショートカットの数は無制限です。

動的ショートカットが固定されている場合、パブリッシャーがそれを動的ショートカットとして削除しても、固定ショートカットは引き続き表示され、起動可能です。これにより、アプリは getMaxShortcutCountPerActivity() の数を超えるショートカットを持つことができます。

たとえば、getMaxShortcutCountPerActivity() が 4 であるとします。

  1. あるチャットアプリが、最新の 4 つのスレッド(c1、c2、c3、c4)を表す 4 つの動的ショートカットを公開します。
  2. ユーザーが 4 つのショートカットをすべて固定します。
  3. その後、ユーザーが追加のスレッド(c5、c6、c7)を 3 つ開始したため、公開元アプリは動的ショートカットを再公開します。新しい動的ショートカット リストは c4、c5、c6、c7 になります。

    アプリは 4 つを超える動的ショートカットを表示できないため、c1、c2、c3 を削除する必要が生じます。ただし、c1、c2、c3 は、依然としてユーザーがアクセスして起動できる固定ショートカットのままです。

    これで、ユーザーは、公開元アプリのアクティビティにリンクする合計 7 つのショートカットを利用できるようになりました。この合計数には、最大数のショートカットと 3 つの固定ショートカットが両方とも含まれているからです。

  4. アプリは updateShortcuts(Context, List) を使用して、既存の 7 つのショートカットのいずれも更新できます。たとえば、チャット相手のアイコンが変更されたときに、このショートカット セットを更新できます。
  5. addDynamicShortcuts(Context, List) メソッドと setDynamicShortcuts(Context, List) メソッドを使用して、同じ ID を持つ既存のショートカットを更新することもできます。ただし、この 2 つは、指定されたリストのショートカットを動的ショートカットに変換しようとするため、動的でない固定ショートカットの更新には使用できません

プッシュして Google アシスタントなどのアシスタント アプリに表示できるショートカットの数に制限はありません。アシスタント アプリで使用するショートカットを作成、更新するには、ShortcutManagerCompat Jetpack ライブラリの pushDynamicShortcut() メソッドを使用します。また、Google アシスタントにダイナミック リンクを表示するには、Google Shortcuts Integration Library もアプリに追加する必要があります。

ショートカットの更新など、アプリのショートカットのガイドラインについては、おすすめの方法をご覧ください。

システム ロケールの変更を処理する

アプリは、システム ロケールが変更されたことを示す Intent.ACTION_LOCALE_CHANGED ブロードキャストを受信したときに、動的ショートカットと固定ショートカットを更新する必要があります。

ショートカットの使用状況をトラッキングする

静的ショートカットと動的ショートカットが表示される状況を判別するために、ランチャーはショートカットの使用履歴を調べます。静的ショートカットの場合、次のいずれかのイベントが発生した際に、 reportShortcutUsed() メソッドを呼び出してショートカットの ID を渡すことにより、ユーザーがアプリ内で特定のアクションを完了したタイミングをトラッキングできます。

  • ユーザーが特定の ID のショートカットを選択した。
  • アプリ内で、ユーザーが同じショートカットに対応するアクションを手動で完了した。

動的ショートカットの使用をトラッキングするには、関連するイベントが発生した際に、pushDynamicShortcut() メソッドを呼び出してショートカットの ID を渡します。このメソッドで動的ショートカットの使用をプッシュすると、Google アシスタントなどのアシスタント アプリが関連のショートカットをユーザーに提案できるようになります。pushDynamicShortcut() メソッドを呼び出すことで使用状況が報告されるため、同じショートカットに対してさらに reportShortcutUsed() メソッドを呼び出さないようにします。

注: アプリからプッシュするダイナミック リンクが Google アシスタントなどの Google サーフェスに表示されるようにするには、Google Shortcuts Integration Library が必要です。このライブラリをアプリに追加することで、アシスタントがダイナミック リンクを取り込んで、ユーザーに提案できるようになります。

ショートカットを無効にする

アプリとそのユーザーはショートカットをデバイスのランチャーに固定できるため、固定ショートカットによって、アプリ内の古くなったアクションまたは存在しなくなったアクションにユーザーが誘導されることがあります。この状況に対処するには、 disableShortcuts() を呼び出して、ユーザーに選択させたくないショートカットを無効にします。これにより、指定したショートカットが静的ショートカットと動的ショートカットのリストから削除され、対応する固定ショートカットが無効になります。このメソッドのオーバーロード版を使用することもできます。これは、CharSequence をカスタムエラー メッセージとして受け入れます。ユーザーが無効なショートカットを起動しようとすると、そのエラー メッセージが表示されます。

注: アプリの更新時にアプリの静的ショートカットの一部を削除すると、それらのショートカットは自動的に無効化されます。

レート制限

setDynamicShortcuts() addDynamicShortcuts() updateShortcuts() のいずれかのメソッドを使用する場合、バックグラウンド アプリ(現在フォアグラウンドで動作しているアクティビティまたはサービスがないアプリ)では、これらのメソッドを特定の回数しか呼び出せない可能性があるため、ご注意ください。これらのメソッドを呼び出すことができる回数の制限は、レート制限と呼ばれます。この機能は、ShortcutManagerCompat がデバイス リソースを過剰に消費することを防ぐためのものです。

レート制限が有効になっている場合、 isRateLimitingActive() は true を返します。ただし、レート制限は特定のイベントでリセットされるため、バックグラウンド アプリであっても、レート制限に再び達するまで ShortcutManager メソッドを呼び出すことができます。そうしたイベントには、次のようなものがあります。

  • アプリがフォアグラウンドに復帰した。
  • システム ロケールが変更された。
  • ユーザーが通知に対してインライン返信アクションを実行した。

開発中またはテスト中にレート制限が発生した場合は、デバイスの設定から [開発者向けオプション] > [ShortcutManager のレート制限をリセット] を選択するか、adb で次のコマンドを入力します。

$ adb shell cmd shortcut reset-throttling [ --user your-user-id ]

バックアップと復元

アプリのマニフェスト ファイルに android:allowBackup="true" 属性割り当てを含めると、ユーザーがデバイスを変更する際にアプリでバックアップと復元を行えるようになります。バックアップと復元を可能にする場合は、アプリのショートカットについて次の点に注意してください。

  • 静的ショートカットは自動的に再公開されますが、ユーザーが新しいデバイスにアプリを再インストールした場合に限られます。
  • 動的ショートカットはバックアップされないため、ユーザーが新しいデバイスでアプリを開いたときに動的ショートカットを再公開するには、アプリにそのためのロジックを組み込む必要があります。
  • 固定ショートカットはデバイスのランチャーに自動的に復元されますが、固定ショートカットに関連付けられたアイコンはバックアップされません。そのため、固定ショートカットの画像をアプリに保存して、新しいデバイスで簡単に復元できるようにする必要があります。

次のコード スニペットは、アプリの動的ショートカットを復元する最適な方法と、アプリの固定ショートカットが保持されたかどうかを確認する方法を示しています。

Kotlin

class MyMainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (ShortcutManagerCompat.dynamicShortcuts.size == 0) {
            // Application restored. Need to re-publish dynamic shortcuts.
            if (ShortcutManagerCompat.pinnedShortcuts.size > 0) {
                // Pinned shortcuts have been restored. Use
                // updateShortcuts() to make sure they contain
                // up-to-date information.
            }

        }
    }
    // ...
}

Java

public class MainActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (ShortcutManagerCompat.getDynamicShortcuts().size() == 0) {
            // Application restored. Need to re-publish dynamic shortcuts.
            if (ShortcutManagerCompat.getPinnedShortcuts().size() > 0) {
                // Pinned shortcuts have been restored. Use
                // updateShortcuts() to make sure they contain
                // up-to-date information.
            }
        }
    }
    // ...
}

参考情報

Android AppShortcuts サンプルは、このページで取り上げたワークフローの使用方法をさらに詳しく示しています。