前言:
【NFC标签打开小程序】这个功能首先基于URL Scheme,要实现这个功能大致流程是:
- 获取URL Scheme
- 再将URL Scheme以NDEF的格式写入进NFC标签中。
写入的数据格式微信官方文档上说明如图1-1:
图1-1
看到这,如果你一脸懵,完全不知道啥意思,就应该往下了解下NDEF数据格式,做一下基础的知识储备了。
一、了解NDEF
1、 NDEF是什么?
NDEF全称:nfc data exchange format 即 nfc 数据交换格式;ndef的message由多个record组成;而record又有record头部(header)和负载(payload)构成,这里会详解record的构成,这对我们后面需要实现的功能非常重要!
2、 record的结构
record是由header和payload构成,如下图:
图1-2
如图1-2所示,第一个字节包含MB,ME,CF,SR,IL,TNF,它们的功能作用如下表1-1:
MB | message begin:消息开始的地方 一般用于开头 且置1 |
ME | message end:消息结束的地方 一般用于结尾 且置1 |
CF | (chunk flag)是否分块 |
SR | (short record)如果设置该值,则上图的 pay length 只需要1个, 表示payload数据长度被限制在255个字节之内。 |
IL | (id_length标志)表示 header 是否含有 id 和 id length 这两个字段 |
TNF | (type name format )用于指明 payload 的类型 具体可见图 |
表1-1
3、了解TNF
TNF的作用是用于指明payload的类型,如果payload中tnf写错,那就会导致在数据传输中对payload的消息解析失败。所以了解下tnf中每个取值代表的含义很重要,具体见下表1-2:
tnf取值 | tnf名 | 作用 |
0x00 | Empty | 表示是一个空的 nfc record |
0x01 | Nfc forum well-Known type | 众所周知类型,其中定义了常见数据格式 |
0x02 | MIME | 多用途 internet 扩展 |
0x03 | Absolute URI | 绝对的 uri 地址 |
0x04 | nfc forum external type | 为第三方组织定义的类型 |
0x05 | unknown | 代表Payload中的数据类型未知 |
0x06 | unchanged | 这种类型的数据用于NFC Record分片 |
表1-2
其中nfc forum well-Known type 定义了一些常见的数据格式 如下:
- URI Record Type:用于存储URI数据,对应Type字段取值为"U"。
- Text Record Type:用于存储文本数据,对应Type字段取值为"T"。
- Signature Record Type:用于存储数字签名数据,对应Type字段取值为"Sig"。
- Smart Poster Record Type:智能海报,用于存储与该海报相关的一些资讯信息,如图片、相关介绍等,对应Type字段取值为"Sp"
- Generic Control Record Type:用于传递控制信息,对应Type字段取值为"Gc"
了解到这里,再回去看图1-1,就能大致看懂了,第一个record的需要携带url schame,所以payload的类型tnf为0x01,type取值‘U’,表示存储的URI数据;安卓还需要一个AAR来拉取微信,则需要再传一个类型为0x04的payload。所以在代码中我们写入record的数据如下(nfc存储的数据是以字节存在的,所以在传进去时需要进行转换,这里用的是封装好的string2ArrayBuffer方法):
按照上面的数据格式,成功写入nfc后,将标签分别于安卓和苹果手机贴靠,发现虽然都能感应标签,却不能打开对应的微信小程序,如下面图:
图3-1 苹果感应结果图
图3-2 安卓感应结果图
这是为什么呢?看来还得了解下payload的结构。
4、payload结构
这里主要了解下常用的payload类型的结构:
- Text record payload(文本型)
- Url record payload(网址型)
(1)text record payload:
文本型payload组成结构有三部分:status,语言码,实际需要写入的Text内容;具体说明如下表:
D1(1101 0001B)对应 MB ME CF SR IL TNF TNF 为 0x01
01 type 的长度
0F payload 的长度
54 type 的类型 对应 ”T“
02 对应语言码字段的长度
65 6E 表示为 “en”
68 65 6C 6F 2C 77 6F 72 6C 64 21 payload 的内容 对应 ASCII 码 结果为 ”Hello,World!“。
ascII 对照表:
ASCII码表,ASCII码一览表,ASCII码对照表完整版-ASCII码中文站
(2)Uri record payload:
网址型payload组成结构有两部分:ID code,实际需要写入的uri内容;其中ID code占总内容的一个字节,剩下的字节就是实际写入的uri的字节数,详细说明如下:
其中ID code的值代表了不同的协议头:
了解到这里,就能知道我们在nfc中写入的url schame 为什么不能被解析成功而实现跳转,原因在于我们在传入payload的时候直接传入了实际的uri内容,而少了ID code部分,所以解析出的内容手机无法识别它是什么协议,从而无法实现正确跳转。正确的做法是,首先需要了解到我们传入uri是否有带协议头,就如我们这里传入的的url schame的内容大致为weixin://xxxxx,它是有带协议的,所以我们再写入payload的内容时还需要在头部加入【无前缀】的ID Code,也就是在uri内容转成字节buffer后再在字节组前面添加0,最后结果就如预料中一样,能正常实现安卓和苹果唤醒小程序的功能。
图4-1 正确写入uri型payload数据
图4-2 遗漏ID code写入的payload数据
- 在arrayBuffer前强制加[00] 的方法如下:
export function payloadFormate(openlink) {
const arrayBuffer = string2ArrayBuffer(openlink);
const zeroArrayBuffer = new Uint8Array([0]).buffer;
const resultArrayBuffer = new Uint8Array(
zeroArrayBuffer.byteLength + arrayBuffer.byteLength
);
resultArrayBuffer.set(new Uint8Array(zeroArrayBuffer), 0);
resultArrayBuffer.set(new Uint8Array(arrayBuffer), 1);
const payload = resultArrayBuffer.buffer;
return payload;
}