记一次 Universal Links 使用与APP微信登录及总结

记一次 Universal Links 使用与APP微信登录及总结

文章目录

  • 前言
  • 需求环境
  • 含义与作用
    • 1.1 什么是 Universal Links
    • 1.2 核心用途
    • 1.3 与 URL Scheme 对比
  • apple-app-site-association 文件
    • 2.1 文件说明
    • 2.2 放置位置
    • 2.3 文件内容示例
    • 2.4 服务端要求
    • 注意:不要求必须搭建web服务器,可以放到CDN中哦~
  • 完整配置方法
    • 3.1 服务端部署 AASA 文件
    • 3.2 Apple Developer 配置
    • 3.3 Xcode 配置
    • 3.4 代码配置
    • 3.5 微信开放平台配置
  • 作用流程
    • 4.1 Apple CDN 验证流程(App 安装时)
    • 4.2 用户点击链接流程
    • 4.3 微信登录回调流程
  • 注意事项
    • 5.1 三处配置必须保持一致
    • 5.2 修改时的推荐操作顺序
    • 5.3 版本兼容策略
    • 5.4 常见踩坑点
    • 5.5 用户禁用场景
  • 验证与调试
    • 6.1 验证检查清单
    • 6.2 验证命令
  • 为什么 URL Scheme 会被盗用
    • URL Scheme 的工作方式
    • 具体攻击场景
  • 为什么 Universal Links 能证明身份
    • 核心原理:用 HTTPS 域名所有权做背书
    • 和 URL Scheme 的对比
    • 黑产能仿冒 Universal Links 吗?
  • 总结

前言

又月底了,总得再凑出一篇不是,在AI大行其道的时代,手搓文章可能又要变成古法写作,不久将被评为非遗传承人了,哈哈哈,不过不管AI怎么发展总会给手搓留下一席之地,就像现在拍张已经非常方便了,但是绘画依旧有自己市场一样,AI可以写主要部分,但是认为的记录还是有一些精华点的,不然满屏的AI味实在让人看不下去,昨晚看到一个观点挺有意思,之前总说加密货币没有意义,浪费电,但是在AI横行的时代,在难辨真假的时代,消耗能源镌刻进资源的方式,或许本身就是一种意义,就好似密码学中引入工作负载,来破解难度一样,所以如果把加密大模型绑定到一起,那不是电上加电变成电的平方了嘛。

跑远了,说回本文重点,Universal Links,苹果的东东,主要是最近APP接入微信登录,需要配置这东西实现登录后打开APP的目的。

需求环境

Apple App Site Association 配置完全指南
适用于 iOS 13+ / 微信 OpenSDK 1.8.6+


含义与作用

1.1 什么是 Universal Links

Universal Links(通用链接)是 Apple 在 iOS 9 推出的机制,通过标准 HTTPS 链接直接打开 App,建立网站域名与 iOS/macOS App 之间的信任关系。

1.2 核心用途

  • 通用链接:点击网页链接直接打开 App,无需跳转浏览器,App 未安装时自动降级到 Safari
  • Handoff / Shared Web Credentials:跨设备接力,Safari 密码可在 App 内自动填充
  • 第三方 SDK 回调:微信等 SDK 用于 App 间相互唤起时的安全校验通道

1.3 与 URL Scheme 对比

对比项URL SchemeUniversal Links
安全性低,可被其他 App 劫持高,Apple CDN 校验,无法劫持
App 未安装报错或无响应自动降级到 Safari
配置复杂度简单需要服务端 + 客户端协同
iOS 版本iOS 3+iOS 9+
微信 SDK旧版(已废弃)SDK 1.8.6+ 强制要求

apple-app-site-association 文件

2.1 文件说明

  • 纯文本 JSON 格式
  • 文件名固定为apple-app-site-association无任何后缀
  • 必须部署在 HTTPS 域名下,不能有重定向

2.2 放置位置

Apple 按以下顺序检查,推荐第一个:

https://example.com/.well-known/apple-app-site-association ← 推荐 https://example.com/apple-app-site-association

2.3 文件内容示例

{"applinks":{"apps":[],"details":[{"appID":"TEAMID.com.example.myapp","paths":["/app/*"]}]}}

这面这种使用或者下面这种推荐格式

{"applinks":{"details":[{"appIDs":["TEAMID.com.example.myapp"],"components":[{"/":"/app/*"},{"/":"/product/*"},{"/":"/user/*/profile"}]}]},"webcredentials":{"apps":["TEAMID.com.example.myapp"]}}

