Android 7.1 新特性:快捷方式 Shortcuts

一、Shortcuts 介绍

Android 7.1 允许 App 自定义 Shortcuts,类似 iOS 的 3D touch。通过在桌面长按 App 弹出 Shortcut 列表,点击某个 Shortcut 快速进入某项操作,同时 Shortcut 可以拖动到桌面进行固定,如下图:

android-7.1-app-shortcuts

1. Shortcuts 作用及分类

Shortcuts 为 App 常用操作提供了快速访问的方式,如上面日历的新建提醒。

这个功能目前只能在 Android 7.1 系统桌面进行使用,这个依然保留着“应用抽屉”古老设计的产品国内应该没多少用户。三方桌面可以通过 API 接入这个功能。
目前支持 Shortcut 的应用主要还是 Google 的 App,看到有即刻的朋友说他们在 7.1 系统发布时快速支持了这个功能并上线,速度很赞。

类似 BroadcastReceiver 可通过静态和动态方式注册,Shortcuts 也可以通过静态和动态方式添加。

2. 静态 Shortcuts(Static Shortcuts)

静态 ShortcutsStatic Shortcuts通过在 Manifest 中声明添加。缺点是不可以修改,只能通过应用升级来添加新的静态 Shortcuts。添加主要分为两步:

2.1 AndroidManifest.xml 的 Main Launcher 对应的 Activity 内添加 meta-data meta-data nameandroid.app.shortcuts,如下:

<application
    ……>
    <activity android:name=".main.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>

必须在 Main Launcher 对应的 Activity 内设置,其中android:resource指向定义了 shortcuts 的资源文件。

2.2 资源文件中定义具体的 shortcuts
res 目录下新建 xml 文件夹,并新建 shortcuts.xml 文件,内容如下:

<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:enabled="true"
        android:icon="@drawable/search"
        android:shortcutId="search"
        android:shortcutDisabledMessage="@string/disabled"
        android:shortcutLongLabel="@string/menu_label"
        android:shortcutShortLabel="@string/launcher_label">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetClass="cn.trinea.android.demo.SearchActivity"
            android:targetPackage="cn.trinea.android.demo"/>
        <intent
            ……/>
    </shortcut>
    ……
</shortcuts>

以shortcuts元素为根,可以包含多个shortcut元素,每个shortcut元素表示一个 shortcut。其中属性分别表示:

  1. shortcutId表示 shortcut 唯一标识符,相同的 shortcutId 会被覆盖。必须字段。
  2. shortcutShortLabel为将 shortcut 拖动到桌面时显示的名字,官方建议不超过 10 个字符,必须字段。
  3. shortcutLongLabel为 shortcut 列表中每个 shortcut 的名字,不宜过长,如果过长或未设置默认会显示 ShortLabel,官方建议不超过 25 个字符。可选字段。
  4. icon为 shortcut 的 icon,在列表展示和拖动到桌面时显示需要,可选字段。
  5. enabled表示 shortcut 是否可用,false 表示禁用。xml 中这个属性几乎没有被设置为 false 的实际场景,具体原因可见6.7 如何更好的删除(废弃)老的 Shortcut中介绍。
  6. shortcutDisabledMessage为已固定在桌面的 shortcut 被 Disabled 后点击时的 Toast 提示内容。可选字段。
  7. intent为点击 shortcut 时响应的 Intent,必须字段。

这里可以添加多个 Intent,但点击时不会启动所有 Intent,而是启动最后一个 Intent,在这个 Intent 回退时会启动它前面一个 Intent,相当于自动将所有 Intent 添加到了堆栈。
对于先跳转到某个页面,Back 键希望退回主页而不是结束 App 这类场景,多个 Intents 挺实用的。

intent可设置属性包括:
android:action、android:data、android:mimeType、android:targetClass、android:targetPackage
其中android:action为必须属性。

3. 动态 Shortcuts(Dynamic Shortcuts)

动态 ShortcutsDynamic Shortcuts 通过 ShortcutManager API 进行操作。可以动态添加、修改、删除。

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
    return;
}

ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
    .setShortLabel("trinea.cn")
    .setLongLabel("Open trinea.cn")
    .setDisabledMessage("Disabled")
    .setIcon(Icon.createWithResource(context, R.drawable.trinea_cn))
    .setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.trinea.cn/")))
    .build();
shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));

