将数据写入不适合的 NFC 标签
Writing data to an NFC tag that does not fit
我的 Android 应用目前通过从剪贴板粘贴、读取 QR 码或从 NFC 读取来消耗 URL 的 Google 电子表格。我在写入 NFC 标签时遇到问题,并收到此错误:
[ERROR:nfa_rw_act.cc(1571)] Unable to write NDEF. Tag maxsize=137, request write size=171
我无法写入此标签,因为我尝试写入的负载大于其上可写的 space。
我想做的就是将 URL 我已经阅读(从剪贴板或 QR)到 NFC 标签,并添加我的应用程序记录,以便它启动 Play 商店到我的应用程序,以防用户尚未安装它。不幸的是,这似乎是太多的数据。我考虑过可能只包括 spreadsheetID 值,但我认为当我不可避免地想要在 Google Sheets 之外添加对电子表格的支持时,这会在未来增加复杂性。
这是我目前的写法:
public NdefMessage createNdefMessage() {
String text = "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit?usp=sharing";
NdefRecord appRecord = NdefRecord.createApplicationRecord(context.getPackageName());
NdefRecord relayRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, new String("application/" + context.getPackageName()).getBytes(Charset.forName("US-ASCII")), null, text.getBytes());
return new NdefMessage(new NdefRecord[] {relayRecord, appRecord});
}
是否只写 ID(在本例中为“1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms”)是我唯一的选择?我还假设我使用的 NFC 标签是一个平均尺寸,而不是 2018 年的超小尺寸。
编辑:
多亏了迈克尔,我才能够让它适应,虽然勉强(134/137 字节)。我通过这个将 URI 写入 NFC:
NdefRecord relayRecord = NdefRecord.createUri(text);
我添加了这个 Intent 过滤器来捕获它:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https" android:host="docs.google.com"/>
</intent-filter>
我用这个读取了 NFC 标签:
NdefMessage[] messages = new NdefMessage[rawMessages.length];
for (int i = 0; i < rawMessages.length; i++) {
messages[i] = (NdefMessage) rawMessages[i];
}
for (NdefRecord r : messages[0].getRecords()) {
if (r.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
byte[] payload = r.getPayload();
try {
String payloadText = new String(payload, 1, payload.length - 1, "UTF-8");
int firstByte = payload[0];
return getUriPrefix(firstByte) + payloadText;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "Read error";
}
}
}
我通过此获得的 URI 压缩的第一个字节,即使我只在我的应用程序中分配“04”(当我将其读取为 int 时为 4):
private String getUriPrefix(int firstByte) {
if (firstByte == 0) {
return "";
} else if (firstByte == 1) {
return "http://www.";
} else if (firstByte == 2) {
return "https://www.";
} else if (firstByte == 3) {
return "http://";
} else if (firstByte == 4) {
return "https://";
} else {
return "";
}
}
您在日志中收到的错误消息非常清楚。您的 NDEF 消息太大,无法容纳标签的数据区域。显而易见的解决方案是使用存储容量足够大的 NFC 标签——有很多更大的标签可用。如果您想准确存储该 NDEF 消息,您将无能为力。
但是,有一些方法可以改进 NDEF 消息本身。您当前使用 MIME 类型记录来存储 URL。这绝对不是存储 URL 的记录类型的最佳选择。 (或实际上任何特定于应用程序的数据)。您选择的 MIME 类型成本 ("application/" + context.getPackageName()).length() = 31 字节(假设您的包名称是 19 字节)。
如果您改为使用 NFC 论坛外部类型记录,则可以创建一个更短的类型名称,格式为 "mydomain.tld:appurl",这样可以节省相当多的字节。
relayRecord = NdefRecord.createExternal("mydomain.tld", "appurl", text.getBytes());
既然你想存储一个URL,甚至有一个更有效(并且随时可用)的记录类型:NFC 论坛 URI 众所周知的类型。该记录的类型名称仅由单个字母 "U" 组成,因此与您的 MIME 类型记录相比,这已经节省了 30 个字节。此外,URI 记录类型使用压缩方案进一步减小记录的大小:有一个众所周知的 URI 前缀列表(例如 "https://")可以表示为 URI 记录中的单个字节(方法 NdefRecord.createUri()
将自动处理该压缩)。因此,您将节省另外 7 个字节。
relayRecord = NdefRecord.createUri(text);
我的 Android 应用目前通过从剪贴板粘贴、读取 QR 码或从 NFC 读取来消耗 URL 的 Google 电子表格。我在写入 NFC 标签时遇到问题,并收到此错误:
[ERROR:nfa_rw_act.cc(1571)] Unable to write NDEF. Tag maxsize=137, request write size=171
我无法写入此标签,因为我尝试写入的负载大于其上可写的 space。
我想做的就是将 URL 我已经阅读(从剪贴板或 QR)到 NFC 标签,并添加我的应用程序记录,以便它启动 Play 商店到我的应用程序,以防用户尚未安装它。不幸的是,这似乎是太多的数据。我考虑过可能只包括 spreadsheetID 值,但我认为当我不可避免地想要在 Google Sheets 之外添加对电子表格的支持时,这会在未来增加复杂性。
这是我目前的写法:
public NdefMessage createNdefMessage() {
String text = "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit?usp=sharing";
NdefRecord appRecord = NdefRecord.createApplicationRecord(context.getPackageName());
NdefRecord relayRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, new String("application/" + context.getPackageName()).getBytes(Charset.forName("US-ASCII")), null, text.getBytes());
return new NdefMessage(new NdefRecord[] {relayRecord, appRecord});
}
是否只写 ID(在本例中为“1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms”)是我唯一的选择?我还假设我使用的 NFC 标签是一个平均尺寸,而不是 2018 年的超小尺寸。
编辑:
多亏了迈克尔,我才能够让它适应,虽然勉强(134/137 字节)。我通过这个将 URI 写入 NFC:
NdefRecord relayRecord = NdefRecord.createUri(text);
我添加了这个 Intent 过滤器来捕获它:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https" android:host="docs.google.com"/>
</intent-filter>
我用这个读取了 NFC 标签:
NdefMessage[] messages = new NdefMessage[rawMessages.length];
for (int i = 0; i < rawMessages.length; i++) {
messages[i] = (NdefMessage) rawMessages[i];
}
for (NdefRecord r : messages[0].getRecords()) {
if (r.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
byte[] payload = r.getPayload();
try {
String payloadText = new String(payload, 1, payload.length - 1, "UTF-8");
int firstByte = payload[0];
return getUriPrefix(firstByte) + payloadText;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "Read error";
}
}
}
我通过此获得的 URI 压缩的第一个字节,即使我只在我的应用程序中分配“04”(当我将其读取为 int 时为 4):
private String getUriPrefix(int firstByte) {
if (firstByte == 0) {
return "";
} else if (firstByte == 1) {
return "http://www.";
} else if (firstByte == 2) {
return "https://www.";
} else if (firstByte == 3) {
return "http://";
} else if (firstByte == 4) {
return "https://";
} else {
return "";
}
}
您在日志中收到的错误消息非常清楚。您的 NDEF 消息太大,无法容纳标签的数据区域。显而易见的解决方案是使用存储容量足够大的 NFC 标签——有很多更大的标签可用。如果您想准确存储该 NDEF 消息,您将无能为力。
但是,有一些方法可以改进 NDEF 消息本身。您当前使用 MIME 类型记录来存储 URL。这绝对不是存储 URL 的记录类型的最佳选择。 (或实际上任何特定于应用程序的数据)。您选择的 MIME 类型成本 ("application/" + context.getPackageName()).length() = 31 字节(假设您的包名称是 19 字节)。
如果您改为使用 NFC 论坛外部类型记录,则可以创建一个更短的类型名称,格式为 "mydomain.tld:appurl",这样可以节省相当多的字节。
relayRecord = NdefRecord.createExternal("mydomain.tld", "appurl", text.getBytes());
既然你想存储一个URL,甚至有一个更有效(并且随时可用)的记录类型:NFC 论坛 URI 众所周知的类型。该记录的类型名称仅由单个字母 "U" 组成,因此与您的 MIME 类型记录相比,这已经节省了 30 个字节。此外,URI 记录类型使用压缩方案进一步减小记录的大小:有一个众所周知的 URI 前缀列表(例如 "https://")可以表示为 URI 记录中的单个字节(方法
NdefRecord.createUri()
将自动处理该压缩)。因此,您将节省另外 7 个字节。relayRecord = NdefRecord.createUri(text);