尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

NFC 贴卡打开 App:Android AAR 与 iOS 通用链接实战

发布时间:2026/9/29 6:26:15

资讯中心
01
ARTICLE

NFC 贴卡打开 App:Android AAR 与 iOS 通用链接实战

NFC 贴卡打开 App:Android AAR 与 iOS 通用链接实战
手上做过好几个带 NFC 交互的线下项目从门店会员卡到展台打卡客户的需求描述几乎一模一样手机贴一下装了 App 就直接打开没装就跳到应用市场去下载。这句话说出口只要三秒但真正落到 Android 和 iOS 两端去实现你会发现两者的能力边界差了整整一个数量级。Android 这边只要在标签里写一条android.com:pkg的 AAR 记录系统就会主动帮你完成未安装跳应用市场这件事iOS 那边iPhone 压根不允许第三方标签在用户没确认的情况下把 App 拉起来你能做到的最好效果是弹一条通知横幅等用户抬手点一下。这篇内容我打算把这条链路上所有的关键环节摊开讲NDEF 记录的字节结构怎么算、AAR 到底放在消息的第几条、iOS 的 Universal Link 要配哪几个文件、落地页的 UA 判断怎么写、国内几家安卓厂商的应用市场 scheme 长什么样、以及我踩过的那些明明写了卡就是没反应的坑。适合正在做线下硬件联动 App 的开发者、做活动物料的运营同学以及第一次接触 NFC 标签、还在纠结买 NTAG213 还是 NTAG216 的朋友。代码以 AndroidKotlin和 iOSSwift为主关键配置直接给可复制的完整片段你照着改包名和域名就能跑。1. 需求拆解一句话需求背后的三种技术路径1.1 贴一下自动打开到底是谁在干活很多人第一次做这个需求时的直觉是我在 App 里开个 NFC 读取会话检测到标签就跳转不就行了。这个思路在 Android 上勉强能用但在 iOS 上基本等于白做因为 iOS 的后台标签读取根本不会把控制权交给你的 App它由系统直接处理。真正让贴一下打开 App成立的是操作系统内置的 NDEF 标签分发机制而不是你的 App 主动去读卡。流程是这样的手机的天线感应到场强变化NFC 控制器被唤醒系统框架层读到标签里的 NDEF 消息然后拿这条消息去问一句在场有没有哪个应用愿意处理这个内容。有就启动那个应用并把数据递过去没有就看消息里有没有指向应用商店的线索。理解这个顺序非常重要它决定了你做这件事的着力点根本不在客户端代码而在标签里写什么。客户端要做的只是声明我愿意处理这类内容和处理完别忘了埋点。所以整个方案可以拆成三块标签数据的构造、App 侧的接收声明、以及没装 App 时怎么把用户送到正确的商店。第三块在两端差异最大也是这篇文章的重点。1.2 三种路径的能力对照把常见做法列一下你能直观看出为什么最后大家都会收敛到 NDEF 落地页这个组合。实现路径Android 可行性iOS 可行性关键限制系统 NDEF 分发 自定义 URL Scheme可用不可用于后台读取Scheme 无兜底未安装直接失败系统 NDEF 分发 AAR 记录官方支持可跳商店无此机制AAR 是 Android 独有系统 NDEF 分发 Universal Link可用App Links官方推荐必须配 AASA 文件且走 HTTPSApp 内常驻前台读卡可用但体验差仅 App 处于前台时可用用户得先打开 App逻辑上死循环HCE 卡模拟可用仅限特定场景方向反了这是被读不是读看到这里结论就很清楚了Android 主推 AAR URI 双记录iOS 只能靠 Universal Link 服务端落地页分流。一套标签同时服务两端完全可行代价是标签里要多塞一条记录容量得算清楚。1.3 标签芯片选型别买回来才发现写不下NFC 标签的容量指的是用户可写数据区不是标称的总容量。常见的 NTAG 系列实际可用空间如下型号用户区容量实际可写 NDEF 消息约适用场景NTAG213144 字节约 137 字节只写一条短 URL 或一条 AARNTAG215504 字节约 492 字节URL AAR 业务参数推荐NTAG216888 字节约 872 字节参数很多、带签名校验串Mifare Classic 1K1024 字节约 700 字节兼容性一般不推荐新项目用为什么推荐 NTAG215因为它刚好覆盖了一条 https 落地页 URL 一条 AAR 几个业务参数这个最典型的组合价格也就比 213 贵几毛钱。NTAG213 在只有短域名的时候够用但你的 URL 一旦带上渠道号和活动 ID很容易顶到上限。I2C 那一类带加密的芯片比如 NTAG 424 DNA在防复制上有优势但读写工具和手机兼容性都要单独验证不是所有安卓机都认。NFC 的通信距离通常只有 2 到 4 厘米标签贴纸的安装位置要避开金属背板和电池仓。贴在金属上必须用抗金属标签否则场强被吸收手机贴上去毫无反应这个坑我第一次做门店桌贴的时候就踩过。2. Android 端实现AAR 是唯一能让系统帮你跳市场的钥匙2.1 Android 的 NDEF 分发优先级到底怎么排Android 系统在读到标签后会依次尝试三种 Intent优先级从高到低是ACTION_NDEF_DISCOVERED、ACTION_TECH_DISCOVERED、ACTION_TAG_DISCOVERED。前一个没匹配到应用才会降级尝试下一个。这个设计的意义在于能理解内容的应用优先只能理解标签物理技术的应用兜底什么都不懂的才走最末一级。实际开发中最容易出问题的是匹配到多个应用。比如你写了 https 链接而手机上装了好几个浏览器、微信、支付宝系统就会弹一个选择器让用户挑。用户看到弹窗的那一瞬间你精心设计的无感体验就碎了。这就是为什么必须用 AAR。AAR 全称 Android Application Record它在 NDEF 里的类型名固定是android.com:pkg载荷就是你的应用包名。系统读到这条记录后行为链条是这样的先用 NDEF 里的其他记录比如 URI构造 Intent看有没有应用能接。如果能接的应用就是 AAR 指定的那个包直接启动它不弹选择器。如果没匹配到任何应用或者匹配到的不是指定包就尝试直接按包名启动该应用。如果这个包名的应用根本没装系统会构造一个应用市场的 Intent本质上是market://details?id包名交给设备上处理该协议的应用。第 4 步就是未安装跳应用市场的免费实现。你什么都不用写系统替你做完了。AAR 记录必须放在 NDEF 消息的最后一条。放在中间会导致它后面的记录被忽略这是 Android 的既定行为很多教程没提结果写完卡测试时发现参数丢了排查半天。2.2 NDEF 记录的字节结构拆解动手写卡之前先搞清楚一条 NDEF 记录长什么样出问题时你才能看懂工具报的错。每条记录由三部分组成头部Header、类型字段Type和载荷Payload。头部通常 3 字节短记录模式第一个字节是标志位第二个字节是类型字段长度第三个字节是载荷长度。第一个字节的位定义是这样的最高位MBMessage Begin标记消息的第一条记录次高位MEMessage End标记最后一条接着是CF分块标志和SR短记录标志再往下是ILID 长度标志最低三位是TNF类型名格式。按这个规则算一下URI 记录用知名类型TNF 为 1类型字段是单个字符U0x55。它如果不是最后一条标志位是MB1, ME0, SR1合成十进制就是 0x91。AAR 记录用外部类型TNF 为 4类型字段是 15 个字节的字符串android.com:pkg。它是最后一条标志位是MB0, ME1, SR1合成 0x54。URI 记录的载荷还有一个额外规则第一个字节是 URI 前缀缩写码用来省空间。常见对照如下前缀码对应的 URI 前缀0x00无前缀原样解析0x01http://www.0x02https://www.0x03http://0x04https://0x05tel:所以你写https://nfc.example.com/c/12345时实际字节只有缩写码 0x04 加上nfc.example.com/c/12345省掉了 8 个字节。标签容量紧张的时候这几字节很关键。2.3 Manifest 与 Activity 的完整配置先说声明部分。业务 Activity 需要在 AndroidManifest 里注册两类 intent-filter一类是针对 URI 内容的一类是针对物理技术的兜底。activity android:name.nfc.NfcEntryActivity android:exportedtrue android:launchModesingleTask android:excludeFromRecentstrue intent-filter android:priority100 action android:nameandroid.nfc.action.NDEF_DISCOVERED / category android:nameandroid.intent.category.DEFAULT / data android:schemehttps android:hostnfc.example.com / /intent-filter intent-filter action android:nameandroid.nfc.action.TECH_DISCOVERED / category android:nameandroid.intent.category.DEFAULT / /intent-filter meta-data android:nameandroid.nfc.action.TECH_DISCOVERED android:resourcexml/nfc_tech_filter / /activitylaunchMode用singleTask是有讲究的。用户贴卡的场景下如果 App 已经在后台你肯定不希望再开一个新实例把用户之前的操作状态冲掉。excludeFromRecents是顺手加上的让这个入口 Activity 不出现在最近任务列表里用户回退时不会看到一个空白页。nfc_tech_filter.xml的内容?xml version1.0 encodingutf-8? resources xmlns:xliffurn:oasis:names:tc:xliff:document:1.2 tech-list techandroid.nfc.tech.NfcA/tech techandroid.nfc.tech.Ndef/tech /tech-list /resourcestech-list里写多个tech是与关系必须同时满足写多个tech-list才是或关系。NTAG213/215 用的是 NfcA 协议这里必须写 NfcA只写 Ndef 在部分 ROM 上匹配不到。2.4 接收 Intent 与解析参数Activity 里要处理两条入口冷启动走onCreate热启动走onNewIntent。两个都要写否则 App 在后台时贴卡没反应。class NfcEntryActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) handleNfcIntent(intent) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) handleNfcIntent(intent) } private fun handleNfcIntent(target: Intent?) { target ?: return val action target.action ?: return if (action ! NfcAdapter.ACTION_NDEF_DISCOVERED action ! NfcAdapter.ACTION_TECH_DISCOVERED action ! NfcAdapter.ACTION_TAG_DISCOVERED ) return val tagId target.getParcelableExtraTag(NfcAdapter.EXTRA_TAG) ?.id?.joinToString() { %02X.format(it) } val rawMessages target.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) val uri rawMessages ?.filterIsInstanceNdefMessage() ?.flatMap { it.records.asList() } ?.firstOrNull { it.tnf NdefRecord.TNF_WELL_KNOWN it.type.contentEquals(NdefRecord.RTD_URI) } ?.toUri() // uri 里带着渠道参数tagId 用于后续埋点去重 routeToTarget(uri, tagId) } private fun routeToTarget(uri: Uri?, tagId: String?) { // 解析 path 和 query决定跳首页、活动页还是详情页 } }这里有几个经验点值得单独说。tagId一定要取它是标签的物理 UID用来做同一张卡一天只记一次的埋点去重不然用户反复贴卡会把你的事件量刷爆。另外toUri()在解析失败时会抛异常生产代码一定要包一层 try-catch我见过因为标签被写过奇怪内容导致入口页直接崩溃的线上事故。2.5 未安装时跳应用市场的三条备选路线AAR 带来的系统级跳转是最省事的但它有个副作用跳哪个商店由系统决定通常就是设备预装的厂商商店。这对大多数项目来说没问题但如果你有强渠道诉求就需要额外的兜底逻辑。第一条路线是 AAR 裸用什么都不加。适合随便哪个商店都行的场景代码零成本。第二条路线是在 NDEF 里把 URI 指向你自己域名的落地页落地页里用 JS 依次尝试各家市场的 scheme。这样做的前提是你的 App 已经安装了能接住这些 scheme 的应用但用户没装你的 App所以这条路只能靠落地页兜底而不是靠标签。第三条路线是 App Links 兜底。把 https 域名配好autoVerifytrue标签里的 URI 指向这个域名用户装了 App 并且系统校验通过时直接打开 App 对应页面没装就走浏览器打开落地页落地页再做分流。这条路和第一条并不冲突事实上我通常两个都配AAR 负责装了就直接进URI 负责没装时有网页兜底。intent-filter android:autoVerifytrue action android:nameandroid.intent.action.VIEW / category android:nameandroid.intent.category.DEFAULT / category android:nameandroid.intent.category.BROWSABLE / data android:schemehttps android:hostnfc.example.com / /intent-filterautoVerify需要服务端在https://nfc.example.com/.well-known/assetlinks.json提供校验文件。[ { relation: [delegate_permission/common.handle_all_urls], target: { namespace: android_app, package_name: com.example.myapp, sha256_cert_fingerprints: [你的签名证书 SHA256 指纹] } } ]指纹从签名 keystore 里取用keytool -list -v -keystore your.jks就能看到。注意这里要填的是正式签名的指纹很多人调试用的 debug 签名跑通了换成正式包就失效原因就在这里。多环境测试、正式需要把两个指纹都列进数组。3. iOS 端实现Universal Link 是唯一靠谱的答案3.1 后台读取的硬件门槛和那道绕不过的通知横幅先泼一盆冷水iOS 上做不到 Android 那种贴一下直接进 App。iPhone 的后台 NFC 标签读取由系统统一接管第三方 App 没有机会干预决策过程。硬件门槛也得说清楚。前台读取App 打开着从 iPhone 7 和 iOS 11 开始支持需要你的 App 调用 CoreNFC 会话后台读取App 没开要求 iPhone XS、XR 及之后的机型因为需要 A12 及更新的芯片配合。老机型用户贴上去毫无反应这不是你的代码问题。再说那个通知横幅。即使机型支持iOS 13 及之后的系统会在读到标签后先弹一条通知写着已检测到 NFC 标签用户点一下才会继续处理链接。这意味着你的转化链路上天然多了一次点击做数据预估的时候必须把这个损耗算进去别拿着 Android 的转化率去套 iOS。还有一个容易被忽略的细节iPhone 在亮屏状态下才响应标签。熄屏放着不动是读不到的用户需要按一下电源键把屏幕点亮或者把手机拿起来触发抬手唤醒。这个行为对线下物料的引导文案设计影响很大桌贴上最好加一句点亮屏幕后贴一下。3.2 Universal Link 从 AASA 文件到 Associated DomainsiOS 侧的核心是把标签里的 URI 写成一个能被 Universal Link 接住的地址。整个配置分四步。第一步写 AASA 文件放在https://nfc.example.com/.well-known/apple-app-site-association。注意这个路径没有扩展名Content-Type 要是application/json而且必须能通过 HTTPS 直接访问不能有任何重定向。很多 CDN 默认会把无扩展名的文件当成 404 处理这是配置失败的常见原因。{ applinks: { details: [ { appIDs: [ABCDE12345.com.example.myapp], components: [ { /: /nfc/*, comment: NFC 标签入口 } ] } ] } }appIDs是 Team ID 加包名拼起来的中间用点连接。Team ID 在开发者账号后台的 Membership 页面能看到是 10 位大写字母数字。新版本的 AASA 格式推荐用components而不是老的paths因为components支持排除规则和查询参数匹配控制粒度更细。第二步在 Xcode 里给 App 打开 Associated Domains 能力添加一条applinks:nfc.example.com。注意这里不带https://也不带路径。第三步App 里处理入口。用 SwiftUI 的话是onContinueUserActivity用 UIKit 的话是application(_:continue:restorationHandler:)。.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in guard let url activity.webpageURL else { return } // url.host 应该是 nfc.example.com // url.path 形如 /nfc/12345 let channel URLComponents(url: url, resolvingAgainstBaseURL: false)? .queryItems?.first(where: { $0.name ch })?.value router.open(path: url.path, channel: channel) }第四步验证。Xcode 里没有直接的调试面板我的做法是把 Universal Link 地址发到备忘录里点击后看是否跳转。如果跳的是 Safari 而不是 App九成是 AASA 文件的问题。苹果有个 AASA 的 CDN 缓存文件更新后不会立刻生效通常需要几分钟到几小时。调试期间如果反复改 AASA 都没反应别怀疑人生换个域名路径或者等一等。开发阶段可以用?modedeveloper这类技巧绕过但正式环境一定要走正常路径。3.3 标签里到底写什么iOS 系统读取标签时会解析 NDEF 消息里的 URI 记录。所以标签内容对 iOS 来说比 Android 简单得多一条指向你的 Universal Link 域名的 https 记录就够了。关键在于同一份数据要同时喂饱两端。我的标准做法是标签里写两条记录第一条URI 记录内容是https://nfc.example.com/nfc/12345?chstoreA。第二条AAR 记录内容是com.example.myapp。Android 端两条都能用上iOS 端忽略第二条只认第一条。这样统一物料仓库管理也简单不会出现这批卡是给安卓的、那批是给苹果的这种让运营抓狂的情况。3.4 落地页分流一段 UA 判断省掉一半麻烦当用户没装 App 时Universal Link 会老老实实打开 Safari 加载你的落地页。这时候页面要负责把用户送到正确的商店。最稳的判断方式是在服务端做一次 UA 识别而不是纯靠前端 JS。服务端拿到 User-Agent 后返回不同的跳转指令能规避一部分浏览器对 JS 跳转的拦截。// 前端兜底逻辑服务端已判断过则可直接跳过 const ua navigator.userAgent; const isIOS /iPhone|iPad|iPod/i.test(ua); const isAndroid /Android/i.test(ua); if (isIOS) { // 苹果只有唯一商店直接跳 location.replace(https://apps.apple.com/cn/app/id你的数字ID); } else if (isAndroid) { // 安卓按厂商分流具体 scheme 见下一节 location.replace(/download/android?ch channel); }iOS 这块反而最简单因为 App Store 只有一个地址https://apps.apple.com/cn/app/idXXXXXXXX里的数字 ID 在 App Store Connect 里能查到。安卓就麻烦多了下面单独说。4. 实操全流程从写卡到真机验证4.1 用脚本生成 NDEF 字节流批量做卡的时候一条条手写不现实。我一般用 Python 生成原始字节流再通过读写器批量烧录。核心是两个构造函数。def build_uri_record(uri: str, is_last: bool) - bytes: prefix_map { https://www.: 0x02, http://www.: 0x01, https://: 0x04, http://: 0x03, tel:: 0x05, } payload None for prefix, code in prefix_map.items(): if uri.startswith(prefix): payload bytes([code]) uri[len(prefix):].encode(utf-8) break if payload is None: payload bytes([0x00]) uri.encode(utf-8) mb 0x00 if is_last else 0x80 me 0x40 if is_last else 0x00 header bytes([mb | me | 0x10 | 0x01, 0x01, len(payload)]) return header bU payload def build_aar_record(package_name: str) - bytes: type_bytes bandroid.com:pkg # 长度 15 payload package_name.encode(utf-8) header bytes([0x40 | 0x10 | 0x04, len(type_bytes), len(payload)]) return header type_bytes payload msg build_uri_record(https://nfc.example.com/nfc/12345?chstoreA, False) msg build_aar_record(com.example.myapp) print(NDEF 消息长度:, len(msg), 字节) print(msg.hex( ))这段脚本里最值得盯的是那两个标志位字节。URI 记录如果不是最后一条MB位置 1、ME位保持 0算出来就是 0x91AAR 是最后一条MB位归 0、ME位置 1配合 SR 和 TNF4得到 0x54。算错一位写进去的标签要么解析不出来要么只识别前半段。4.2 容量核算与写入方式拿一个真实例子算笔账。包名com.example.myapp是 18 个字符那么记录计算过程字节数URI 记录头3 字节固定3URI 类型字段单个字符 U1URI 载荷前缀码 1 字节 nfc.example.com/nfc/12345?chstoreA共 35 字节36AAR 记录头3 字节固定3AAR 类型字段android.com:pkg共 15 字节15AAR 载荷包名 18 字节18合计76再加 TLV 封装头1 字节 Tag 长度字段 1 到 2 字节和终止符 1 字节总共大概 80 字节出头。NTAG213 的 137 字节可用空间完全够用甚至还有余量加个十几字节的签名参数。如果 URL 里要带长参数比如带 JWT 或者 base64 加密串一条记录就能涨到一百多字节这时候就必须上 NTAG215。我的建议是直接按 NTAG215 报价做预算别为了省几毛钱反复拉锯项目后期加需求再换芯片返工成本远高于材料差价。写入方式有两种。小批量几十张直接用手机上的第三方写卡工具选 NDEF 写入模式手动填 URI 和 AAR一次一张胜在零成本。大批量几百张以上需要 USB 读写器和 PC 端工具把上面的 Python 脚本产生的字节流批量写入效率差几十倍。注意写卡工具里的锁卡选项一旦锁定标签就永久只读写错了只能作废除非项目明确需要防篡改否则不要锁。4.3 真机测试矩阵不要只拿自己那台手机测一遍就上线NFC 的兼容性问题非常分散。我一般按下面的矩阵过一遍每个组合至少测三张卡。测试维度覆盖项关注点系统版本Android 9 / 11 / 13 / 14权限模型和分发行为变化品牌华为、小米、OPPO、vivo、荣耀、三星厂商商店 scheme 与分发优先级差异装机状态未装 / 已装未运行 / 已装后台运行 / 已装前台冷启动、热启动、状态保持iOS 机型iPhone XR 及以后 / XR 以前后台读取是否可用贴卡姿态手机上半部、中部、天线位置有效感应区差异环境金属桌面、塑料外壳、厚手机壳场强衰减实测下来最常见的失败场景是已装 App 但后台运行时贴卡没反应。这种情况八成是onNewIntent没写或者launchMode用的是standard导致每次新开一个实例。另一个高频问题是在小米和 OPPO 上弹出了选择器而不是直接进 App这是 URI 匹配到了多个应用需要靠 AAR 收口。5. 踩坑记录与排查速查表5.1 Android 侧的高频问题贴卡后没有任何反应。先确认手机的 NFC 开关是否打开这个听起来很傻但我遇到过不止一次是用户自己在设置里关掉了。排除后检查 Manifest 里的android:host是否和标签里的域名完全一致少一层子域都不行。再确认tech-list里写了android.nfc.tech.NfcA。弹出了应用选择器。说明 URI 匹配到了多个应用且没有 AAR 收口。要么加 AAR 记录要么把 URI 的域名收窄到一个只有你的 App 会声明的路径上。能打开 App 但参数丢了。九成是 AAR 记录的位置放错了它必须是最后一条。另外检查EXTRA_NDEF_MESSAGES的读取方式有些低版本 ROM 返回的是Parcelable[]而不是NdefMessage[]需要做类型判断。未安装时跳的商店不对。AAR 的跳转目标由设备默认处理market://的应用决定。想指定商店只能走落地页方案自己按厂商分流。重复贴卡启动多次。检查launchMode并在onNewIntent里做时间戳去重同一次会话内 2 秒以内的重复触发直接忽略。5.2 iOS 侧的高频问题AASA 文件更新后不生效。检查路径是否带扩展名、Content-Type 是否为application/json、是否存在重定向。三样都对还是不行就等 CDN 刷新或者临时换个路径验证。Universal Link 在 Safari 里能打开但 App 接不到。大概率是 Associated Domains 没配对注意这里填的格式是applinks:域名不带协议头和路径。另外必须用真机测试模拟器不支持。老机型贴卡完全没反应。iPhone XR 之前的机型不支持后台读取这个没法通过代码解决。物料上可以做机型适配提示或者干脆把老机型引导到手动路径。锁屏状态下读不到。iPhone 需要亮屏才响应标签这是系统行为。线下物料加一句操作引导能显著提升成功率。弹了通知但点进去没到指定页面。检查 App 的路由解析逻辑webpageURL在不同系统版本上的 query 保留行为有差异稳妥做法是把关键参数放在 path 里而不是 query 里。5.3 上线前必须过的检查项防复制这件事必须在业务层做。标签里的内容是明文的任何人都能用手机读取并原样写到另一张空白卡上。所以不要把积分、金额、权限标识这类敏感信息直接写进标签标签里只放一个随机 ID真正的业务校验交给服务端去查。如果项目对防伪要求高考虑用带动态加密能力的芯片但成本和兼容性都要重新评估。安卓厂商商店的跳转协议要真机验证。各家协议在不同版本上都有变化下面这张表是我最近一次项目中实测的常见形式仅供参考务必用你的目标机型复测。厂商常见跳转协议形式备注Google Playmarket://details?id包名系统级通用协议华为appmarket://details?id包名网页版为 appgallery.huawei.com小米mimarket://details?id包名部分版本需带 backtrueOPPOoaps://mk/dt?pkg包名版本差异较大vivovivomarket://details?id包名部分机型回落到 market://应用宝tmast://appdetails?pname包名需安装应用宝落地页里的通用写法是先尝试厂商 scheme设一个 500 毫秒到 1 秒的定时器如果页面还在前台说明 scheme 没被接住就回落到对应的 https 下载页。这个尝试加超时回落的模式比单纯跳一个链接稳得多。不要把跳转逻辑做成死循环。我见过一个落地页用户从微信打开后一直在跳转中和打开 App之间反复横跳原因是 scheme 跳转被拦截后定时器又触发了一次。加个只跳一次的标志位一秒钟的事。埋点要从入口 Activity 就开始上报。用户贴卡到 App 完全启动之间有几百毫秒到两秒的窗口如果等首页加载完才上报会丢掉一部分中途退出的用户。把 tagId、路径参数、时间戳在入口 Activity 的第一时间就投递出去。物料文案要写清楚操作姿势。我在门店项目里做过一轮 A/B 测试桌贴上加不加点亮屏幕后贴一下这句提示成功率差了将近三成。安卓用户的 NFC 开关状态也是个变量物料上留一个没反应点这里手动打开的二维码兜底能挽回一批流失。我个人在这个方向做了两年多最大的体会是技术实现其实不难难的是一套物料同时喂饱 Android 和 iOS、同时照顾装了和没装、同时兼容各种品牌和系统版本。所以我的固定套路是标签只写最基础的两条记录URI 加 AAR所有分流和降级逻辑全部放在服务端的落地页里通过配置中心下发。这样一旦某家厂商的跳转协议变了改后端配置就能生效不用重新做卡、不用重新发版这才是线下硬件项目真正扛得住迭代的做法。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。