通过ShortcutInfo.Builder新建 ShortcutInfo,再通过shortcutManager添加即可。其他:

  1. setDynamicShortcuts(List)可以替换并添加所有 shortcut 列表;
  2. addDynamicShortcuts(List)可以添加新的 shortcut 到列表,超过最大个数会报异常;
  3. updateShortcuts(List)可以更新一组 shortcuts;
  4. removeDynamicShortcuts(List)和removeAllDynamicShortcuts() 可以删除部分或所有 shortcuts。

ShortcutInfo的属性与 xml 中定义字段含义一致,shortcutId shortcutShortLabel intent 是必须设置的字段,并且intent必须设置Action。

4. 固定的 Shortcuts(Pinned Shortcuts)

指通过拖动固定到桌面的 Shortcuts,App 不可以添加、修改、删除这些 Shortcuts,只能禁用他们。即便 App 内删除了某个 Shorcut,对应的已固定到桌面的 Shortcuts 也不会被删除。

可以通过:

  1. getPinnedShortcuts()得到所有固定的 Shortcuts 的信息。
  2. disableShortcuts(List)或disableShortcuts(List, CharSequence)禁用动态的 Shortcuts。

对于静态的 Shortcuts 需要在资源文件中设置android:enabled="false"进行禁用,不过没有必要,静态 Shortcuts 可直接通过删除达到禁用的效果,具体原因可见6.7 如何更好的删除(废弃)老的 Shortcut中介绍。

静态 Shortcuts 和动态 Shortcuts 是有最大个数限制的,默认为 5,超过最大个数后添加会报异常。而固定的 Shortcuts 并没有个数限制,并且固定的 Shortcut 对应的 Shortcut 即便被动态删除了,依然可以通过 id 进行 Update 操作。

5. 其他

5.1 动态 Shortcuts 与静态 Shortcuts 区别

  1. 静态 Shortcuts 只能通过升级应用修改,动态 Shortcuts 随时可以修改;
  2. 静态 Shortcuts 的 Intent 无法设置 Flag,默认为FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TASK Flag,即若应用运行中会清除所有已存在的 Activity。动态 Shortcuts 的 Intent 可以设置 Flag;
  3. 静态 Shortcuts 的rank系统默认根据声明顺序设置,动态 Shortcuts 的rank可以通过setRank(int rank)接口主动设置,rank 不能小于 0,值越大表示在 shortcut 列表展示时离 App Icon 越远。静态 Shortcuts 默认比动态 Shortcuts 离 App Icon 更近。
  4. 静态 Shortcuts 删除可以直接删除,动态 Shortcuts 建议通过禁用删除;

5.2 动态 Shortcuts 操作的频率问题

当应该完全退到后台(无 Activity 或 Service 在前台时),其操作 Shortcut(包括添加、删除、修改) 的频率是受限的。可通过isRateLimitingActive()查询是否已受限,true表示已受限。

5.3 跟踪 Shorcut 使用情况

在 Shortcut 被选择或者其关联的操作被操作时需调用reportShortcutUsed(String shortcutId)接口上报数据,为了方便启动器收集应用 Shortcuts 使用情况,以便未来进行预测或者向开发者展示哪些操作适合作为 Shortcuts 以及其优先级。

PS:这个接口其实挺尴尬的,一方面需要 App 主动上报,侵入性太强。另一方面这个预测功能未来也不好加到 Shortcuts 推荐里,更多是个开发工具相关功能。
最好是由启动器自己纯粹收集 Shortcut 被选择的使用情况数据,而不需要统计 Shortcut 被关联操作通过其他方式调用的使用情况数据。至于哪些操作适合作为 Shortcuts,开发者大可通过其他监控 SDK 去判断。

5.4 应用备份

如果应用通过备份恢复到另外一台机器上,固定的 Shortcuts 是可以直接恢复的,不过启动器不保存这些 Shortcut 的 icon,所以应用内需要存在这些 icon 对应的资源以便启动器能找到。

静态 Shortcuts 需要应用重新安装、升级才能生效。
动态 Shortcuts 需要相应代码被执行过才能生效。

二、Shortcuts 一些实践&问题


6. 最佳实践

