admin管理员组文章数量:1620371
让Android WiFi支持中文
先要 弄清楚以下几点:
一、 Android显示的WiFi名字,计算机都是以二进制处理的数据的,所以接受到的这个名字一定是一个二进制数据,它是怎么变成字符串的呢?
在frameworks/base/wifi/java/android/net/wifi/WifiSsid.java中
@Override
public String toString() {
byte[] ssidBytes = octets.toByteArray();
// Supplicant returns \x00\x00\x00\x00\x00\x00\x00\x00 hex string
// for a hidden access point. Make sure we maintain the previous
// behavior of returning empty string for this case.
if (octets.size() <= 0 || isArrayAllZeroes(ssidBytes)) return "";
// TODO: Handle conversion to other charsets upon failure
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharBuffer out = CharBuffer.allocate(32);
CoderResult result = decoder.decode(ByteBuffer.wrap(ssidBytes), out, true);
out.flip();
if (result.isError()) {
return NONE;
}
return out.toString();
}
这段代码很明显是用了utf-8规则解码了ssidBytes,ssidBytes在这里是一个字节数组,也就是Android所收到的WiFi名称。问题来了,有些路由器的WiFi名称是GBK编码的,这里用utf-8编码很显然得不到正确的结果。所以看到的是乱码,这里就有要兼容GBK编码的问题。如果这里修改为兼容GBK编码是不是就可以了,修改后会发现,显示正常了但是连不上,为什么呢,那就要知道连接过程了。
二、WiFi正真的连接工作是wpa_supplicant完成的。一般在init.xxxx.rc中会看到一个service 如下
service wpa_supplicant /system/bin/wpa_supplicant \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
-O/data/misc/wifi/sockets \
-e/data/misc/wifi/entropy.bin \
-g@android:wpa_wlan0
class main
user root
group system wifi
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
这里有一个配置文件wpa_supplicant.conf,Android会把WiFi热点名称,密码等写入这个文件,wpa_supplicant会通过这个配置文件去获取WiFi名称(ssid)和密码, 然后与扫描到的进行比较,然后找到匹配的热点然后再连接,比较函数位于external/wpa_supplicant_8/wpa_supplicant/events.c
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
int i, struct wpa_bss *bss,
struct wpa_ssid *group,
int only_first_ssid)
{
u8 wpa_ie_len, rsn_ie_len;
int wpa;
struct wpa_blacklist *e;
const u8 *ie;
struct wpa_ssid *ssid;
int osen;
//省略部分代码
if (check_ssid &&
(bss->ssid_len != ssid->ssid_len ||
os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
continue;
}
if (ssid->bssid_set &&
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
continue;
}
在上面可以看到比较了ssid,问题就在这里这里比较是通不过的,因为配置文件中的ssid是utf-8编码的,而扫描到的是GBK编码,而且这里你也不能强制让他通过,因为在wpa_supplicant不仅仅是这里用到了配置文件中的ssid。那怎么办,你肯定会想到是谁用utf-8把ssid保存到配置文件里的。
三、谁保存的这个ssid和密码
在frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiConfigStore.java中
private String encodeSSID(String str){
String tmp = removeDoubleQuotes(str);
return String.format("%x", new BigInteger(1, tmp.getBytes(Charset.forName("UTF-8"))));
}
这里会把String 也就是你看到的WiFi名称,转换成二进制数据,这里的二进制数据会存入wpa_supplicant.conf,这就是为什么比较通不过的原因了。
解决方法
了解了这个多,现在应该有一个思路了,显示名称时需要修改WifiSsid.java中的toString,以兼容GBK,存储wpa_supplicant.conf,又需要正确的转换成二进制数。
我的解决方法是在WifiSsid.java中的toString方法中兼容GBK,并且用map存储string和二进制数的键值对。然后WifiConfigStore.java中的encodeSSID方法用string去这个map中取出二进制数,注意有一种情况map中没有这个string,map中存储了所有扫描显示了的WiFi热点,还有一种map中没有就是隐藏了的热点,如果如果map中没有,还需要用utf-8或者是GBK转化成二进制。
版权声明:本文标题:让Android WiFi支持中文 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1728819173a1175231.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论