2.4 服务端要求

要求项说明
协议必须 HTTPS,证书有效,不接受 HTTP
重定向不能有重定向,Apple CDN 不跟随跳转
Content-Type返回application/json
文件名apple-app-site-association,无后缀
path 通配符末尾必须加/*,微信等 SDK 会在路径后拼接参数
appID 格式TeamID + BundleID,如ABCDE12345.com.example.myapp

注意:不要求必须搭建web服务器,可以放到CDN中哦~

完整配置方法

3.1 服务端部署 AASA 文件

确保 path 加通配符,微信会在 Universal Link 末尾拼接路径和参数:

"components":[{"/":"/app/*"}]

3.2 Apple Developer 配置

  1. 登录 Apple Developer → Identifiers
  2. 找到对应 App,开启Associated Domains能力
  3. 如使用手动 Profile,需重新生成描述文件

3.3 Xcode 配置

在 Signing & Capabilities 添加 Associated Domains:

applinks:example.com applinks:www.example.com applinks:example.com?mode=developer // 开发调试模式

3.4 代码配置

SDK 注册(以微信为例):

WXApi.registerApp("wx1234567890abcdef",universalLink:"https://example.com/app/")

处理回调 — SceneDelegate(iOS 13+):

funcscene(_scene:UIScene,continueuserActivity:NSUserActivity){guarduserActivity.activityType==NSUserActivityTypeBrowsingWeb,leturl=userActivity.webpageURLelse{return}handleUniversalLink(url)}

处理回调 — AppDelegate(兼容旧版):

funcapplication(_application:UIApplication,continueuserActivity:NSUserActivity,...)->Bool{guardleturl=userActivity.webpageURLelse{returnfalse}handleUniversalLink(url)returntrue}

3.5 微信开放平台配置

  1. 登录 open.weixin.qq.com → 管理中心 → 移动应用
  2. 找到对应应用 → 开发信息 → 修改
  3. 在 iOS 应用 → Universal Links 中填入https://example.com/app/
  4. 注意:结尾必须有 /

作用流程

4.1 Apple CDN 验证流程(App 安装时)

App 安装 → iOS 读取 Entitlement 中的 Associated Domains → Apple CDN 请求 AASA 文件 https://app-site-association.cdn-apple.com/a/v1/example.com → 验证 appIDs 中的 TeamID + BundleID 与 App 匹配 → 缓存路径规则到设备 → Universal Links 生效 验证失败 → 链接只在浏览器打开

Apple 通过自己的 CDN 代理请求,不是设备直连服务器,更新 AASA 后最长延迟24~48 小时生效。

4.2 用户点击链接流程

用户点击 https://example.com/app/xxx → iOS 检查本地缓存路径规则 → 路径匹配? ├── 是 → App 已安装? │ ├── 是 → 直接打开 App,触发 continueUserActivity 回调 │ └── 否 → Safari 打开(可配置 Smart App Banner 引导下载) └── 否 → Safari 打开

4.3 微信登录回调流程

你的 App 调用微信 SDK 发起登录 → 跳转微信 App,用户授权 → 微信通过 Universal Link 唤起你的 App (在路径后拼接 code、state 等参数) → 触发 continueUserActivity 回调 → WXApi.handleOpenUniversalLink 解析登录结果

注意事项

5.1 三处配置必须保持一致

微信开放平台后台 https://example.com/app/ ↕ 必须相同 SDK 注册代码 universalLink: "https://example.com/app/" ↕ path 必须能覆盖 AASA 文件 { "/": "/app/*" }

修改任意一处,必须同时更新其他两处,否则校验失败。

5.2 修改时的推荐操作顺序

  1. 先更新服务端 AASA 文件并验证可访问
  2. 更新微信开放平台后台配置
  3. 更新代码中 SDK 注册的universalLink参数
  4. 发版

5.3 版本兼容策略

修改域名或路径时,新旧路径应在 AASA 中同时保留一段时间,待旧版用户自然升级后再移除旧路径。

5.4 常见踩坑点

问题原因解决方法
Universal Links 不生效AASA 未正确部署或有重定向curl 验证文件可访问,检查 Content-Type
微信授权出现二次确认弹窗Universal Link 校验失败检查三处配置是否一致
path 匹配失败末尾缺少通配符/*改为/app/*格式
appID 不匹配TeamID 或 BundleID 填错在 Apple Developer 后台核实 TeamID
修改后未生效AASA 只在首次安装时下载删除 App 重新安装
WKWebView 内链接不触发WKWebView 不自动触发 UL手动拦截decidePolicyFor处理
Apple CDN 延迟Apple 通过 CDN 代理,非实时更新后最长 24~48 小时生效
企业签名证书失效部分企业证书不具备 UL 能力使用开发签名证书调试

5.5 用户禁用场景

用户长按链接选择「在 Safari 中打开」后,该域名 Universal Links 被临时禁用,需在 Safari 中点击顶部 Banner 重新启用。


验证与调试

6.1 验证检查清单

检查项正确值
AASA Content-Typeapplication/json
HTTPS 证书有效,无自签名,无重定向
Team ID与 Apple Developer 后台一致
Bundle ID与 Xcode 项目一致
path 末尾必须有通配符/*
Entitlement 格式applinks:前缀,无https://
三处 URL 一致性微信后台 = SDK 注册 = AASA path 覆盖

6.2 验证命令

# 验证 AASA 可访问curl-Ihttps://example.com/.well-known/apple-app-site-association# 查看 Apple CDN 缓存内容curlhttps://app-site-association.cdn-apple.com/a/v1/example.com# 模拟器测试链接xcrun simctl openurl booted"https://example.com/app/test"

在线验证工具:https://branch.io/resources/aasa-validator/

为什么 URL Scheme 会被盗用

URL Scheme 的工作方式

任何 App 都可以在Info.plist里声明自己支持某个 Scheme:

<!-- 恶意 App 的 Info.plist --><key>CFBundleURLSchemes</key><array><string>mybank</string><!-- 和你的银行 App 一模一样 --></array>

iOS不做任何唯一性校验,两个 App 声明同一个 Scheme 完全合法。当系统收到mybank://pay?amount=100时,如果两个 App 都安装了,行为是不确定的(通常后安装的会覆盖)。


具体攻击场景

正常流程: 微信 → 调用 mybank://pay → 打开你的银行 App → 完成支付 被盗用后: 微信 → 调用 mybank://pay → 打开黑产仿冒的银行 App ↓ 展示假支付页面 或静默收集参数 或返回假成功给微信

黑产只需要上架一个仿冒 App,声明相同的 Scheme,就能劫持所有通过该 Scheme 发起的跳转。用户完全无感知。


为什么 Universal Links 能证明身份

核心原理:用 HTTPS 域名所有权做背书

Universal Links 的信任链是这样的:

你能在 example.com 放文件 ↓ 说明你是 example.com 的所有者 ↓ 你在 AASA 文件里声明了某个 AppID ↓ 说明该 App 是你发布的 ↓ iOS 信任这个 App 处理 example.com 的链接

关键在于:往域名根目录放文件这件事,只有域名所有者才能做到。


和 URL Scheme 的对比

URL SchemeUniversal Links
声明方式App 本地 Info.plist 自己写服务器上的 AASA 文件
谁能声明任何人,无需审核只有域名所有者
校验时机运行时,iOS 不校验唯一性App 安装时,Apple CDN 主动验证
仿冒成本极低,改个 plist 即可极高,需要控制对方的域名服务器

黑产能仿冒 Universal Links 吗?

假设黑产想劫持https://example.com/app/的跳转:

方案一:伪造 AASA 文件

  • 需要在example.com上放文件
  • 但他们没有example.com的控制权
  • ❌ 无法实现

方案二:自己买个域名

  • 注册examp1e.com,部署 AASA
  • 但链接变成了https://examp1e.com/app/,不是原来的域名
  • 用户或调用方看 URL 就能发现异常
  • ❌ 无法劫持原链接

方案三:在 App 里声明相同的 Universal Link

  • Universal Link 不是 App 声明的,是服务器声明的
  • App 里只有applinks:example.com的 Entitlement
  • Apple CDN 会去example.com验证,AASA 里没有黑产的 AppID
  • ❌ 验证直接失败

总结

  • URL Scheme 是 App自己说自己是谁,没有人核实;
  • Universal Links 是域名服务器替 App 担保,而域名所有权由 HTTPS 证书 + DNS 保证,第三方无法伪造。
  • APP配置微信登后回调时,微信开放平台后台、SDK 注册代码、AASA 文件 配置必须一致https://example.com/app/
  • apple-app-site-association不是必须放在web服务的中访问,也可以放到CDN中,只要能证明域名所有全就行

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

小孩子玩游戏才是真情流露,随心所欲,喜欢就是喜欢,不喜欢就是不喜欢,而大人玩游戏总喜欢斤斤计较,精于算计,看似“聪明伶俐,但已经失去本心。