乐于分享
好东西不私藏

Flutter 解锁 App Shortcuts:让应用入口快人一步

Flutter 解锁 App Shortcuts:让应用入口快人一步

人生路上我们总在寻找捷径,当然,是合乎道德的那一种。但如果我告诉你,在你的移动应用中也能实现这种“捷径”呢?

本文将深度剖析 App Shortcuts 的原理、类型以及在 Flutter 中的完整落地方案。


过在学习这件事上,可没有捷径可言,所以请确保你读到了最后。

一、什么是 App Shortcuts?

作为开发者,我们可以定义快捷方式(Shortcuts),让用户直接跳转到应用内的特定页面或流程,大幅减少操作步骤。

最终目的:通过提升导航效率,极致优化用户体验。

你一定见过这种交互

长按任何应用图标,都会弹出一个快捷菜单。这些快捷方式分为两类:

  1. ‎系统快捷方式:如“应用锁”、“卸载”、“分享”等,各应用表现一致。
  2. ‎应用自定义快捷方式:如“扫一扫”、“付款”,由开发者定义。

它们不仅出现在系统桌面,还能被 Google 助手等语音助手调用,让用户快速触达核心功能。

命名差异:在 Android 上称为 Shortcuts;在 iOS 上,桌面快捷方式通常被称为 Quick Actions(或 Home Screen Quick Actions)。


二、Shortcuts 的三大类型

类型
特点
修改时机
可见性
‎静态 (Static)
固定不变
仅限安装时定义,运行时不可改
安装后立即显示
‎动态 (Dynamic)
随用户行为变化
运行时可增、删、改
依赖应用逻辑,需 App 主动创建
‎固定 (Pinned)
用户钉在桌面
用户手动固定或代码请求固定
始终可见,直达体验

1. 静态快捷方式 (Static Shortcuts)

提供对常用、预定义操作的快速访问。它们在应用安装后立即可用,即使从未打开过 App。

特点:因在编译时定义,运行时无法修改。任何变更都需要发版。

常见示例:Gmail 的“收件箱”、YouTube 的“搜索”。

Android 实现 (shortcuts.xml)

在 res/xml/ 目录下创建 shortcuts.xml:

<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">

    <shortcut
        android:shortcutId="new_post_static"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutShortLabel="@string/shortcut_new_post_short"
        android:shortcutLongLabel="@string/shortcut_new_post_long">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.app_shortcuts"
            android:targetClass="com.example.app_shortcuts.MainActivity">
            <extra android:name="shortcutId" android:value="new_post" />
            <extra android:name="source" android:value="static" />
        </intent>
    </shortcut>

    <shortcut
        android:shortcutId="test_shortcut_static"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutShortLabel="@string/shortcut_test_short"
        android:shortcutLongLabel="@string/shortcut_test_long">
        <!-- 省略 intent -->
    </shortcut>

</shortcuts>

注意:由于无法访问外部 URL,此处为等效的本地实现示例。
并在 AndroidManifest.xml 中引用:

<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />

iOS 实现 (Info.plist)

在 Info.plist 中添加 UIApplicationShortcutItems 数组:

<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>new_post_static</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>New Post</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>Create a new post</string>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypeCompose</string>
        <key>UIApplicationShortcutItemUserInfo</key>
        <dict>
            <key>shortcutId</key>
            <string>new_post</string>
            <key>source</key>
            <string>static</string>
        </dict>
    </dict>
    <!-- 更多 Shortcut ... -->
</array>

处理点击:需要通过 MethodChannel 在原生侧捕获启动事件,传递给 Flutter 侧进行路由跳转(完整代码见文末)。


2. 动态快捷方式 (Dynamic Shortcuts)

基于用户交互和应用内活动动态变化。与静态不同,它们可以在运行时创建、更新或删除。

特点:安装后不会立即可见,需等待应用逻辑触发。

常见示例:从最近的存档点恢复游戏,或打开用户上次阅读到的书籍页码。

Flutter 实现 (quick_actions 包)

  1. ‎初始化:在 App 生命周期早期初始化,并设置回调。
    final QuickActions quickActions = const QuickActions();
    quickActions.initialize((shortcutType) {
      if (shortcutType == 'action_main') {
        print('用户点击了 "主视图" 快捷方式');
      }
      // 更多处理逻辑...
    });
  2. ‎管理快捷方式:
    quickActions.setShortcutItems(<ShortcutItem>[
      const ShortcutItem(type: 'action_main', localizedTitle: '主视图', icon: 'icon_main'),
      const ShortcutItem(type: 'action_help', localizedTitle: '帮助', localizedSubtitle: '点击获取帮助', icon: 'icon_help'),
    ]);
  3. ‎清除所有动态快捷方式:
    await quickActions.clearShortcutItems();

3. 固定快捷方式 (Pinned Shortcuts)

允许用户将特定操作直接钉在桌面上,实现一键直达。通常用于高度个性化或高频使用的功能。

