App添加桌面快捷方式引导实现

1,361 阅读7分钟

一、需求背景

快捷方式可帮助用户快速访问您的应用的某些部分,从而为他们呈现特定类型的内容。

游戏专区因为多次整改,游戏视频页面的入口多次下线或调整,一定程度影响用户留存。签到看视频入口是平台历史入口(APP个人中心),因诸多整改、用户属性因素流量空间被挤压,每次入口调整,老用户就会反馈投诉无法找到入口。

因此,产品希望通过创建桌面固定快捷方式,达到给用户提供直达相关功能页面的目的,从而提高用户留存率和产品满意度。在本次需求中,采用的是桌面固定快捷方式实现方式,同时会介绍其他两种常见的快捷方式实现形式。

二、实现方式介绍

Shortcuts的实现有三种形式:静态快捷方式(static shortcuts)、动态快捷方式(dynamic shortcuts)和桌面固定快捷方式(pinned shortcuts)。

其中静态快捷方式和动态快捷方式显示形式相同,只会在Android启动器种显示,无法作为独立launcher在手机桌面显示。启动方式为长按App launcher出现。可以通过拖拽来把创建好的静态/动态快捷方式固定在桌面上。

并且创建数量有上限,一次推送的快捷方式数不能超过设备支持的数量上限,一般情况下为4。

桌面固定快捷方式,指的是在桌面上显示为一个图标的快捷方式。为app创造了一个新的launcher icon,可以指定该launcher的跳转intent。创建数量不限。

下图1显示了这两类快捷方式之间的展示区别。

图1 应用快捷方式(静态/动态)与固定快捷方式的外观(图来自google官方文档)

三、具体实现

1、静态快捷方式实现

1)在资源文件res下新建xml目录,新建文件shortcuts.xml,文件名可以随便定义。

2)在shortcuts.xml中,添加 <shortcuts> 根元素,其中包含 <shortcut> 元素的列表。每个 <shortcut> 元素都包含有关一个静态快捷方式的信息,包括其图标、说明标签及其在应用内启动的 intent。

<?xml version="1.0" encoding="utf-8"?><shortcuts xmlns:android="http://schemas.android.com/apk/res/android">    <shortcut        android:icon="@drawable/ic_settings"        android:shortcutId="setting"        android:shortcutLongLabel="@string/shortcut_setting_long"        android:shortcutShortLabel="@string/shortcut_setting_short">        <intent            android:action="com.example.shortcutstest.SETTING"            android:target            android:targetPackage="com.example.shortcutstest" />    </shortcut></shortcuts>

android:shortcutIdandroid:shortcutShortLabel是必须要配置的,否则快捷方式不会显示,其他属性都是可选的。

还需要在shortcut标签内部配置Intent,指定点击快捷方式时要执行的操作,和Activity的intent-filter类似,intent标签有以下几个属性:

  • android:action:指定Intent要启动的操作或任务,该属性必须要指定,否则不会显示快捷方式。

  • android:targetClass:要跳转的目标类。

  • android:targetPackage:要跳转的目标应用包名。

3)AndroidManifest.xml文件配置

<manifest xmlns:android="http://schemas.android.com/apk/res/android"          package="com.example.myapplication">  <application ... >    <activity android:name="Main">      <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>

配置快捷方式的Activity必须满足actionandroid.intent.action.MAIN并且categoryandroid.intent.category.LAUNCHER,即App启动Activity。 这样就创建好了静态快捷方式。

静态快捷方式的配置有数量限制,最多只能显示4个,如果配置超过4个,多余的则不会显示,应用并不会报错。

2、动态快捷方式实现

动态快捷方式(Dynamic Shortcuts),可以在应用运行过程中添加快捷方式。官方提供了一个类ShortcutManager,可以实现快捷方式的创建、更新和删除等操作。最新的jetpack库中推出了ShortcutManagerCompat,使用起来更方便。

实现代码如下:

ShortcutInfo shortcut = new ShortcutInfoCompat.Builder(context, "id1")    .setShortLabel("Website")    .setLongLabel("Open the website")    .setIcon(IconCompat.createWithResource(context, R.drawable.icon_website))    .setIntent(new Intent(Intent.ACTION_VIEW,                   Uri.parse("https://www.mysite.example.com/")))    .build();ShortcutManagerCompat.pushDynamicShortcut(context, shortcut);
  • 推送和更新:使用 [pushDynamicShortcut()](https://developer.android.com/reference/androidx/core/content/pm/ShortcutManagerCompat?hl=zh-cn#pushDynamicShortcut(android.content.Context,%20androidx.core.content.pm.ShortcutInfoCompat)) 发布和更新动态快捷方式。如果已经存在具有相同 ID 的动态快捷方式或固定快捷方式,那么每个可变快捷方式都会更新。
  • 移除:使用 [removeDynamicShortcuts()](https://developer.android.com/reference/androidx/core/content/pm/ShortcutManagerCompat?hl=zh-cn#removeDynamicShortcuts(android.content.Context,%20java.util.List%3Cjava.lang.String%3E)) 移除一组动态快捷方式,或使用 [removeAllDynamicShortcuts()](https://developer.android.com/reference/androidx/core/content/pm/ShortcutManagerCompat?hl=zh-cn#removeAllDynamicShortcuts(android.content.Context)) 移除所有动态快捷方式。

需要注意,如果在删除之前将快捷方式固定到了桌面上(这种称作固定快捷方式),在删除之后该快捷方式的图标不会消失,点击后依然可以完成正常跳转。这种固定在桌面上的快捷方式只能用户手动来移除,因此更好的一种做法是在删除快捷方式后判断该快捷方式是否被固定到了桌面上,如果是的话就再禁用该快捷方式,并提示用户该快捷方式已被删除。通过ShortcutManagerdisableShortcuts()方法可以禁用快捷方式。

3、桌面固定快捷方式实现

在Android 8.0(API level 26)及更高版本上,系统支持直接创建固定快捷方式,创建的步骤如下:

1)、通过ShortcutManager的isRequestPinShortcutSupported()方法判断是否支持固定快捷方式,返回true表示支持,false表示不支持,该方法是Android 8.0才有的,因此在调用前需要判断一下。也可以使用ShortcutManagerCompat.isRequestPinShortcutSupported(context)方法,该方法兼容了Android 8.0以下版本。

2)、创建一个ShortcutInfo对象,指定要固定的快捷方式,如果要固定的是已经创建好的快捷方式,那么在构建ShortcutInfo时只需要传id就可以了,需要注意固定的快捷方式不能是已禁用的,否则应用会报错;如果要固定一个新的快捷方式,就像创建动态快捷方式那样构建一个ShortcutInfo就好了。

