1. ホーム
  2. Android

Android O (8.0) デスクトップショートカットを作成する

2022-02-13 12:10:15
<パス

インラインプッシュ

<ブロッククオート

[長期有効】Byte Jump Meチームへの参加を歓迎します。 インサイダーリンク

Android Oの正式リリースが間近に迫り、同社のアプリもAndroid Oに対応し始めています。テストで、Android Oのネイティブデスクトップでは、従来のショートカットの作成形式通りにショートカットが作成されないことが判明しました。

追記:以下の例のソースコードについては、https://github.com/OptimusPrimeRen/AndroidOShortcut を参照してください。


従来のやり方は以下の通りです。

public static final String ACTION_ADD_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";

public void addShortcutBelowAndroidN(Context context) {
    Intent addShortcutIntent = new Intent(ACTION_ADD_SHORTCUT);

    // duplicate creation is not allowed, not based on the name of the shortcut to determine the duplicate
    addShortcutIntent.putExtra("duplicate", false);

    addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Shortcut Name");

    //Icons
    addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(context, R.mipmap.ic_ shortcut));

    // Set the associated application
    Intent launcherIntent = new Intent();
    launcherIntent.setClass(context, ShortcutActivity.class);
    addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, launcherIntent);

    // Send a broadcast
    context.sendBroadcast(addShortcutIntent);
}



ShortcutManager

Android 7.1 (API 25) より、デスクトップ上のアプリアイコンを押してポップアップしたショートカットを管理するためのShortcutManagerが追加されました。使い方は、Loader's Blogのこちらの記事をご参照ください。http://blog.csdn.net/qibin0506/article/details/52878690

しかし、Android 7.1では、デスクトップに直接ショートカットを追加する(例えば、360 Cleanupは、デスクトップにメモリをクリーンアップするショートカットを追加する)には、まだ上記の古い方法が使われていますが、Android Oでは、Googleは、より統一したインターフェースでデスクトップショートカットを管理したいはずなので、この形態をやめ、ShortcutManagerで管理することにしているのです。そこでAPI 26では、ShortcutManagerにPinned Shortcutsの管理を追加しました。
まちかど博物館の公式記事:https://developer.android.com/reference/android/content/pm/ShortcutManager.html
壁を乗り越えられない人のために、以下で該当するセレクションを傍受しています。

公式テキストです。
アプリは、requestPinShortcut(ShortcutInfo, IntentSender) を使用して、既存のショートカット(静的または動的)または全く新しいショートカットをサポートされているランチャーにプログラムで固定することができます。このメソッドには、2 つの引数を渡します。

ShortcutInfo オブジェクト - ショートカットがすでに存在する場合、このオブジェクトにはショートカットの ID だけが含まれている必要があります。ShortcutInfo オブジェクトには、ID、インテント、および新しいショートカットの短いラベルを含める必要があります。
PendingIntent オブジェクト - このインテントは、ショートカットがデバイスのランチャーに正常に固定された場合に、アプリが受け取るコールバックを表します。

注: ユーザーがショートカットをランチャーにピン留めすることを許可していない場合、ピン留め処理は失敗し、この PendingIntent オブジェクトに渡される Intent オブジェクトは実行されません。 ユーザーがショートカットをランチャーにピン留めすることを許可していない場合、ピン留め処理は失敗し、この PendingIntent オブジェクトに渡される Intent オブジェクトは実行されません。

注: Android O で導入されたバックグラウンド実行の制限により、コールバックを受け取るにはマニフェストで宣言されたレシーバーを使用するのが最善です。
また、他のアプリが Receiver を呼び出さないようにするため、Receiver のマニフェスト項目に属性 assignment android:exported="false" を追加してください。

注: ショートカットの固定を要求するロジックをアプリに追加する場合、すべてのランチャーがショートカットの固定をサポートしていないことに留意してください。あなたのアプリが特定のデバイス上でこの処理を完了できるかどうかを判断するには、isRequestPinShortcutSupported() の戻り値を確認します。この戻り値に基づいて、ユーザーがショートカットを固定できるようにするアプリのオプションを非表示にすることを決定することができます。

注:サポートライブラリ API の isRequestPinShortcutSupported(Context) および requestPinShortcut(Context, ShortcutInfoCompat, IntentSender) も参照してください。これは、非推奨の private intent com.android.launcher.action.INSTALL_ SHORTCUT にフォールバックして Android バージョン O より低いところで機能します。

