Deep Links 在 Flutter:初学者终极指南(无第三方包)(第1部分)
Source: Dev.to
想象一下: 你的用户收到一个折扣链接,点击它 — 然后 BOOM! 不仅打开了你的应用,还直接进入了已应用优惠券的结算页面。
这像魔法吗?不是 —— 这就是 Deep Links!
系列目标
- 在 Flutter 中实现 deep links 不使用现成的包。
- 学习其底层工作原理。
你将在本文中学习的内容
- 什么是深度链接。
- App Links 与 Custom Schemes 的区别。
- 如何在 Flutter 中构建基础结构。
基础概念
Deep links 是将用户直接带到应用特定页面的 URL,而不是在浏览器中打开。
实际示例
| 传统流程 | 深度链接 |
|---|---|
| 1️⃣ 打开浏览器 → 2️⃣ 用户安装应用 → 3️⃣ 打开应用 → 4️⃣ 导航到目标页面 | 1️⃣ 直接在正确页面打开应用(即使应用尚未安装 – Deferred Deep Linking)。 |
延迟深度链接 (Deferred Deep Linking)
下面的图示说明了称为 Deferred Deep Linking 的路由方式,即使用户尚未安装应用,链接的上下文在经过应用商店后仍会被保留。
完整流程:
1. 用户点击链接 →
2. 如果应用未安装,重定向到商店 →
3. 用户安装应用 →
4. 打开后,应用接收原始链接并导航到正确的页面。链接示例
https://fitconnect.app/signup?referralCode=TRAINER12345| 部分 | 值 |
|---|---|
| Scheme | https |
| Host | fitconnect.app |
| Path | /signup |
| Query | referralCode=TRAINER12345 |
每个部分在导航中都有特定作用:scheme 标识协议(或在自定义 scheme 的情况下标识应用);host 和 path 决定路由;query parameters 携带额外数据(例如:推荐码)。
深度链接类型
1️⃣ 自定义 Scheme
fitconnect://fitconnect.app/signup?referralCode=TRAINER12345- ✅ 实现快速。
- ✅ 适合本地测试。
- ⚠️ 安全性较低 — 任何应用都可以注册相同的 scheme。
- ⚠️ 如果未安装应用,系统会显示一个难看的错误。
2️⃣ HTTPS(App Links / Universal Links)
https://fitconnect.app/signup?referralCode=TRAINER12345- ✅ 安全 — 应用与服务器之间的双向验证。
- ✅ 如果未安装应用,会在浏览器中正常打开。
- ✅ 推荐用于生产环境。
- ⚠️ 需要自有域名。
- ⚠️ 设置更复杂。
什么是双向验证?
操作系统仅在双方相互识别时才会打开应用:
App 声明它处理哪些域名。
服务器 通过托管在该域名下的文件确认哪些应用有权限:
- Android →
assetlinks.json - iOS →
apple-app-site-association
- Android →
如果这些文件中的任何一个缺失或不一致,链接会作为回退在浏览器中打开,防止恶意应用拦截你的链接。
提示: 在开发期间使用自定义 scheme,生产环境迁移到 HTTPS(App Links / Universal Links)。
用例:FitConnect
我们来构建 FitConnect —— 一个虚构的平台,通过推荐系统将私人教练与客户连接起来。
场景
- Maria,私人教练,分享她的推荐链接。
- 当学生使用该链接注册时,Maria 获得奖励,学生获得折扣。
系列主深度链接
https://fitconnect.app/signup?referralCode=TRAINER12345678901234点击后,应用应直接打开注册页面,且代码 TRAINER12345678901234 已预填。
| 项目 | 值 |
|---|---|
| 域名 | fitconnect.app |
| 自定义方案 | fitconnect:// |
| Package (Android) | com.fitconnect.app |
Source: …
准备结构
在编写原生代码之前,我们先定义将在应用所有层之间共享的 常量、枚举和模型。集中管理字符串(例如 channel 名称)可以避免难以追踪的拼写错误。
常量
// lib/shared/const/deep_link_const.dart
class DeepLinkConst {
static const String methodChannel = 'com.fitconnect.app/deeplink';
static const String eventChannel = 'com.fitconnect.app/deeplink_stream';
static const String customScheme = 'fitconnect';
static const String httpsScheme = 'https';
static const String appHost = 'fitconnect.app';
static const String signupPath = '/signup';
static const String referralCodeParam = 'referralCode';
static const int referralCodeLength = 20;
}Deep Link 类型枚举
// lib/shared/enums/deep_link_type.dart
enum DeepLinkType {
customScheme,
appLink, // Android HTTPS
universalLink, // iOS HTTPS
unknown;
bool get isSecure => this == appLink || this == universalLink;
}
isSecuregetter 让代码更具可读性——不需要手动比较字符串或检查 scheme,只需使用data.type.isSecure即可。
数据模型(使用 Freezed)
// lib/shared/models/deep_link_data.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'deep_link_type.dart';
part 'deep_link_data.freezed.dart';
part 'deep_link_data.g.dart';
@freezed
class DeepLinkData with _$DeepLinkData {
const factory DeepLinkData({
required String url,
required DeepLinkType type,
required String scheme,
String? host,
String? path,
@Default({}) Map<String, dynamic> queryParameters,
String? referralCode,
}) = _DeepLinkData;
factory DeepLinkData.fromJson(Map<String, dynamic> json) =>
_$DeepLinkDataFromJson(json);
}为什么使用 Freezed?
- 保证 不可变性。
- 自动生成
copyWith、==、hashCode以及 JSON(反)序列化代码。- 便于维护携带关键参数的对象(例如:推荐码)。
Source: …
下一步
- 实现原生层(Android 与 iOS)以拦截链接。
- 在 Flutter 中创建导航流程,消费
DeepLinkData。 - 配置 App Links / Universal Links(
assetlinks.json与apple-app-site-association文件)。 - 测试,既要在 debug 模式下(自定义 scheme)也要在 生产 环境(HTTPS)进行。
在后续文章中我们将详细阐述这些内容,包括双向验证文件的配置(第 5 篇)以及在 Flutter 中的完整集成。
下次见! 🚀
eferralCode,
required DateTime receivedAt,
}) = _DeepLinkData;
}完成本阶段后,你将拥有:
- 对 deep link 工作原理的清晰认识。
- 对不同类型链接的理解。
- 在 Flutter 中的坚实基础,便于开始实现。
这套基础将在后续步骤中用于集成原生代码,完成端到端的流程。
下一步
在下一阶段,我们将进入 Android 原生实现——包括完整的 AndroidManifest.xml 与 MainActivity.kt。
完整代码已在仓库中提供:GitHub 上的 FitConnect 项目。
关于系列文章
这是 9 篇 深度链接系列的 第一篇。在后续文章中,我们将讨论:
- Android 与 iOS 的原生代码
- 延迟链接(Deferred links)
- 重定向页面
- 测试
全部 不依赖现成的第三方库。
如果你有疑问、建议,或曾遇到类似 deep link 的问题,欢迎在评论区留言!我很乐意了解这些经验在真实项目中的应用。
想跟进后续文章,只需在 Medium 上关注本账号即可。
反馈
如果本文对你有帮助,请在 DEV.to 上点个 ❤️ 或 🔖——这会帮助文章被更多开发者看到。
社区提问
你是否已经在自己的应用中实现了 deep link?
遇到的最大挑战是什么?我想在系列的后续文章中使用这些真实案例 👇
标签
flutter android ios deeplinks mobile programming