3)、通过requestPinShortcut()方法来固定快捷方式,该方法有两个参数对象,第一个参数是我们上面创建好的ShortcutInfo对象,第二个参数是一个IntentSender对象,可以通过PendingIntent.getIntentSender()来获得,当固定快捷方式成功后,会执行该Intent指定的操作,包括启动Activity、发送广播等,如果固定快捷方式成功后不需要做额外处理的话该参数传null就可以。

具体代码如下:

@TargetApi(Build.VERSION_CODES.O)    private static void addShortCutAbove26(Context context, String id, String title, int iconId, String protocol) {        try {            ShortcutManager shortCutManager = (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);            if (shortCutManager != null && shortCutManager.isRequestPinShortcutSupported()) {                Intent shortcutInfoIntent = new Intent();                //action必须设置,不然报错                shortcutInfoIntent.setAction(Intent.ACTION_VIEW);                shortcutInfoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                shortcutInfoIntent.setComponent(new ComponentName(context, "com.wuba.RedirectActivity"));                shortcutInfoIntent.setData(Uri.parse(protocol));                ShortcutInfo info = new ShortcutInfo.Builder(context, id)                        .setIcon(Icon.createWithResource(context, iconId))                        .setShortLabel(title)                        .setIntent(shortcutInfoIntent)                        .build();                //当添加快捷方式的确认弹框弹出来时,将被回调                PendingIntent shortcutCallbackIntent = PendingIntent.getBroadcast(context, 0, new Intent(context,ShortcutReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);                //创建快捷方式                shortCutManager.requestPinShortcut(info, shortcutCallbackIntent.getIntentSender());            }        } catch (Exception e) {            e.printStackTrace();        }    }

ShortcutReceiver是一个广播接收器,当固定快捷方式成功时会发送广播,我们可以在onReceive()方法中添加一些逻辑。比如:弹出toast提示用户"创建XX快捷方式成功"。需要注意的是,在开发过程中发现华为EMUI系统和鸿蒙系统在创建成功后,系统会自动弹出toast提示成功,其他系统则不会。

使用shortManager创建固定快捷方式会弹出一个提示对话框,用户点击确认后才会将快捷方式添加到桌面,并执行requestPinShortcut()方法第二个参数指定的操作。如下图所示:

图2 shortManager创建固定快捷方式

在Android8.0版本以下低版本系统,通过发送系统广播的方式添加。具体步骤如下:

1)申请系统权限

<!-- android o 以下创建桌面快捷方式需要如下权限--><uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" /><!-- 添加快捷方式 --><uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /><!-- 移除快捷方式 --><uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" /><!-- 查询快捷方式 --><uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />

2)发送创建固定快捷方式广播

Intent intent = new Intent();intent.setAction(Intent.ACTION_VIEW);intent.setComponent(new ComponentName(context, "com.wuba.RedirectActivity"));intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);intent.setData(Uri.parse(protocol));Intent shortcutIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);shortcutIntent.putExtra("duplicate", false);shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);shortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(context, iconId));context.sendBroadcast(shortcutIntent);

需要注意的是,通过发送广播方式创建固定快捷方式,无法判断创建成功与否的状态。因此,通常App做法是发送广播完成后。通过创建一个dialog或者toast提示用户“XX快捷方式已尝试添加到桌面”。

需要注意的是,以上两种方式均需要用户打开App权限里的桌面快捷方式权限。如果权限未打开,则会导致创建失败。

另外在实际开发过程中,发现某些低端手机,会出现在权限打开的情况下添加不成功。

四、总结

  • 静态快捷方式:属于应用驱动型,提供指向应用内常规操作的链接。通常用于App内固定的常用高频功能引导。

  • 动态快捷方式:跟静态快捷方式显示方式相同,但相比于静态快捷方式内容更为灵活,可在不同场景动态改变配置。

  • 固定快捷方式:用于用户驱动的特定操作,显示图、标题和跳转可由用户自定义,更加个性化。

参考资料:

developer.android.com/guide/topic…