翻訳してください。
アプリケーションは、requestPinShortcut (ShortcutInfo, IntentSender) を使用して、既存のショートカット(静的または動的)またはサポートされているランチャーへの新規ショートカットを修正することが可能です。このメソッドには、2つのパラメータを使用します。

ShortcutInfo オブジェクト - ショートカットが既に存在する場合、このオブジェクトにはショートカットの ID だけが含まれていなければなりません。そうでない場合、新しい ShortcutInfo オブジェクトには新しいショートカットの ID、インテント、ショートラベルが含まれている必要があります。
PendingIntent オブジェクト - このインテントは、ショートカットがデバイスのランチャーに正常にピン留めされた場合に、アプリがコールバックを受け取ることを意味します。

注意:ユーザーがショートカットをランチャーにピン留めすることを許可していない場合、ピン留め処理は失敗し、この PendingIntent オブジェクトに渡された Intent オブジェクトは実行されません。

注意:Android Oで導入されたバックグラウンド実行の制限のため、コールバックを受け取るにはリスト宣言されたレシーバーを使用するのが最適です。
また、他のアプリが受信機を呼び出さないように、受信機のマニフェスト項目に属性割り当て android: exported = "false" を追加してください。

注意: ショートカットを起動するロジックをアプリに追加する場合、すべてのランチャーが固定ショートカットをサポートしているわけではないことに留意してください。あなたのアプリが特定のデバイス上でこれを行うことができるかどうかを判断するには、isRequestPinShortcutSupported() の戻り値を確認してください。この返り値に基づいて、ユーザーがショートカットを固定できるようにするアプリのオプションを非表示にすることを決定できます。

注:サポートライブラリAPI isRequestPinShortcutSupported (Context) および requestPinShortcut (Context, ShortcutInfoCompat, IntentSender) も参照してください。これらはO run以下のAndroidバージョンで使用できますが、推奨されないプライベートインテント com.android.launcher.action.INSTALL_SHORTCUT にフォールバックするためです。

APIレベル26のShortcutManagerクラスに、isRequestPinShortcutSupported, requestPinShortcut, createShortcutResultIntentの3つのメソッドが追加されました。その説明は以下の通りです。

1. isRequestPinShortcutSupported (リクエストピンショートカットサポート)

公式テキストです。
デフォルトのランチャーがrequestPinShortcut(ShortcutInfo, IntentSender)をサポートしているデバイスでアプリが動作している場合、TRUEを返します。

ユーザーがデフォルトのランチャーアプリを変更した場合、その後の呼び出しで戻り値が変更される可能性があります。

注:レガシーなプライベートインテント com.android.launcher.action.INSTALL_SHORTCUT を使用して O より低い Android バージョンをサポートする、サポートライブラリ対応部分 isRequestPinShortcutSupported(Context) も参照してください。

翻訳してください。
デフォルトのデスクトップがrequestPinShortcut (ShortcutInfo, IntentSender) メソッドをサポートしている場合、TRUEを返します。

ユーザーがデフォルトのランチャーアプリケーションを変更した場合、その後の呼び出しで戻り値が変更される可能性があります。

注:Android O以下のバージョンで古いプライベートインテント com.android.launcher.action.INSTALL_SHORTCUT の使用をサポートするサポートライブラリ対応物 isRequestPinShortcutSupported (Context) も参照してください。

2. requestPinShortcut

公式テキストです。
デフォルトのランチャーはこのリクエストを受信し、ユーザーに承認を求めます。ユーザーが承認した場合、ショートカットが作成され、resultIntent が送信されます。しかし、ユーザーによってリクエストが拒否された場合、呼び出し元には何も応答が送信されません。

フォアグラウンドアクティビティまたはフォアグラウンドサービスを持つアプリのみが、このメソッドを呼び出すことができます。そうでない場合は、IllegalStateExceptionをスローします。

同じパッケージがこの API を連続して複数回呼び出した場合、以前の保留中のリクエストをどのように処理するかは、ランチャー次第です。

注: サポートライブラリの対応する requestPinShortcut(Context, ShortcutInfoCompat, IntentSender) も参照してください。これは、レガシープライベートインテント com.android.launcher.action.INSTALL_SHORTCUT を使用して、Android バージョン O より低いバージョンをサポートします。

