Androidその2 Advent Calendar 2016の4日目の記事です。
Android 7.1のAppShortcutsを紹介します。
App Shortcutsとは
App ShortcutsとはAndroid 7.1で追加されたアプリ内機能のショートカットを作成できる機能です。
アプリアイコンを長押しすると表示されるショートカットからアプリ内の各機能にアクセスできます。
ショートカットはコピーしてランチャーにピン止めしておくこともできます。
利用頻度が高い機能をショートカットに追加しておくと機能へ即座にアクセスできるようになって便利です。
ショートカット一覧 | ショートカットのピン留め |
---|---|
ちなみにGoogleのアプリ以外だとTwitter、Talon(Tiwtterクライアント)等はすでに対応しているのでGooglePlayから落として動作をみてみると良いかもしれません。
App Shortcutsの種類
ショートカットには2つの種類があります。
Static Shortcuts
静的なショートカットでxmlにショートカットの設定を記述しショートカットを表示します。
動的にショートカットの更新や削除等は出来ず、変更するにはアプリのアップデートが必要です。
(動的に削除しようとすると落ちます。。)
Dynamic Shortcuts
動的なショートカットでStaticShortcutsと違いコード上からショートカットの追加・削除・更新等が可能です。
動的に追加できるのでユーザーがよくアクセスするページをショートカットに追加したり、ユーザーにショートカットを選ばせたりいろいろな使い方ができそうです。
Static Shortcutsを実装する
ショートカットの設定ファイルを用意
表示するショートカットの設定を記述したxmlファイルを res/xml
に配置します。
shortcuts
内に表示するショートカットを記述していきます。
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<!-- ショートカットのID・アイコン・文言等を設定 -->
<shortcut
android:icon="@mipmap/ic_launcher"
android:shortcutId="first_shortcut"
android:shortcutShortLabel="@string/short_label">
<!-- 遷移先 -->
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.kuwapp.myshortcutsample"
android:targetClass="com.kuwapp.myshortcutsample.MainActivity" />
</shortcut>
</shortcuts>
AndroidManifest.xmlにショートカットの設定ファイルを指定
intent-filterにandroid.intent.action.MAIN
とandroid.intent.category.LAUNCHER
を持つActivityのmeta-data要素にショートカットの設定ファイルを指定します。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kuwapp.myshortcutsample">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<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>
</application>
</manifest>
これだけでショートカットが表示されるはずです。
shortcut要素に記述できる属性
|属性|説明|
|---|---|---|
|android:shortcutId| shortcutを識別するためのID 必須|
|android:enabled| 有効、無効のフラグ 初期値はtrue |
|android:shortcutShortLabel| ピンされたアイコンのタイトル文言 |
|android:shortcutLongLabel| ランチャーアイコン長押し時に表示されるショートカットの文言 (定義されていない場合ShortLabelが使われる) |
|android:shortcutDisabledMessage| 無効なピン留めされたショートカットがタップされたタイミングで表示される文言 |
Dynamic Shortcutsを実装する
DynamicShortcutsの追加
ShortcutManager
クラスのaddDynamicShortcuts
またはsetDynamicShortcuts
メソッドを使用します。
どちらのメソッドでもDynamicShortcutsは追加できますが、違いとしてaddDynamicShortcuts
は既存のDynamicShortcutsのリストに新たなDynamicShortcutsを追加するのに対してsetDynamicShortcuts
は既存のDynamicShortcutsのリストを新しいDynamicShortcutsに置き換えます。
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
// Actionを設定しないと落ちる
intent.setAction(Intent.ACTION_DEFAULT);
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, id)
.setShortLabel(getString(R.string.short_label))
.setIntent(intent)
.build();
shortcutManager.addDynamicShortcuts(Collections.singletonList(shortcutInfo));
DynamicShortcutsの削除
ShortcutManager
クラスのremoveAllDynamicShortcuts
またはremoveDynamicShortcuts
メソッドを使用します。
メソッド名から推測できる通り、removeAllDynamicShortcuts
は全てのDynamicShortcutsを削除し、removeDynamicShortcuts
は単一のDynamicShortcutsを削除します。
removeDynamicShortcuts
の引数には削除するDynamicShortcutsのIDを指定します。
// 削除するDynamicShortcutのIDを指定
shortcutManager.removeDynamicShortcuts(removeShortcutIdList);
DynamicShortcutsの更新
ShortcutManager
クラスのupdateShortcuts
メソッドを使用します。
// 更新するShortcutと同一のIDを指定
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, id)
.setShortLabel(getString(R.string.short_label))
.setIntent(intent)
.build();
shortcutManager.updateShortcuts(Collections.singletonList(shortcutInfo));
ショートカットを無効にする
ショートカットを無効にした場合、一覧から表示されなくなり、ピン留していたアイコンはグレーアウトしてタップしても動作しません。
タップ時はdisabledMessage
で指定した文言がトーストで表示されます。
ピン留めされたショートカットは無効にできますが、コードから動的に削除することはできません。
Static Shortcuts
android:enabled
属性をfalseにすることで無効になります。
無効時に表示されるメッセージはandroid:shortcutDisabledMessage
で指定します。
Dynamic Shortcuts
ShortcutManager
クラスのdisableShortcuts
メソッドを呼び出します。
引数にはdisableにするショートカットのIDを指定します。
shortcutManager.disableShortcuts(disableShortcutIds);
無効時に表示されるメッセージはShortcutInfo
作成時にsetDisabledMessage
メソッドで指定します。
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, id)
.setShortLabel(getString(R.string.short_label))
.setIntent(intent)
.setDisabledMessage(getString(R.string.disable_message))
.build();
TIPSやはまったことなど
ショートカットが表示されない
以下の場合にショートカットが表示されませんでした。
-
android:shortcutId
が別のショートカットと重複している -
android:shortcutId
にstringリソースを指定している -
android:action
を指定していない
バックスタックに別のActivity積んだ上で遷移させたい
ActivityBに遷移させてバックキー押下時にAcitivtyAを表示させたいような場合は複数のIntentを指定します。
(ActivityA->ActivityBのように積まれている)
StaticShortcuts
<shortcut
android:icon="@mipmap/ic_launcher"
android:shortcutId="shortcut"
android:shortcutShortLabel="@string/short_label">
<!-- バックスタックに積みたいActivityの数だけintentを追加する 一番下に記述したintentが一番上に積まれる -->
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.kuwapp.myshortcutsample"
android:targetClass="com.kuwapp.myshortcutsample.MainActivity" />
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.kuwapp.myshortcutsample"
android:targetClass="com.kuwapp.myshortcutsample.SecondActivity" />
</shortcut>
DynamicShortcuts
ShortcutInfo
のインスタンス生成時にsetIntents
メソッドの引数に複数のIntentを指定します。
Intent[] intents = // 略
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(this, id)
.setShortLabel(getString(R.string.short_label))
.setIntents(intents)
.build();
StaticShortcutsを使用していてビルド時にパッケージ名を動的に変更しているときの対応
複数のAPKを共存させるためにビルド時にパッケージ名を変更している場合(debugとrelease版など)はStaticShortcutsのintent要素に追加するandroid:targetPackage
も同時に変更しなければなりません。
アプローチとしては以下が考えられると思います。
- パッケージ名の数だけショートカットの設定ファイルを作成しておく
- BuildTypeやFlavorが増える毎にほぼ同内容の設定ファイルを追加しなければならない
- ビルド時に動的に設定ファイルを書き換えるGradleのタスク等を作る
- 一度作ってしまえば楽だが、少し手間がかかる
- Static ShortcutsをやめDynamic Shortcutsを使用する
- 単に置き換えるだけなので容易
Dynamic Shortcutsへの移行は容易なので自分はDynamicShortcutsを使用することにしました。
異なるショートカットから同一のActivityへ遷移させるが、ショートカット毎に振る舞いを変えたい
異なるショートカットから同一のActivityへ遷移させ表示内容を変えたいときなどはIntentのActionかExtraに値を入れておいてそれを見て処理を変えることで実現できます。
Static Shortcutsなら以下のようにandroid:action
に独自アクションを入れるかintent要素内にextraを記述して起動側で受け取るようにすればどのショートカットからきたか分かります。
<intent
android:action="com.kuwapp.Intent.MAIN"
android:targetClass="com.kuwapp.appshortcutssample.MainActivity"
android:targetPackage="com.kuwapp.appshortcutssample">
<extra android:name="Shortcut" android:value="Main" />
</intent>
以下のようにAction or extraを取り出しどのショートカットからきたか判断して処理を変えれば良いです。
String action = getIntent().getAction();
String extra = getIntent().getStringExtra("Shortcut");
おわりに
AppShortcutsを実装してみました。現在Android7.1でしか使えませんが、実装は非常に容易であると同時に便利な機能なので入れてみても良いと思います。(いつかminSdkVersionが25になれば良いなあ・・・)
個人的にはDynamic Shortcutsの方が柔軟性があるのであえてStatic Shortcutsを使う意味があるのだろうかと思ったり。