这块官网已经给出了一部分建议,包括:

  1. 设计上和系统 App 的 Shortcuts 保持一致。
  2. 最多添加 4 个 Shortcuts 以保持在启动器中显示的样式最佳
    目前虽然说是 5 个,但实际最多只能添加 4 个,可见7.2 Shortcut 添加或修改无效中介绍。
  3. 限制 Label 长度
    其中shortcutShortLabel建议不超过 10 个字符,shortcutLongLabel 建议不超过 25 个字符。这块可能有些问题,可见7.1 LongLabel 和 ShortLabel中介绍。
  4. 记录 Shortcut 及其对应操作使用记录。
    这个在5.3 跟踪 Shorcut 使用情况中已经介绍了。
  5. 只在 Shortcut 意义不变的情况下更新,否则新增。
  6. 动态 Shortcuts 在 BackUp 恢复后不可以直接恢复,考虑适时新增或更新已有的 Shortcuts
    除了以上这些外,个人觉得还有几点需要遵守:
  7. 如何更好的删除(废弃)老的 Shortcut
    这里主要考虑到删除老的 Shortcut,可能会影响已经固定的 Shortcut。
    对于静态 Shortcuts,直接删除配置文件中对应的 Shortcut 即可,系统桌面会将已固定的该 Shortcut 置灰,点击会提示 shortcutDisabledMessage。
    对于动态 Shortcuts 建议通过禁用的方式而不是直接删除的方式,因为已经删除的动态 Shortcut 如果被固定了依然是可用的,所以希望该入口不可用最好的方式是禁用。
  8. 始终设置shortcutDisabledMessage
    根据上面的介绍废弃老的 Shortcut 较好的方式是禁用,通过自定义shortcutDisabledMessage去更友好的提示用户。
  9. 动态添加 Shortcut 前需要判断 API 版本不小于 25
    否则在低版本会报 ClassNotFoundException 异常。

7. 一些问题

7.1 LongLabel 和 ShortLabel

LongLabel和ShortLabel的含义,官方 API 文档解释的并不是很清楚。
在 Nexus 6 上测试,当 LongLabel 长度大于 17 个小写字符时,会显示 ShortLabel,而不是 LongLabel。这里的界限长度跟大小写、空格都有关,应该是受限于桌面 Shortcuts 列表 Item 的宽度!

7.2 Shortcut 添加、修改、点击无效

可能原因:

  1. shortcutId 被覆盖
    shortcutId 是唯一标识,相同 shortcutId 会被覆盖。
  2. intent 不对
    intent 必须设置 android:action 属性,同时目标 Activity 必须有效即已在 Manifest 中声明。
  3. 后台 App 有频率限制
    当应该完全退到后台(无 Activity 或 Service 在前台时),其操作 Shortcut(包括添加、删除、修改) 的频率是受限的。可通过isRateLimitingActive()查询是否已受限,true表示已受限。
    若已受限,可通过开发者选项中“重置 ShortcutManager 调用频率限制”或命令行adb shell cmd shortcut reset-throttling [ --user USER-ID ]解决。
  4. Shortcut 个数限制
    虽然官方文档介绍静态和动态 Shortcut 总和不能超过 5 个,通过getMaxShortcutCountPerActivity()得到的也是 5,但实际测试下来是不超过4个!即静态和动态shortcuts加起来总数最多是五个.
    当我们尝试添加第六个shortcut时, 应用会抛出异常:
    java.lang.IllegalArgumentException: Max number of dynamic shortcuts exceeded.
    虽然总数限制是5个, 但是当我正好有5个(2个静态 + 3个动态)的时候, 长按只显示了4个shortcuts.

android-7.1-app-shortcuts数量的限制

7.3 getIntents() 有 Bug

getIntents() 实现 中可以看出未做mIntents是否为 null 及 empty 的判断,在 null 时会出现:

java.lang.NullPointerException: Attempt to get length of null array

的异常。

8. 三方桌面支持 Shortcuts——LauncherApps

如果三方桌面希望支持这个特性,请参考 LauncherApps API 介绍,不过只有系统默认桌面才有权限得到其他 App Shortcuts 信息。

可通过hasShortcutHostPermission()查看是否拥有权限,如果没有权限,会报如下异常:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xx/com.xx.XXActivity}:
java.lang.SecurityException: Caller can't access shortcut information
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)

通过getShortcuts API 获取到所有 Shortcuts 信息。

参考:
App Shortcuts的官方文档: App Shortcuts
Exploring Android Nougat 7.1 App Shortcuts

-------------本文结束 感谢阅读-------------

本文标题:Android 7.1 新特性:快捷方式 Shortcuts

文章作者:OCNYang

发布时间:2016年11月23日 - 16:11

最后更新:2018年05月29日 - 21:05

原始链接:http://ocnyang.com/2016/11/23/Android7Shortcuts/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持好文章的分享,您的支持将是对我最大的鼓励!