算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

App Shortcuts 実装方法と実際の応用例

f:id:ngsw_taro:20161207211521p:plain:w400

一昨日くらいにAndroid 7.1.1のOTAが開始されましたね。 私のNexus5Xにも届いたので、早速インストールしました。

Android 7.1で目玉の機能となるのは、App Shortcutsなのではないでしょうか! ということで試してみました。 公式のAPIガイドを見てやれば、すごく簡単に実装できます!

App Shortcuts 概略

App Shortcutsは、欲しい情報にすぐにアクセスするための機能です。 ランチャーアイコンを長押しすることで、ショートカット一覧が表示されます。 ショートカットを押せば、そのアプリの特定の画面にすぐにたどり着けるというものです。

次の図のようなイメージです。 地図アプリのランチャーアイコンを長押しすると「Work」「Home」のショートカットが表示されます。 「Work」ショートカットを押すと単に地図アプリを起動するときとは異なり、現在地から職場までの道案内がすぐに始まります。

f:id:ngsw_taro:20161208111749p:plain:w400

動きの話をすると、各ショートカットはひとつのインテントを持っており、ショートカットが押されるとそのインテントが発行されるという仕組みです。

App Shortcutsにおいて、ショートカットには2種類あります。 静的ショートカットと動的ショートカットです。

静的ショートカットは、XMLでショートカットを定義してやる方法です。

一方、動的ショートカットは、プログラムコードで定義します。 「動的」の言葉のとおり、アプリの実行中に状況に応じてショートカットを追加、更新、削除が可能です。

静的ショートカット

XMLでショートカットをあらかじめ準備してやる方法です。 res/xmlの下にショートカット一覧を定義するXMLファイルを作成します。 ここではshortcuts.xmlという名前のファイルを作成します。 その内容は、下記が最小構成です。

<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="launch"
        android:shortcutShortLabel="@string/launcher_short">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.app"
            android:targetClass="com.example.app.MainActivity" />
    </shortcut>
</shortcuts>

ルートにshortcuts要素があり、その直下にいくつかのshortcut要素を含みます。 shortcut要素は、少なくともandroid:shortcutId, android:shortcutShortLabelの属性を持つ必要があるようです。

そしてshortcut要素はintent要素を持ちます。 ショートカットが押されたときに、このインテントが発行されます。 この例では、指定したアクティビティを起動するだけです。

次に、自分のアプリがショートカットを持っていることを知らせるためにAndroidManifest.xmlを編集します。 ランチャーから起動されるアクティビティ内に、meta要素を追加します。

<activity
    android:name=".MainActivity"
    android:label="@string/app_name">
    <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <meta-data
        android:name="android.app.shortcuts"
        android:resource="@xml/shortcuts" />
</activity>

これで静的ショートカットの準備は完了です。 ビルドして実行するとか、次のようにショートカットを確認できるはずです。

f:id:ngsw_taro:20161208120527p:plain:w400

shortcut要素にandroid:shortcutLongLabel属性とandroid:icon属性を追加してみます。

<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="launch"
        android:shortcutShortLabel="@string/launcher_short"
        android:shortcutLongLabel="@string/launcher_long"
        android:icon="@mipmap/ic_launcher">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.app"
            android:targetClass="com.example.comm.MainActivity" />
    </shortcut>
</shortcuts>

ビルドして実行すると、下記のように変わっています。

f:id:ngsw_taro:20161208121223p:plain:w400

ショートカット一覧に表示されるラベルがandroid:shortcutLongLabelに対応しているようです。 android:shortcutShortLabelはどこで使われるかと言うと、ショートカット一覧でショートカットを長押しすると、ショートカットをホーム画面に設置できるのですが、そのときのラベルに使用されます。

f:id:ngsw_taro:20161208121551p:plain:w200

ちなみに、ショートカットのアイコンですが、デザイン・ガイドライン(PDF)が提供されているので、それに従うべきでしょう(この例はダメダメなデザイン)。

今回、私が趣味で開発している「夢と魔法の待ち時間」では、次のように静的ショートカットを定義しています(一部、例示用に改変)。

<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="land"
        android:enabled="true"
        android:icon="@drawable/ic_land"
        android:shortcutShortLabel="@string/label_land_wait_time"
        android:shortcutLongLabel="@string/label_land_wait_time">
        <intent
            android:action="android.intent.action.VIEW"
            android:data="app://com.example.app/land_wait_time" />
    </shortcut>
    <shortcut
        android:shortcutId="sea"
        android:enabled="true"
        android:icon="@drawable/ic_sea"
        android:shortcutShortLabel="@string/label_sea_wait_time"
        android:shortcutLongLabel="@string/label_sea_wait_time">
        <intent
            android:action="android.intent.action.VIEW"
            android:data="app://com.example.app/sea_wait_time" />
    </shortcut>
</shortcuts>

f:id:ngsw_taro:20161207211521p:plain:w400

ショートカットを押すと、URLへのアクセスが起こり、アプリがこれをフックするという具合です。

動的ショートカット

動的ショートカットのみを提供する場合はXMLは不要です。 プログラムコードでショートカットを表現し、追加、更新、削除といった操作を行います。

重要なAPIShortcutInfoShortcutManagerです。 まずShortcutInfoでショートカットを表現します。

val shortcutInfo: ShortcutInfo = ShortcutInfo.Builder(context, "lastVisitedScreen")
    .setShortLabel(lastVisitedScreenShortName)
    .setLongLabel(lastVisitedScreenLongName)
    .setIcon(Icon.createWithResources(context, R.drawable.ic_history)
    .setIntent(Intent(Intent.ACTION_VIEW, lastVisitedScreenUri))
    .build()

上記のように、ShortcutInfo.Builderというビルダーのインスタンスを取得し、メソッドチェーンを形成しショートカットの設定をセットしていきます。 ちなみに、このコードはKotlinで記述しています。

次に、このshortcutInfoShortcutManagerを使って追加しましょう。 下記がそのコードです。

val shortcutManager: ShortcutManager = context.getSystemService(ShortcutManager::class.java)
shortcutManager.setDynamicShortcuts(listOf(shortcutInfo))

ショートカットの追加メソッドsetDynamicShortcutsと更新メソッドupdateShortcutsは、ShortcutInfoのリストを受け取るので、Kotlin標準関数listOfでリストにしています。 削除メソッドremoveDynamicShortcutsは、文字列(ショートカットID)のリストを受け取ります。

「夢と魔法の待ち時間」では、動的ショートカットを使って、最後に表示した画面へのショートカットを提供しています。 これは静的ショートカットでは実現できない機能です。

f:id:ngsw_taro:20161207211525p:plain:w400

星のアイコンのショートカットが、最後に表示した画面へのショートカットです。

まとめ

  • Android 7.1.1の配信が始まりました
  • App Shortcutsはショートカットを提供する機能でAndroid 7.1で導入されました
  • ショートカットには静的ショートカットと動的ショートカットがあります
  • 静的ショートカットは、XMLで事前に定義しておきます
  • 動的ショートカットは、プログラムで動的に定義します

Androidでの体験がより便利になりそうですね!!!!

さらにApp Shortcutsを学びたい人は公式のAPIガイドを参照してください。