探索Android 7.1 app快捷方式(App Shortcuts)
Posted 碎格子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了探索Android 7.1 app快捷方式(App Shortcuts)相关的知识,希望对你有一定的参考价值。
Google已经发布了android Nougat 7.1(API 25) 版本,但是这个不是一个小的发布版,事实上它绑定了一些有趣的功能在底层。其中一个附加功能就是App快捷方式。
- App快捷方式对于暴露你的app的actions然后把用户带入你的流程中去都是非常不错的
- 快捷方式可以是静态或者动态的
- 静态的方式一旦定义了就不能更改了(你只可以通过App重新部署来更改)
- 动态的方式可以被动态地改变
- 一旦你通过快捷方式开启一个Activity,你可以创建一个Activity的回退栈
- 快捷方式可以被重新排序,但是只针对他们各自的类型,静态快捷方式总是会处于底部因为他们是最先被添加的(他们没有可以被定义的排名优先级)
- 这些快捷方式的标签都是CharSequence,你可以通过spans来操作他们
如果你想通过一步一步的指南来实现,请接着看。
是什么及为什么?
App快捷方式是将你应用的常见操作或者任务暴露给发射器的一种手段。用户可以通过长按app的启动图标看到快捷方式。
他们有两种类型:
- 静态:被静态定义在资源文件里,不能被更改除非你修改了文件并且重新部署了app
- 动态:发布在运行时,快捷方式可以被更新不需要重新部署app
注意:你的app最多只可以有5个快捷方式
通过暴露你的常见任务,你的用户可以不需要额外的指示便可直接返回你的app
怎么做
给你的App添加快捷方式是相当简单的。让我们从创建一个简单的静态快捷方式开始。
注意:你必须要使用Android Nougat 7.1 的设备和一个支持快捷方式的launcher(比如Pixel launcher或者Now launcher)
静态快捷方式
我假设你已经有了或者创建了一个新的Android Studio项目。下面配置你的AndroidManifest.xml,添加如下meta-data标志到你的主Activity中:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.catinean.appshortcutsdemo">
<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" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
</application>
</manifest>
在meta-data中,android:resource的key对应一个被定义在res/xml/shortcuts.xml的资源文件。在这你需要定义你的所有的静态快捷方式,然后将一个可以打开你app指定的activity的快捷方式添加进去(在我的例子里我创建了一个假想的StaticShortcutActivity)
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_static_shortcut"
android:shortcutDisabledMessage="@string/static_shortcut_disabled_message"
android:shortcutId="static"
android:shortcutLongLabel="@string/static_shortcut_long_label"
android:shortcutShortLabel="@string/static_shortcut_short_label">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.catinean.appshortcutsdemo.StaticShortcutActivity"
android:targetPackage="com.catinean.appshortcutsdemo" />
</shortcut>
</shortcuts>
你可以看到这个file根目录的tag是,它可以包含多个块。他们的每一个,正如你所想,都代表一个静态的快捷方式。以下的配置可以设置在每一个快捷方式下:
- enabled: 作为状态声明,表明是否开启快捷方式。如果你想要禁用你的静态快捷方式,你可以把它置为false,或者简单粗暴地把它从集合中移除。
- icon: icon显示在快捷方式的左边。在我的例子里,我从Android Studio中创建了一个简单的Vector Drawable并作为一个icon。
- shortcutDisabledMessage: 当你禁用了你的快捷方式,它会从这些快捷方式中消失,用户可以通过长按app图标进行显示,但是可以将一个快捷方式绑定到launcher上(通过在想要的的启动界面长按及拖拽它),因此当禁用了被绑定的快捷方式将显示灰色,当点击它的时候会出现显示这个message的Toast。
- shortcutLongLabel:当launcher有足够的空间时,快捷方式长文本会显示
- shortcutShortLabel:快捷方式的一段简短的描述。这个域是必须的。这个将会出现在你的launcher上。
- intent: 当点击时你的快捷方式你定义intent(或者intents)将开启
让我们看看我们的静态快捷方式长什么样子:
很好用也很简单,但是可以看到,当点击回退键后,用户却回到了launcher界面。那怎样让用户回到app里呢?为了实现这个功能,我们可以在之前的基础上添加多个intent标签:
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
...>
<intent
android:action="android.intent.action.MAIN"
android:targetClass="com.catinean.appshortcutsdemo.MainActivity"
android:targetPackage="com.catinean.appshortcutsdemo" />
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.catinean.appshortcutsdemo.StaticShortcutActivity"
android:targetPackage="com.catinean.appshortcutsdemo" />
</shortcut>
</shortcuts>
注意看,我们在之前已有的intent之上添加了一个额外的指向MainActivity。这个将会创建一个intents的回退栈,最后一个Activity是由快捷方式打开。在我们的例子里,回退栈看起来似乎是MainActivity -> Static ShortcutActivity,因此当我们按下回退键时,用户会回到MainActivity:
添加一个静态的快捷方式是非常简单的,现在让我们关注定义一些动态的快捷方式:
动态快捷方式
正如他们名字所述,这个快捷方式可以在运行时被动态修改而不需要重新部署app。如你所想的,这个不是通过静态资源文件(shortcuts.xml)定义的,而是通过code创建。
让我们添加我们的第一个动态快捷方式。为了实现它,你将必须使用ShortcutManager和ShortcutInfo.Builder。我将在我的MainActivity的onCreate()方法中构建第一个动态快捷方式:
@Override
protected void onCreate(Bundle savedInstanceState)
...
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
ShortcutInfo webShortcut = new ShortcutInfo.Builder(this, "shortcut_web")
.setShortLabel("catinean.com")
.setLongLabel("Open catinean.com web site")
.setIcon(Icon.createWithResource(this, R.drawable.ic_dynamic_shortcut))
.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse("https://catinean.com")))
.build();
shortcutManager.setDynamicShortcuts(Collections.singletonList(webShortcut));
这儿我们获得了shortcutManager以及ShortcutInfo的构造器。通过使用ShortcutInfo.Builder我们可以设置我们想要创建的快捷方式的各种属性。上面我们使用的builder的所有方法都与静态快捷方式的相同属性相对应,因此我不再赘述。然而,有一个属性是有点不同的,即shortcut_web,它是快捷方式的id,作为第二个参数被定义在StaticInfo.Builder的构造器里。我已经定义了intent来打开网页。最后,我把动态的快捷方式设置到ShortcutManager里。现在看看我们的快捷方式是什么样子:
看起来很6啊~现在我们的app有2个快捷方式-一个静态一个动态。
我们来添加另一个指向app内部的activity的快捷方式,然后看看我们可以怎样给它创建一个回退栈。
@Override
protected void onCreate(Bundle savedInstanceState)
...
ShortcutInfo dynamicShortcut = new ShortcutInfo.Builder(this, "shortcut_dynamic")
.setShortLabel("Dynamic")
.setLongLabel("Open dynamic shortcut")
.setIcon(Icon.createWithResource(this, R.drawable.ic_dynamic_shortcut_2))
.setIntents(
new Intent[]
new Intent(Intent.ACTION_MAIN, Uri.EMPTY, this, MainActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
new Intent(DynamicShortcutActivity.ACTION)
)
.build();
shortcutManager.setDynamicShortcuts(Arrays.asList(webShortcut, dynamicShortcut));
可以看到现在我们为了创建一个回退栈在builder上使用了setIntents()。
第一个的intent相当于MainActivity。我们指定它为FLAG_ACTIVITY_CLEAR_TASK是为了清除任何一个存在的且与app有关的任务,并创建MainActivity为当前的根activity,第二个intent对应DynamicShortcutActivity(这只是一个我创建的空的Activity)。为了实现这个,我们需要提供一个Intent附带一个特殊的Action,这是一个被定义在DynamicShortcutActivity的静态字符串,与之对应的intent-filter的action被定义在AndroidManifest.xml:
<activity
android:name=".DynamicShortcutActivity"
android:label="Dynamic shortcut activity">
<intent-filter>
<action android:name="com.catinean.appshortcutsdemo.OPEN_DYNAMIC_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
通过这个顺序声明intents数组,我们确保通过我们创建的快捷方式,当用户打开DynamicShortcutActivity之后按下back键,MainActivity也将被打开。
让我们看看效果:
快捷方式的排序
我们现在已有了一个静态快捷方式和两个动态快捷方式,我们如何指定一个自定义的顺序给他们呢?仔细看看ShortcutInfo.Builder的方法,其中一个吸引了我们的注意:setRank(int)。通过设置一个自定义的排序方法给一个动态的快捷方式,我们可以控制他们出现的顺序:排名越高,快捷方式越靠顶部。
比方说我们想要第二个快捷方式(catinean.com)置顶,我们可以动态改变已添加进去的快捷方式的排名。我们在MainActivity里的按钮按下的时候实现:
findViewById(R.id.main_rank_button).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
ShortcutInfo webShortcut = new ShortcutInfo.Builder(MainActivity.this, "shortcut_web")
.setRank(1)
.build();
ShortcutInfo dynamicShortcut = new ShortcutInfo.Builder(MainActivity.this, "shortcut_dynamic")
.setRank(0)
.build();
shortcutManager.updateShortcuts(Arrays.asList(webShortcut, dynamicShortcut));
);
在这个按钮的click监听器里,我们使用同样的ID创建新的ShortcutInfo给每一个我们之前添加过的快捷方式,但是现在我们给shortcut_web设置了一个更高的排名,把更低的排名给shortcut_dynamic。最后我们使用了ShortcutManager里的updateShortcuts(List)方法去使用新排名更新快捷方式:
你可以从gif图上看到静态快捷方式位于了列表的底部。事实上,我们不能改变静态快捷方式的排名,他们会按照在shortcuts.xml文件里定义的顺序进行展示。如果我们只有一个静态快捷方式,那他的默认排名是0并且不能被改变。
额外的一些小姿势
如果注意看ShortcutInfo.Builder里的setShortLabel(CharSequence)这个方法,我们可以看到他接收了一个CharSequence作为一个参数。这意味着什么?对,这意味着我们可以使用自定义的spans去玩它。
比方说如果我们想在按下按钮的时候把label的颜色变为红色,我们可以创建一个SpannableStringBuilder以及使用ForegroundColorSpan设置一个我们想要的颜色,用spannableStringBuilder作为一个shortLabel(因为SpannableStringBuilder就是一个CharSequence)
findViewById(R.id.main_rank_button).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
ForegroundColorSpan colorSpan = new ForegroundColorSpan(getResources().getColor(android.R.color.holo_red_dark, getTheme()));
String label = "catinean.com";
SpannableStringBuilder colouredLabel = new SpannableStringBuilder(label);
colouredLabel.setSpan(colorSpan, 0, label.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ShortcutInfo webShortcut = new ShortcutInfo.Builder(MainActivity.this, "shortcut_web")
.setShortLabel(colouredLabel)
.setRank(1)
.build();
...
);
本文为翻译的文章,想看英文原文的朋友可以点原文链接
以上是关于探索Android 7.1 app快捷方式(App Shortcuts)的主要内容,如果未能解决你的问题,请参考以下文章
Android App 快捷方式之 Android 版本的 3D Touch