让Android WiFi支持中文

让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转化成二进制。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值