(点击
上方公众号
,可快速关注)
来源:伯乐在线专栏作者 - 踏歌行
链接:http://android.jobbole.com/85121/
点击 → 了解如何加入专栏作者
Android 7.1 新功能之一就是 App Shortcuts(应用快捷方式) ,该功能与 iPhone 上的 3D Touch 功能相似,通过长按应用图标,可弹出应用快捷方式,点击可以直接跳转到相应的界面。目前最多支持 5 个快捷方式,可以 getMaxShortcutCountPerActivity() 查看 Launcher 最多支持几个快捷方式,不同的是 Android 支持通过拖拽将快捷方式固定到桌面。
看似美好,其实应用快捷方式还是有很多缺陷的:
-
只能在 Google 的 Nexus 及 Pixel 设备上使用
-
系统必须是 Android 7.1 及以上(API Level >= 25)
-
已经被用户固定到桌面的快捷方式必须得到兼容性处理,因为你基本上失去了对其控制,除了升级时禁用
Launcher applications allow users to “pin” shortcuts so they’re easier to access. Both manifest and dynamic shortcuts can be pinned. Pinned shortcuts cannot be removed by publisher applications; they’re removed only when the user removes them, when the publisher application is uninstalled, or when the user performs the “clear data” action on the publisher application from the device’s Settings application.
However, the publisher application can disable pinned shortcuts so they cannot be started. See the following sections for details.
应用快捷方式可分为
Static Shortcuts(静态快捷方式)
和
Dynamic Shortcuts(动态快捷方式)
两种。
下面分别来讲述如何创建静态快捷方式和动态快捷方式。
创建静态快捷方式
shortcuts
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
>
shortcut
android
:
shortcutId
=
"compose"
android
:
enabled
=
"true"
android
:
icon
=
"@drawable/compose_icon"
android
:
shortcutShortLabel
=
"@string/compose_shortcut_short_label1"
android
:
shortcutLongLabel
=
"@string/compose_shortcut_long_label1"
android
:
shortcutDisabledMessage
=
"@string/compose_disabled_message1"
>
intent
android
:
action
=
"android.intent.action.VIEW"
android
:
targetPackage
=
"com.example.myapplication"
android
:
targetClass
=
"com.example.myapplication.ComposeActivity"
/>
categories
android
:
name
=
"android.shortcut.conversation"
/>
shortcut
>
shortcuts
>
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
>
补充
:注意第 2 点的描述,也就是说如果 Manifest 中存在多个满足条件的 Activity ,那么就可以存在多组应用快捷方式,但资源文件必须不同,主要是 shortcutId 必须不同,否则不会显示。大家可以自己去尝试下~
标签属性含义如下:
shortcutId
:快捷方式的唯一标识。
当用户拖拽快捷方式到桌面,只要
shortcutId
不变,修改
shortcut
>
其余属性值,重新打包,修改之后的变化会体现到已拖拽到桌面的快捷方式上。
若存在多个
shortcut
>
但
shortcutId
相同,则只会显示一个
icon
:快捷方式图标
shortcutShortLabel
:快捷方式的
Label
,当用户拖拽快捷方式到桌面时,显示的也是该字符串
shortcutLongLabel
:长按
app
图标出现快捷方式时显示的图标
shortcutDisabledMessage
:当快捷方式被禁用时显示的提示语
enabled
:标识快捷方式是否可用,可用时,快捷方式图标正常显示,点击跳转到对应的
intent
;不可用时,快捷方式图标变灰,点击弹出
shortcutDisabledMessage
对应字符串的
Toast
intent
:快捷方式关联的
intent
,当用户点击快捷方式时,列表中所有
intent
都会被打开,但用户看见的是列表中最后一个
intent
。
categories
:用于指定
shortcut
的
category
,目前只有
SHORTCUT_CATEGORY
_
CONVERSATION
一个值
补充:如果
shortcuts
>
中只有一个
shortcut
>
且
enabled
=
false
,那么长按
app
图标是不会弹出任意快捷方式
gradle 配置:
apply
plugin
:
'com.android.application'
android
{
//如果只是创建静态快捷方式,那么版本号任意
//即使 compileSdkVersion 、targetSdkVersion 为 23 ,在 Android 7.1 的 Nexus 和 Pixel 设备上也能使用。
//但是如果是创建动态快捷方式,因为则必须使 compileSdkVersion 为 25
compileSdkVersion
25
buildToolsVersion
"25.0.0"
defaultConfig
{
applicationId
"com.littlejie.shortcuts"
minSdkVersion
23
targetSdkVersion
25
versionCode
1
versionName
"1.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
}
// something else ...
}
关于 compileSdkVersion 、 minSdkVersion 以及 targetSdkVersion 的区别可参考这篇文章
创建动态快捷方式
创建动态快捷方式主要依靠 ShortManager 、 ShortcutInfo 和 ShortcutInfo.Builder 这几个类来实现。ShortcutInfo 和 ShortcutInfo.Builder 主要用来构造快捷方式对象, ShortManager 是一个系统服务,用于管理应用快捷方式,ShortManager 可以通过以下方式获取:
ShortManager
shortManager
=
(
ShortcutManager
)
getSystemService
(
Context
.
SHORTCUT_SERV
ICE
);
ShortManager 主要有以下几个功能:
-
发布:通过调用 setDynamicShortcuts(List) 替换整个快捷方式列表或者通过 addDynamicShortcuts(List) 往已存在的快捷方式列表中添加快捷方式。
-
更新:调用 updateShortcuts(List) 来更新已存在的快捷方式列表
-
移除:调用 removeDynamicShortcuts(List) 移除列表中指定快捷方式,调用 removeAllDynamicShortcuts() 移除列表中所以快捷方式。
-
禁用:因为用户可能将您任意的快捷方式拖拽到桌面,而这些快捷方式会将用户引导至应用中不存在或过期的操作,所以可以通过调用 disableShortcuts(List) 来禁用任何已存在的快捷方式。调用 disableShortcuts(List, Charsquence) 会给出错误提示。
下面代码主要演示了使用 ShortManager 实现动态发布、更新、移除以及禁用快捷方式。
动态创建快捷方式核心代码:
public
class
MainActivity
extends
Activity
implements
View
.
OnClickListener
{
private
static
final
String
TAG
=
MainActivity
.
class
.
getSimpleName
();
private
ShortcutManager
mShortcutManager
;
private
ShortcutInfo
[]
mShortcutInfos
;
@
Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_main
);
//这里常量Context.SHORTCUT_SERVICE会报错,不用管,可正常编译。看着烦的话把minSdkVersion改为25即可
mShortcutManager
=
(
ShortcutManager
)
getSystemService
(
Context
.
SHORTCUT_SERVICE
);
mShortcutInfos
=
new
ShortcutInfo
[]{
getShoppingShortcut
(),
getDateShortcut
()};
findViewById
(
R
.
id
.
btn_set
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_add
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_update
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_disabled
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_remove
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_removeAll
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_print_max_shortcut_per_activity
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_print_dynamic_shortcut
).
setOnClickListener
(
this
);
findViewById
(
R
.
id
.
btn_print_static_shortcut
).
setOnClickListener
(
this
);
}
private
ShortcutInfo getAlarmShortcut
(
String
shortLabel
)
{
if
(
TextUtils
.
isEmpty
(
shortLabel
))
{
shortLabel
=
"Python"
;
}
ShortcutInfo
alarm
=
new
ShortcutInfo
.
Builder
(
this
,
"alarm"
)
.
setIntent
(
new
Intent
(
Intent
.
ACTION_VIEW
,
Uri
.
parse
(
"https://www.baidu.org/"
)))
.
setShortLabel
(
shortLabel
)
.
setLongLabel
(
"不正经的闹钟"
)
.
setIcon
(
Icon
.
createWithResource
(
this
,
R
.
mipmap
.
ic_alarm
))
.
build
();
return
alarm
;
}
private
ShortcutInfo getShoppingShortcut
()
{
ShortcutInfo
shopping
=
new
ShortcutInfo
.
Builder
(
this
,
"shopping"
)
.
setIntent
(
new
Intent
(
Intent
.
ACTION_VIEW
,
Uri
.
parse
(
"http://www.taobao.com"
)))
.
setShortLabel
(
"双十一剁手"
)
.
setLongLabel
(
"一本正经的购物"
)
.
setIcon
(
Icon
.
createWithResource
(
this
,
R
.
mipmap
.
ic_shopping
))
.
build
();
return
shopping
;
}
private
ShortcutInfo getDateShortcut
()
{
ShortcutInfo
date
=
new
ShortcutInfo
.
Builder
(
this
,
"date"
)
.
setIntent
(
new
Intent
(
Intent
.
ACTION_VIEW
,
Uri
.
parse
(
"http://www.google.com"
)))
.
setShortLabel
(
"被强了"
)
.
setLongLabel
(
"日程"
)
.
setIcon
(
Icon
.
createWithResource
(
this
,
R
.
mipmap
.
ic_today
))
.
build
();
return
date
;
}
@
Override
public
void
onClick
(
View
view
)
{
switch
(
view
.
getId
())
{
case
R
.
id
.
btn_set
:
setDynamicShortcuts
();
break
;
case
R
.
id
.
btn_add
:
addDynamicShortcuts
();
break
;
case
R
.
id
.
btn_update
:
updateDynamicShortcuts
();
break
;
case
R
.
id
.
btn_disabled
:
disableDynamicShortcuts
();
break
;
case
R
.
id
.
btn_remove
:
removeDynamicShortcuts
();
break
;
case
R
.
id
.
btn_removeAll
:
removeAllDynamicShortcuts
();
break
;
case
R
.
id
.
btn_print_max_shortcut_per_activity
:
printMaxShortcutsPerActivity
();
break
;
case
R
.
id
.
btn_print_dynamic_shortcut
:
printDynamicShortcuts
();
break
;
case
R
.
id
.
btn_print_static_shortcut
:
printStaticShortcuts
();
break
;
}
}
/**
* 动态设置快捷方式
*/
private
void
setDynamicShortcuts
()
{
mShortcutManager
.
setDynamicShortcuts
(
Arrays
.
asList
(
mShortcutInfos
));
}
/**
* 添加快捷方式
*/
private
void
addDynamicShortcuts
()
{
mShortcutManager
.
addDynamicShortcuts
(
Arrays
.
asList
(
getAlarmShortcut
(
null
)));
}
/**
* 更新快捷方式,类似于Notification,根据id进行更新
*/
private
void
updateDynamicShortcuts
()
{
mShortcutManager
.
updateShortcuts
(
Arrays
.
asList
(
getAlarmShortcut
(
"Java"
)));
}
/**
* 禁用动态快捷方式
*/
private
void
disableDynamicShortcuts
()
{
mShortcutManager
.
disableShortcuts
(
Arrays
.
asList
(