示例:将特定聊天置顶、钉住支付流程入口。

  • ‎平台支持:主要支持 Android。iOS 无直接等价物,但可通过 Widget 或 Siri Shortcuts 实现类似效果。
  • ‎用户操作:长按应用图标 -> 长按快捷方式 -> 拖到桌面。

Flutter 实现 (pinned_shortcuts 包)

// 请求系统添加固定快捷方式。用户会看到系统确认弹窗。
// 注意:我们无法得知用户是接受还是取消,因此不要假设操作一定成功。
Future<void> createNetworkPinnedShortcut() {
  return FlutterPinnedShortcuts.createPinnedShortcut(
    id: AppConstants.defaultPinnedShortcutId,
    label: AppConstants.defaultPinnedShortcutLabel,
    imageSource: AppConstants.pinnedShortcutImageUrl,
    imageSourceType: ImageSourceType.network,
    adaptiveIconForeground: AppConstants.pinnedShortcutImageUrl,
    adaptiveIconBackground: AppConstants.pinnedShortcutBgColor,
    adaptiveIconBackgroundType: AdaptiveIconBackgroundType.color,
    extraData: const {'type': 'adaptive_color'},
  );
}

检测支持性与处理点击:

Future<void> _initPinned() async {
  // 监听固定快捷方式的点击事件
  _pinnedSub = FlutterPinnedShortcuts.onShortcutClick.listen((data) {
    final id = data['id']?.toString();
    if (id == null) return;
    // 处理跳转逻辑...
  });

  await FlutterPinnedShortcuts.initialize();
  final supported = await FlutterPinnedShortcuts.isSupported();
  if (!supported) {
    // 部分启动器或旧设备不支持固定。静默退出,不影响其他功能。
    debugPrint('当前设备不支持固定快捷方式');
    await _pinnedSub?.cancel();
    _pinnedSub = null;
    return;
  }
}

三、集成前的关键考量

  1. ‎数量限制:可见的快捷方式数量受 OS 或启动器限制。通常最多显示 4 个(静态与动态混合)。
  2. ‎静态不可变:静态快捷方式在运行时无法修改,任何更改都需要应用更新。
  3. ‎动态排名:动态快捷方式的可见性取决于系统排名因素(如使用历史、最近使用、频率)。
  4. ‎排序规则:静态快捷方式遵循 XML 中的定义顺序;动态快捷方式通过代码分配排名。
  5. ‎固定快捷方式的差异:它们可以支持原生资源、Flutter 资源甚至网络图片(取决于实现)。
  6. ‎‎quick_actions 包的局限性:
    • 不支持禁用快捷方式。
    • 不暴露备份相关标志。
    • 对于此类高级用例,需使用 平台通道 (Platform Channels) 自行实现。

四、最佳实践

  1. ‎确保唯一 ID:如果新快捷方式使用了现有 ID,它将更新旧的那个。
  2. ‎优先使用 Deep Link:对于动态快捷方式,使用深度链接而非硬编码的路由字符串。这能让你对导航有更好的灵活性和控制力。
  3. ‎妥善处理冷启动与热启动:确保快捷方式回调在 App 未运行(冷启动)和已运行(热启动)时都能正确初始化并跳转。
  4. ‎使用有意义的图标:静态和动态快捷方式应引用原生资源(iOS 的 ‎xcassets 或 Android 的 ‎drawable 资源)。
  5. ‎保持动态快捷方式的相关性:根据用户的近期行为和频率更新它们。
  6. ‎拓展至搜索与助手:若想在启动器之外(如 Google 搜索)展示快捷方式,可集成 Google Shortcuts Integration Library。

五、结语

有人创建了一个示例应用,演示了静态、动态和固定快捷方式的实现,并处理了冷启动与热启动场景。它还包含使用 SharedPreferences 进行持久化的逻辑。感兴趣的可以看看https://github.com/anupam92402/app_shortcuts

掌握 App Shortcuts 不仅能提升你应用的用户体验,更是让你的产品融入系统生态、提升用户留存的关键一步。


💡 架构师视角 (Bonus)

  1. ‎Deep Link 路由设计
    处理快捷方式点击的核心在于路由。推荐使用 ‎go_router 等支持深度链接的路由库,将快捷方式传递的 ‎extraData 映射为统一的路由路径。

  2. ‎原生与 Flutter 的桥梁
    对于 ‎quick_actions 或 ‎pinned_shortcuts 包未覆盖的高级功能(如禁用、备份标志),你需要编写 Platform Channel (‎MethodChannel) 代码,在 Android 侧调用 ‎ShortcutManager 或 iOS 侧调用 ‎UIApplication 的相关 API。

  3. ‎国内 Android 生态适配
    华为、小米、OPPO 等定制 ROM 对快捷方式的支持程度和交互略有差异。务必在主流国产机型上进行真机测试,并参考各厂商的桌面快捷方式适配文档。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料