Android 7.1 应用快捷键详解

上一篇讲到了Android 7.1的预览版发布,今天这篇来说说其中的App Shortcut的使用。

Android 7.1允许在你的应用中定义具体动作的快捷键,这些快捷键能够被支持显示到launcher桌面上。比如说Nexus 和Pixel设备上已经提供了这个了。快捷键能让你的用户快速在你的应用中开始一个通用的或者建议的任务。

每一个快捷键引用了一个或者更多的intent,当用户在你的应用中选择了快捷键,每一个都会启动一个具体的动作。你能够表现出来的动作示例包括如下这些:

  • 在一款地图类应用中导航用户去一个特定的位置
  • 在一款社交类应用中发送消息给一个朋友
  • 在一款媒体类应用中播放下一集电视剧
  • 在一款游戏类应用中加载最后一次保存的游戏进度

你能够在你的应用中发布两种不同类型的快捷键:

  • 静态快捷键定义在一个资源文件中,打包到一个APK中,因此,你必须等到你的应用直到更新升级整个应用,才能去改变这些静态快捷键的详细内容。
  • 动态快捷键在运行时使用ShortcutManager API发布,在运行的过程中,你可以去发布、更新、移除它的快捷键。

你能够在你的应用中一个时间里发布5个快捷键(静态快捷键和动态快捷键结合在一起)。用户,然而,能够复制应用的快捷键到launcher桌面上,创建一个固定的快捷键。用户能够在你的应用中创建和访问一个没有限制数量大小的固定快捷键和触发动作。你的应用不能够移除这些快捷键,但是能够禁用它们。

注意: 虽然其他的应用不能够访问在你快捷键中的元数据,launcher桌面它自己能访问这个数据,因此,这些元数据应该隐藏敏感的用户信息。

静态快捷键

静态快捷键应该在你的应用内部提供一个链接去生成动作,这些动作应该和你应用的当前版本的生活时间保持一致。对于静态快捷键较好的候选包括查看已发送的信息、设置一个闹钟和显示一个用户一天的锻炼活动。
对于创建一个静态的快捷键,完成如下的顺序步骤:

1、在你应用的manifest文件(AndroidManifest.xml)中找到一个activity的intent filtes,action是设置的andorid.intent.action.MAIN并且category是设置的android.intent.category.LAUNCHER

2、添加一个节点到这个activity,引用在应用中定义的快捷键资源文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<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>

3、创建一个新的资源文件(res/xml/shortcuts.xml),这个文件就是定义在应用的manifest的快捷键

4、在这个新的资源文件中,添加一个根节点,包含了一个的list集合节点。每一个节点中包含了关于一个静态快捷键的信息,包括它的图标、它的描述、和它在应用内部启动的intent意图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="id0"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/shortcutShortLabel"
android:shortcutLongLabel="@string/shortcutLongLabel"
android:shortcutDisabledMessage="@string/shortcutDisabledMessage">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.xw.appshortcuts"
android:targetClass="com.xw.appshortcuts.MainActivity" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<!-- 这里指定更多的快捷键 -->
</shortcuts>

以下是对上面的shortcut标签相关属性的解释:

  • shortcutId, 表示唯一的id
  • enabled, 表示这个shortcut是否可用
  • shortcutShortLabel, 这里是配置的短名称, 下面还会有长名称, 如果长名称显示不下, 就显示短名称
  • shortcutLongLabel, 这里是配置的长名称, launcher会优先选择长名称显示
  • shortcutDisabledMessage, 这个配置是在我们选择一个不可用的shortcut时给用户的一个提示

动态快捷键

动态的快捷应该在你的应用内部提供一个具体的链接,上下文敏感动作。这些动作能够在用户使用你的应用中进行改变,并且他们甚至能够在当你的应用运行的时候进行改变。对于动态快捷键较好的候选包括打电话给某一个人、导航到一个固定的位置、和查看一款固定游戏当前的分数。

这个ShortcutManager API允许你完成如下的动态快捷键操作:

  • 发布:使用setDynamicShortcuts(List))去重新定义动态快捷键实体类集合,或者使用addDynamicShortcuts(List))去增加一个已经存在的动态快捷键集合。
  • 更新:使用updateShortcuts(List))方法。
  • 移除:移除一个设置的动态快捷键使用removeDynamicShortcuts(List)),或者使用removeAllDynamicShortcuts())方法去移除所有的动态快捷键。

具体示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package com.xw.appshortcuts;