翻訳してください。
固定ショートカットの作成依頼。デフォルトのイニシエータはリクエストを受信し、ユーザーに承認を求めます。ユーザーが承認した場合、ショートカットが作成され、resultIntentが送信されます。しかし、ユーザーによってリクエストが拒否された場合、呼び出し側には何も応答が送信されません。

フォアグラウンドアクティビティまたはフォアグラウンドサービスを持つアプリケーションのみが、このメソッドを呼び出すことができます。そうでない場合は、IllegalStateExceptionをスローします。

本 API が同一パッケージから連続して複数回呼び出された場合、以前の保留中のリクエストをどのように処理するかは、開発者の判断に委ねられます。ひとつの方法として、以前のリクエストを無視することも可能です。

注:サポートライブラリの対応する requestPinShortcut (Context, ShortcutInfoCompat, IntentSender) も参照してください。これは、Android バージョン O より下では、古い private intent com.android.launcher.action. install_shortcut の使用をサポートしています。

3. createShortcutResultIntent

公式テキストです。
与えられた ShortcutInfo を含むショートカットをピン留めするために、デフォルトのランチャーで使用できる Intent を返します。このメソッドは、ACTION_CREATE_SHORTCUTに応答して結果を設定するActivityによって使用される必要があります。

翻訳してください。
与えられた ShortcutInfo を含むショートカットを修正するために、デフォルトのランチャーが使用できる Intent を返します。Activityは、このメソッドを使用して、応答ACTION_CREATE_SHORTCUTの結果を設定する必要があります。


公式の説明を読んだら、実践してみましょう。

コード

@RequiresApi(api = Build.VERSION_CODES.O)
public static void addShortCut(Context context) {
    ShortcutManager shortcutManager = (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);

    if (shortcutManager.isRequestPinShortcutSupported()) {
        Intent shortcutInfoIntent = new Intent(context, ShortcutActivity.class);
        shortcutInfoIntent.setAction(Intent.ACTION_VIEW); //action must be set, otherwise an error is reported

        ShortcutInfo info = new ShortcutInfo.Builder(context, "The only id")
                .setIcon(Icon.createWithResource(context, R.mipmap.ic_shortcut))
                .setShortLabel("Short Label")
                .setIntent(shortcutInfoIntent)
                .build();

        //When the confirmation popup box for adding a shortcut pops up, it will be called back
        PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, MyReceiver.class), PendingIntent.FLAG_ UPDATE_CURRENT);

        shortcutManager.requestPinShortcut(info, shortcutCallbackIntent.getIntentSender());
    }

}


Android Oエミュレーター上で、このメソッドを呼び出した後、システムは図のようなプロンプトボックスをポップアップ表示します。

ポップアッププロンプトからわかるように、このアイコンをドラッグすることでデスクトップにショートカットを追加できます。「自動追加」ボタンをクリックすると、デスクトップ上のデフォルトの位置が表示されます。
追加されると、以下の画像のようにデスクトップ上にアイコンが表示されます。

ははは、ショートカットアイコンの右下にアプリアイコンが追加されますよ。

コールバックに使用するReceiverです。

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive: ");
    }
}


ログを印刷すると、公式記事にあるように、ポップアップボックスの自動追加ボタンをクリックした後にonReceiveがコールバックを取得していることがわかります。しかし実際には、このアイコンを既にデスクトップに追加している場合、追加するためにrequestPinShortcutが再度呼ばれると、onReceiveが直接呼び戻されて、ポップアップボックスがポップアップしてしまいます。

PS: 市販のサードパーティ製デスクトップでより人気のあるものを使用すると、デスクトップ側が適応されない場合、requestPinShortcutメソッド呼び出しではポップアップボックスとonReceiveコールバックが表示されません。


ShortcutManagerCompat

上記3つの方法の公式な紹介の中で、ショートカットのバージョン適応にAndroidサポートライブラリのShortcutManagerCompatを使用することが公式に促されています。そこで、build.gradleに依存関係を追加して試してみます。

compile 'com.android.support:appcompat-v7:26.+'

public static void addShortCutCompact(Context context) {
    if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
        Intent shortcutInfoIntent = new Intent(context, ShortcutActivity.class);
        shortcutInfoIntent.setAction(Intent.ACTION_VIEW); //action must be set, otherwise an error is reported

        ShortcutInfoCompat info = new ShortcutInfoCompat.Builder(context, "The only id")
                .setIcon(R.mipmap.ic_shortcut)
                .setShortLabel("Short Label")
                .setIntent(shortcutInfoIntent)
                .build();

        //When the confirmation popup box for adding a shortcut pops up, it will be called back
        PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, MyReceiver.class), PendingIntent.FLAG_ UPDATE_CURRENT);
        ShortcutManagerCompat.requestPinShortcut(context, info, shortcutCallbackIntent.getIntentSender());
    }
}



