使用 application/vnd.wfa.wsc in Android 创建 NDEF WiFi 记录
Creating an NDEF WiFi record using application/vnd.wfa.wsc in Android
从 Android 5.0.0 开始,您可以长按 WiFi 连接并将该连接写入标签 ("Write to NFC tag")。您可以在此处找到该操作的来源:WriteWifiConfigToNfcDialog.java。采用 WiFi 连接并创建 NDEF 负载的相关行似乎在此处:
String wpsNfcConfigurationToken = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId);
mWifiManager
是 WifiManager
的实例,但是 getWpsNfcConfigurationToken
不是 API 的一部分。通过追踪这个方法,我们可以在这里找到它的提交:Add calls for NFC WSC token creation 不幸的是,这没有帮助。 这是我的调查结果 运行。 编辑:
我发现了以下调用堆栈:
WifiServiceImpl.java
呼叫 mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId);
WifiStateMachine.java
调用 mWifiNative.getNfcWpsConfigurationToken(netId);
WifiNative.java
终于有方法了
public String getNfcWpsConfigurationToken(int netId) {
return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
}
然后调用
String result = doStringCommandNative(mInterfacePrefix + command);
其中 doStringCommandNative
进行系统调用(在任何地方都找不到代码)。
调查到此结束。
希望有人可以介入并向我展示一种创建 NdefRecord
类型 application/vnd.wfa.wsc
给定 SSID、密码、Encryption/Auth 类型的方法。
我当然检查了由 Android 创建的实际 application/vnd.wfa.wsc
记录的字节,但是用字节手动重新创建这个过程似乎可能非常不可靠并且非常乏味。
最终doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId)
的调用由wpa_supplicant模块处理。此功能描述为 here. I think the actual implementation of this can be found in wps_supplicant.c。
您实际尝试做的并不是 Android 具体的事情。在"WiFi Simple Configuration Technical Specification"中定义,填写this form即可下载。相关部分应该是10.1.2 Configuration Token.
NfcUtils.java 有一个有效的实现!有一些 FIXME 和 TODO,但总的来说它有效并且应该让你很好地了解你需要做什么。
如果您想自己解析此类 NdefRecords 并使用 SSID 和密钥执行某些操作,NfcWifiProtectedSetup.java 展示了如何执行此操作。
答案就在 Wi-Fi 联盟 "Wi-Fi Simple Configuration Technical Specification v2.0.5"(可供下载 here)。 Android 使用这种标准格式来配置 WiFi 网络,我错误地认为它是专有的。
首先,我创建了一个 NFC 助手 class(恰如其分地命名为 NFCHelper.java),它具有构建记录所需的所有字节常量。然后,我创建了一个 hacky 方法来创建所需的两个记录之一。该规范实际上在这里毫无用处,我所做的是检查了一些已通过 Android OS 成功配置的标签的有效负载。最后,您需要有一种机制来预先添加 "Handover Select Record (NFC WKT Hs)"(请参阅 WiFi 规范的第 90 页)。我相信这条记录 "tells" Android 可以在以下令牌中注册网络。
如何创建交接记录:
ndefRecords = new NdefRecord[2];
byte[] version = new byte[] { (0x1 << 4) | (0x2)};
ndefRecords[0] = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_HANDOVER_REQUEST, new byte[0], version);
// and then obviously add the record you create with the method below.
创建配置令牌的方法:
private NdefRecord createWifiRecord(String[] data) {
String ssid = data[0];
String password = data[1];
String auth = data[2];
String crypt = data[3];
byte[] authByte = getAuthBytes(auth);
byte[] cryptByte = getCryptBytes(crypt);
byte[] ssidByte = ssid.getBytes();
byte[] passwordByte = password.getBytes();
byte[] ssidLength = {(byte)((int)Math.floor(ssid.length()/256)), (byte)(ssid.length()%256)};
byte[] passwordLength = {(byte)((int)Math.floor(password.length()/256)), (byte)(password.length()%256)};
byte[] cred = {0x00, 0x36};
byte[] idx = {0x00, 0x01, 0x01};
byte[] mac = {0x00, 0x06};
byte[] keypad = {0x00, 0x0B};
byte[] payload = concat(NFCHelper.CREDENTIAL, cred,
NFCHelper.NETWORK_IDX, idx,
NFCHelper.NETWORK_NAME, ssidLength, ssidByte,
NFCHelper.AUTH_TYPE, NFCHelper.AUTH_WPA_PERSONAL, authByte,
NFCHelper.CRYPT_TYPE, NFCHelper.CRYPT_WEP, NFCHelper.CRYPT_AES_TKIP,
NFCHelper.NETWORK_KEY, passwordLength, passwordByte);
// NFCHelper.MAC_ADDRESS, mac);
return NdefRecord.createMime(NFC_TOKEN_MIME_TYPE, payload);
}
许可证和要点here。您可以在网上的任何地方找到 concat
方法的实现,或者自己编写。
注意:这是一个相当复杂的实现(您可能会注意到)。我包括 AES 和 AES/TKIP 字节,因为我在测试它时发现它适用于在 Android 下使用不同 encryption/auth 方法的各种网络 5.*
请随时更改函数原型,String 数组与我所做的工作配合得很好。
使用上面第一个代码段中创建的两条记录,然后您应该将其传递到 NdefMessage
并将其写入您的代码。
很快有一天我会写一篇文章和一个远 better/robust 带有图形和东西的解决方案,所以我会更新这个答案。
从 Android 5.0.0 开始,您可以长按 WiFi 连接并将该连接写入标签 ("Write to NFC tag")。您可以在此处找到该操作的来源:WriteWifiConfigToNfcDialog.java。采用 WiFi 连接并创建 NDEF 负载的相关行似乎在此处:
String wpsNfcConfigurationToken = mWifiManager.getWpsNfcConfigurationToken(mAccessPoint.networkId);
mWifiManager
是 WifiManager
的实例,但是 getWpsNfcConfigurationToken
不是 API 的一部分。通过追踪这个方法,我们可以在这里找到它的提交:Add calls for NFC WSC token creation 不幸的是,这没有帮助。 这是我的调查结果 运行。 编辑:
我发现了以下调用堆栈:
WifiServiceImpl.java
呼叫 mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId);
WifiStateMachine.java
调用 mWifiNative.getNfcWpsConfigurationToken(netId);
WifiNative.java
终于有方法了
public String getNfcWpsConfigurationToken(int netId) {
return doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId);
}
然后调用
String result = doStringCommandNative(mInterfacePrefix + command);
其中 doStringCommandNative
进行系统调用(在任何地方都找不到代码)。
调查到此结束。
希望有人可以介入并向我展示一种创建 NdefRecord
类型 application/vnd.wfa.wsc
给定 SSID、密码、Encryption/Auth 类型的方法。
我当然检查了由 Android 创建的实际 application/vnd.wfa.wsc
记录的字节,但是用字节手动重新创建这个过程似乎可能非常不可靠并且非常乏味。
最终doStringCommand("WPS_NFC_CONFIG_TOKEN WPS " + netId)
的调用由wpa_supplicant模块处理。此功能描述为 here. I think the actual implementation of this can be found in wps_supplicant.c。
您实际尝试做的并不是 Android 具体的事情。在"WiFi Simple Configuration Technical Specification"中定义,填写this form即可下载。相关部分应该是10.1.2 Configuration Token.
NfcUtils.java 有一个有效的实现!有一些 FIXME 和 TODO,但总的来说它有效并且应该让你很好地了解你需要做什么。
如果您想自己解析此类 NdefRecords 并使用 SSID 和密钥执行某些操作,NfcWifiProtectedSetup.java 展示了如何执行此操作。
答案就在 Wi-Fi 联盟 "Wi-Fi Simple Configuration Technical Specification v2.0.5"(可供下载 here)。 Android 使用这种标准格式来配置 WiFi 网络,我错误地认为它是专有的。
首先,我创建了一个 NFC 助手 class(恰如其分地命名为 NFCHelper.java),它具有构建记录所需的所有字节常量。然后,我创建了一个 hacky 方法来创建所需的两个记录之一。该规范实际上在这里毫无用处,我所做的是检查了一些已通过 Android OS 成功配置的标签的有效负载。最后,您需要有一种机制来预先添加 "Handover Select Record (NFC WKT Hs)"(请参阅 WiFi 规范的第 90 页)。我相信这条记录 "tells" Android 可以在以下令牌中注册网络。
如何创建交接记录:
ndefRecords = new NdefRecord[2];
byte[] version = new byte[] { (0x1 << 4) | (0x2)};
ndefRecords[0] = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_HANDOVER_REQUEST, new byte[0], version);
// and then obviously add the record you create with the method below.
创建配置令牌的方法:
private NdefRecord createWifiRecord(String[] data) {
String ssid = data[0];
String password = data[1];
String auth = data[2];
String crypt = data[3];
byte[] authByte = getAuthBytes(auth);
byte[] cryptByte = getCryptBytes(crypt);
byte[] ssidByte = ssid.getBytes();
byte[] passwordByte = password.getBytes();
byte[] ssidLength = {(byte)((int)Math.floor(ssid.length()/256)), (byte)(ssid.length()%256)};
byte[] passwordLength = {(byte)((int)Math.floor(password.length()/256)), (byte)(password.length()%256)};
byte[] cred = {0x00, 0x36};
byte[] idx = {0x00, 0x01, 0x01};
byte[] mac = {0x00, 0x06};
byte[] keypad = {0x00, 0x0B};
byte[] payload = concat(NFCHelper.CREDENTIAL, cred,
NFCHelper.NETWORK_IDX, idx,
NFCHelper.NETWORK_NAME, ssidLength, ssidByte,
NFCHelper.AUTH_TYPE, NFCHelper.AUTH_WPA_PERSONAL, authByte,
NFCHelper.CRYPT_TYPE, NFCHelper.CRYPT_WEP, NFCHelper.CRYPT_AES_TKIP,
NFCHelper.NETWORK_KEY, passwordLength, passwordByte);
// NFCHelper.MAC_ADDRESS, mac);
return NdefRecord.createMime(NFC_TOKEN_MIME_TYPE, payload);
}
许可证和要点here。您可以在网上的任何地方找到 concat
方法的实现,或者自己编写。
注意:这是一个相当复杂的实现(您可能会注意到)。我包括 AES 和 AES/TKIP 字节,因为我在测试它时发现它适用于在 Android 下使用不同 encryption/auth 方法的各种网络 5.* 请随时更改函数原型,String 数组与我所做的工作配合得很好。
使用上面第一个代码段中创建的两条记录,然后您应该将其传递到 NdefMessage
并将其写入您的代码。
很快有一天我会写一篇文章和一个远 better/robust 带有图形和东西的解决方案,所以我会更新这个答案。