import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private static final String TAG = "MainActivity";
private List<ShortcutInfo> shortcutInfos;//快捷键集合
private String[] shortLabel = null;//每个快捷键的短名称
private String[] longLabel = null;//每个快捷键的长名称
private String[] url = null;//每个快捷键的意图跳转域名
private int[] icon = null;//每个快捷键的图标
//============================================
private ShortcutManager shortcutManager = null;
private Button setDynamicShortcuts = null;//加载动态快捷键的按钮
private Button disableShortcuts = null;//禁用移除快捷键的按钮
private Button updateShortcuts = null;//更新快捷键的按钮

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
initData();
}

/**
* 初始化视图
*/
private void initView() {
this.updateShortcuts = (Button) findViewById(R.id.updateShortcuts);
this.disableShortcuts = (Button) findViewById(R.id.disableShortcuts);
this.setDynamicShortcuts = (Button) findViewById(R.id.setDynamicShortcuts);
this.updateShortcuts.setOnClickListener(this);
this.disableShortcuts.setOnClickListener(this);
this.setDynamicShortcuts.setOnClickListener(this);
}

/**
* 初始化数据
*/
private void initData() {
shortcutManager = getSystemService(ShortcutManager.class);
shortLabel = new String[]{"Google", "Youtube", "Facebook", "Twitter"};
longLabel = new String[]{"Open Google", "Open Youtube", "Open Facebook", "Open Twitter"};
url = new String[]{"https://www.google.com/", "https://www.youtube.com/", "https://www.facebook.com/", "https://www.twitter.com/"};
icon = new int[]{R.mipmap.ic_google,R.mipmap.ic_youtube,R.mipmap.ic_facebook,R.mipmap.ic_twitter};
}

/**
* 设置动态快捷键
*/
private void setDynamicShortcuts() {
shortcutInfos = new ArrayList<>();
for (int i = 0; i < shortLabel.length; i++) {
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, String.valueOf(i))
.setShortLabel(shortLabel[i])
.setLongLabel(longLabel[i])
.setIcon(Icon.createWithResource(this, icon[i]))
.setIntent(new Intent(Intent.ACTION_VIEW,
Uri.parse(url[i])))
.build();
shortcutInfos.add(shortcut);
}
shortcutManager.setDynamicShortcuts(shortcutInfos);
}

/**
* 禁用并移除快捷键
*/
private void disableShortcuts() {
List<ShortcutInfo> list = shortcutManager.getPinnedShortcuts();
if (list != null) {
for (ShortcutInfo info : list) {
//移除下标为0的快捷键
if (info.getId().equals("0")) {
shortcutManager.disableShortcuts(Collections.singletonList(info.getId()), "快捷方式已无效,请手动删除");
shortcutManager.removeDynamicShortcuts(Collections.singletonList(info.getId()));
}
}
}

}

/**
* 更新快捷键
* @param index
*/
private void updateShortcuts(int index) {

ShortcutInfo info = new ShortcutInfo.Builder(this, String.valueOf(index))
.setShortLabel("GitHub")
.setLongLabel("Open GitHub")
.setIcon(Icon.createWithResource(this, R.mipmap.ic_github))
.setIntent(new Intent(Intent.ACTION_VIEW,
Uri.parse("https://www.github.com")))
.build();
shortcutManager.updateShortcuts(Collections.singletonList(info));
}

/**
* 点击事件
* @param view
*/
@Override
public void onClick(View view) {

switch (view.getId()) {
case R.id.setDynamicShortcuts:
setDynamicShortcuts();
break;
case R.id.disableShortcuts:
disableShortcuts();
break;
case R.id.updateShortcuts:
updateShortcuts(0);
break;
default:
break;
}

运行效果:

动态增加快捷键:

(长按图标弹出)

set-shortcuts-1.png

(将每一个快捷键拖出来固定到桌面)

set-shortcuts-2.png

(固定到桌面的和快捷键集合弹出)

set-shortcuts-3.png

动态更新快捷键:

(更新Google为==>GitHub)

update-shortcuts.png

动态禁用移除快捷键:

(禁用GitHub)

disabled-shortcut.png

系统代码结构

shortcutshierarchyviewer1.png

通过sdk下的hierarchyviewer工具,可以看到长按桌面图标弹出的部分是一个DeepShortcutsContainer,其中包括了一个白色箭头的View和显示每一个快捷键的条目DeepShortcutsView组成。每一个DeepShortcutsView快捷键item又是由一个显示图标的View和一个DeepshortcutsTextView组成。

shortcutshierarchyviewer2.png

以上就是简单的对Android 7.1上面App Shortcut方面的概括总结,部分内容源于官方文档,如有不足,欢迎指正,谢谢。

if (本文对您有用) { Pay (请随意¥打赏) } else { Commit feedback (底部评论区提交建议、反馈) } 感谢支持!