public static boolean isRequestPinShortcutSupported(@NonNull Context context) {
    if (BuildCompat.isAtLeastO()) {
        return ShortcutManagerCompatApi26.isRequestPinShortcutSupported(context);
    }
    
    if (ContextCompat.checkSelfPermission(context, INSTALL_SHORTCUT_PERMISSION)
        ! = PackageManager.PERMISSION_GRANTED) {
        return false;
    }
    for (ResolveInfo info : context.getPackageManager().queryBroadcastReceivers(
            new Intent(ACTION_INSTALL_SHORTCUT), 0)) {
        String permission = info.activityInfo.permission;
        if (TextUtils.isEmpty(permission) || INSTALL_SHORTCUT_PERMISSION.equals(permission)) { if (TextUtils.isEmpty(permission) || INSTALL_SHORTCUT_PERMISSION.equals(permission)) {
            return true;
        }
    }
    return false;
}


その後、Android O エミュレータで動かしてみたところ、うまくいかなかったので、Debug でフォローしたところ、ShortcutManagerCompat.isRequestPinShortcutSupported が false を返してきたので、ソースコードでフォローし実装したところ

public static boolean isAtLeastO() {
    return ! "REL".equals(VERSION.CODENAME)
            && ("O".equals(VERSION.CODENAME) || VERSION.CODENAME.startsWith("OMR"));
}


BuildCompat.isAtLeastOはfalseを返します。このメソッドをフォローしてください。

public static Intent createShortcutResultIntent(@NonNull Context context,
        @NonNull ShortcutInfoCompat shortcut) {
    Intent result = null;
    if (BuildCompat.isAtLeastO()) {
        result = ShortcutManagerCompatApi26.createShortcutResultIntent(context, shortcut);
    }
    if (result == null) {
        result = new Intent();
    }
    return shortcut.addToIntent(result);
}


まあ、まだAndroid Oが正式に出ていないためか、エミュレータのVERSION.CODENAMEがRELになっていますが......。

今のところCompactパッケージで手抜きすることはできませんが、それでも見栄えのする実装になっていますね。
各メソッドの実装の詳細は省きますが、掲載した他の2つのメソッドのソースコードを紹介します。

public static boolean requestPinShortcut(@NonNull final Context context,
        Nullable final IntentSender callback) { { ShortcutInfoCompat shortcut, @Nullable final IntentSender callback, @Nullable final IntentSender callback, @Nullable final IntentSender callback
    if (BuildCompat.isAtLeastO()) {
        return ShortcutManagerCompatApi26.requestPinShortcut(context, shortcut, callback);
    }

    if (!isRequestPinShortcutSupported(context)) {
        return false;
    }
    Intent intent = shortcut.addToIntent(new Intent(ACTION_INSTALL_SHORTCUT));

    // コールバックが NULL の場合は、ブロードキャストを送信するだけです。
    if (コールバック == null) {
        context.sendBroadcast(intent)を実行します。
        trueを返します。
    }

    // それ以外の場合は、インテントが正常にディスパッチされたときにコールバックを送信します。
    context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {)
        オーバーライド
        public void onReceive(Context context, Intent intent) { .
            トライ {
                callback.sendIntent(context, 0, null, null, null);
            } catch (IntentSender.SendIntentException e) { { {...
                // 無視する
            }
        }
    }, null, Activity.RESULT_OK, null, null);
    trueを返します。
}



public static Intent createShortcutResultIntent(@NonNull Context context,
        @NonNull ShortcutInfoCompat shortcut) {
    Intent result = null;
    if (BuildCompat.isAtLeastO()) {
        result = ShortcutManagerCompatApi26.createShortcutResultIntent(context, shortcut);
    }
    if (result == null) {
        result = new Intent();
    }
    return shortcut.addToIntent(result);
}



この時点で、アプリがデスクトップショートカットを追加する方法についての話は終わりです。デスクトップ・ソフトウェアがこれらのインターフェイスをどのように適応させるかは、さらなる探求の余地があります。