16、联系人快捷方式:创建联系人快捷方式

快捷方式这个东西,说白了就是让用户少点几下。我刚开始做Android开发那会儿,系统还不支持动态快捷方式,每次更新快捷方式都得卸载重装,那体验真是够呛。后来Android 8.0引入了ShortcutManager,这事儿才算真正靠谱了。

今天咱们就聊聊联系人快捷方式的创建。你想想看,用户每天可能要联系某个人十几次,如果能直接在桌面点一下就能拨号,那体验提升可不是一星半点。

快捷方式的三种形态

Android系统里,快捷方式其实分三种,我习惯把它们叫做“三兄弟”:

类型 说明 适用场景
静态快捷方式 写在xml里,编译时就固定了 固定功能,比如“新建联系人”
动态快捷方式 运行时通过ShortcutManager添加 最近联系人、常用联系人
PinnedShortcut 用户手动固定到桌面的快捷方式 用户主动选择的联系人

嗯,这里要注意:PinnedShortcut是唯一可以出现在桌面上的,其他两种只出现在长按应用图标后的菜单里。

创建动态快捷方式

动态快捷方式最适合联系人系统。用户每次拨号或接听,咱们就可以把那个联系人加到快捷方式列表里。我在项目里就是这么干的,效果还不错。

先看代码:

// 获取ShortcutManager
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

// 构建快捷方式
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "contact_001")
    .setShortLabel("张三")
    .setLongLabel("打电话给张三")
    .setIcon(Icon.createWithResource(this, R.drawable.ic_contact))
    .setIntent(new Intent(Intent.ACTION_DIAL)
        .setData(Uri.parse("tel:13800138000")))
    .build();

// 添加动态快捷方式
shortcutManager.addDynamicShortcuts(Arrays.asList(shortcut));

这里有个坑,我踩过。setShortLabel最多只能10个字符,超了会被截断。setLongLabel可以长一些,但也不建议超过25个字。你想想看,桌面上就那么点地方,太长了也显示不全。

PinnedShortcut:用户说了算

动态快捷方式虽然方便,但用户没法把它拖到桌面上。PinnedShortcut就是干这个的。用户长按应用图标,看到“固定到桌面”的选项,点一下就能把快捷方式钉在桌面上。

实现起来也不复杂:

// 请求固定快捷方式
ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);

if (shortcutManager.isRequestPinShortcutSupported()) {
    ShortcutInfo pinShortcut = new ShortcutInfo.Builder(this, "pinned_contact_001")
        .setShortLabel("李四")
        .setIntent(new Intent(Intent.ACTION_DIAL)
            .setData(Uri.parse("tel:13900139000")))
        .build();

    // 创建PendingIntent,用于接收固定结果
    Intent pinnedIntent = shortcutManager.createShortcutResultIntent(pinShortcut);
    PendingIntent successCallback = PendingIntent.getBroadcast(this, 0,
        pinnedIntent, PendingIntent.FLAG_IMMUTABLE);

    shortcutManager.requestPinShortcut(pinShortcut, successCallback.getIntentSender());
}

我曾经遇到过一个情况:用户固定了快捷方式,但后来那个联系人被删了。这时候点击快捷方式就会报错。所以一定要做容错处理,比如在Intent里加一个fallback页面。

动态快捷方式更新

快捷方式不是一成不变的。用户今天常联系的人,下周可能就不联系了。所以咱们得定期更新。

更新的逻辑其实很简单:

// 更新动态快捷方式
List<ShortcutInfo> updatedShortcuts = new ArrayList<>();

// 假设这是从数据库查出来的最近联系人
List<Contact> recentContacts = contactDao.getRecentContacts(5);

for (Contact contact : recentContacts) {
    ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "contact_" + contact.getId())
        .setShortLabel(contact.getName())
        .setLongLabel("打电话给" + contact.getName())
        .setIcon(Icon.createWithResource(this, contact.getAvatarResId()))
        .setIntent(new Intent(Intent.ACTION_DIAL)
            .setData(Uri.parse("tel:" + contact.getPhone())))
        .build();
    updatedShortcuts.add(shortcut);
}

// 替换所有动态快捷方式
shortcutManager.setDynamicShortcuts(updatedShortcuts);

这里有个细节:setDynamicShortcuts会替换掉所有现有的动态快捷方式。如果你只想更新某几个,可以用updateShortcuts方法。我个人习惯每次全量替换,逻辑更清晰,不容易出bug。

适配Android 8+的注意事项

Android 8.0(API 26)是分水岭。在这之前,创建快捷方式用的是不同的API。咱们做联系人系统,最低支持版本一般都在API 26以上,所以直接用ShortcutManager就行。

但还是有几个点要注意:

  • 权限问题:Android 8.0以后,应用图标长按菜单最多显示5个快捷方式,多了会被忽略
  • 图标大小:快捷方式图标必须是自适应图标(Adaptive Icon),否则在Android 8+上会变形
  • Intent必须明确:不要用隐式Intent,否则系统不知道该怎么处理
  • 唯一ID:每个快捷方式的ID必须唯一,重复添加会覆盖旧的
注意:Android 12开始,动态快捷方式有了新的限制。如果应用在后台,调用addDynamicShortcuts可能会被系统忽略。建议在用户主动操作时(比如点击按钮)才更新快捷方式。

知识体系总览

下面这张图是我整理的快捷方式知识结构,你看一眼就能明白整体脉络:

联系人快捷方式知识体系 ShortcutManager 静态快捷方式 动态快捷方式 PinnedShortcut XML中定义,编译时固定 运行时添加,可更新 用户固定到桌面 核心要点:唯一ID、明确Intent、图标适配、权限检查 Android 8+ 使用 ShortcutManager,注意后台限制
小技巧:我在做联系人快捷方式时,会在每次应用启动时检查动态快捷方式的数量。如果少于3个,就从最近通话记录里补几个。这样用户每次打开都能看到最新的常用联系人。

避坑指南

做快捷方式开发,有几个坑我不得不提:

  • ID冲突:我曾经因为ID重复,导致快捷方式怎么更新都不变。后来排查了半天才发现是ID写死了。建议用“contact_”+数据库ID这种格式。
  • 图标加载:联系人头像可能是从网络加载的,但快捷方式图标必须是本地资源。我一般会在下载头像后,先保存到本地缓存,再用本地路径创建图标。
  • 权限检查:调用requestPinShortcut前,一定要先检查isRequestPinShortcutSupported()。有些厂商的ROM不支持这个功能,直接调用会崩溃。
  • 数量限制:动态快捷方式最多5个,PinnedShortcut没有数量限制,但用户桌面空间有限,别一股脑全加上去。

嗯,快捷方式这块内容就这些。说白了就是让用户少走几步路,咱们开发者多花点心思。你只要把上面这些逻辑理清楚,联系人快捷功能基本就稳了。

公众号:蓝海资料掘金营,微信deep3321