微信智能硬件 airkiss協(xié)議 配網(wǎng)開發(fā)

一蝗肪、前言蝴乔、微信Airkiss官方文檔:

http://iot.weixin.qq.com/wiki/new/index.html?page=4-1-1
簡介:AirKiss是微信硬件平臺為Wi-Fi設(shè)備提供的微信配網(wǎng)、局域網(wǎng)發(fā)現(xiàn)和局域網(wǎng)通訊的技術(shù)产弹。開發(fā)者若要實現(xiàn)通過微信客戶端對Wi-Fi設(shè)備配網(wǎng)氏身、通過微信客戶端在局域網(wǎng)發(fā)現(xiàn)Wi-Fi設(shè)備,或者把微信客戶端內(nèi)的音樂遗契、圖片、文件等消息通過局域網(wǎng)發(fā)送至Wi-Fi設(shè)備病曾,需要在硬件設(shè)備中集成相應(yīng)的AirKiss靜態(tài)庫牍蜂。

二、開發(fā)模塊介紹

微信的Airkiss開發(fā)包含以下4部分泰涂。
1 廠商提供的硬件設(shè)備鲫竞,底層對Airkiss協(xié)議的support。
2 微信配網(wǎng)前端開發(fā)[小程序或者微信公眾帳號]逼蒙。
3 AirKiss協(xié)議層開發(fā)从绘。
4 Android層聯(lián)網(wǎng)處理。
ps:如果需要上報配網(wǎng)等信息給服務(wù)器是牢,在聯(lián)網(wǎng)完成后處理僵井。

簡圖如下:


三、硬件對AirKiss的協(xié)議support

  • 硬件能力要求:
  1. 能夠切換信道妖泄;
  2. 具備定時器功能驹沿,能夠提供100ms的定時中斷;
  3. 能夠設(shè)置為混雜模式蹈胡,接收802.11網(wǎng)絡(luò)幀;
  4. 提供一種進入AirKiss模式的控制方式朋蔫,例如一個按鍵罚渐;
  • 軟件能力要求:
  1. 能夠提供類似標準memset函數(shù)的功能函數(shù);
  2. 能夠提供類似標準memcpy函數(shù)的功能函數(shù)驯妄;
  3. 能夠提供類似標準memcmp函數(shù)的功能函數(shù)荷并;
  4. 能夠提供至少232字節(jié)的全局緩沖空間(完成AirKiss后用戶可用于自己的應(yīng)用程序或進行釋放);

四青扔、微信端開發(fā)

參考這位同學的詳細介紹:http://blog.csdn.net/jrainbow/article/details/50509162

效果如圖:


五源织、AirKiss協(xié)議開發(fā)

很多WiFI廠商都和微信有了合作,實現(xiàn)了Airkiss微猖、AirSync等功能谈息。每個廠商的具體實現(xiàn)不竟相同,我們以正基科技為例凛剥,它提供了(AMPAK)AP6212的EasySetupTarget.zip侠仇,實現(xiàn)了微信的Airkiss功能。略注意,這份代碼在使用的時候你需要調(diào)整一些細節(jié)逻炊,使得在android平臺下順暢運行

1. 代碼結(jié)構(gòu)如下:
2. 代碼入口分析:

命令參數(shù)k可以設(shè)置16位key互亮,-p即為設(shè)置開啟協(xié)議,其中4為airkiss余素。

void usage() {
    printf("-h: show help message\n");
    printf("-d: show debug message\n");
    printf("-k <v>: set 16-char key for all protocols\n");
    printf("-p <v>: bitmask of protocols to enable\n");
    printf("  0x%04x - bcast\n", 1<<EASY_SETUP_PROTO_BCAST);
    printf("  0x%04x - neeze\n", 1<<EASY_SETUP_PROTO_NEEZE);
    printf("  0x%04x - Air Kiss\n", 1<<EASY_SETUP_PROTO_AKISS);
    printf("  0x%04x - Xiaoyi\n", 1<<EASY_SETUP_PROTO_XIAOYI);
    printf("  0x%04x - changhong\n", 1<<EASY_SETUP_PROTO_CHANGHONG);
    printf("  0x%04x - jingdong\n", 1<<EASY_SETUP_PROTO_JINGDONG);
    printf("  0x%04x - jd JoyLink\n", 1<<EASY_SETUP_PROTO_JD);
}

static void signal_handler(void) {
    printf("aborted\n");
    killed = 1;
}

int main(int argc, char* argv[])
{
    printf("enter exec main\n");
    int ret;
    int len;
    uint16 val;

    int flag = 0;

    for (;flag < 1;) {
        printf("enter the mainloop\n");
        int c = getopt(argc, argv, "dhek:p:");
        printf("args parse %c\n",c);
        printf("optarg %s\n",optarg);
        if (c < 0) {
            break;
        }

        switch (c) {
            case 'd':
                debug_enable = 1;
                break;
            case 'k':
                bcast_set_key(optarg);
                bcast_set_key_qqcon(optarg);
                neeze_set_key(optarg);
                neeze_set_key_qqcon(optarg);
                akiss_set_key(optarg);
                jingdong_set_key(optarg);
                jd_set_key(optarg);
                printf("finish set key:%s\n",optarg);
                break;

            case 'p':
                sscanf(optarg, "%04x", (uint32*)&val);
                easy_setup_enable_protocols(val);
                printf("finish set protocol:%s\n",optarg);
                break;

            case 'h':
                usage();
                return 0;
            case 'e':
                printf("finish parse");
                flag = 1;
                break;
            default:
                usage();
                return 0;
        }
    }
....
}
3豹休、編譯方式:
一、編譯可執(zhí)行文件

adb push到開發(fā)版桨吊。執(zhí)行./easysetup -p4(airkiss協(xié)議為4)慕爬,即可以監(jiān)聽airkiss配網(wǎng)的發(fā)生。

二屏积、編譯靜態(tài)庫医窿,修改源代碼為jni接口調(diào)用。這個時候程序在執(zhí)行到easy_setup_ioctl()接口的時候炊林,會報easy setup ioctl(cmd=263) failed: 1(Operation not permitted)錯誤.

easy_setup_start()接口如下:

int easy_setup_ioctl(int cmd, int set, void* param, int size) {
    struct ifreq ifr;
    wl_ioctl_t ioc;
    int ret = 0;

    if (g_ioc_fd < 0) {
        LOGE("easy setup ioctl: control socket not initialized.\n");
        printf("easy setup ioctl: control socket not initialized.\n");
        return -1;
    }

    ioc.cmd = cmd;
    ioc.buf = param;
    ioc.len = size;
    ioc.set = set;

    strncpy(ifr.ifr_name, WLAN_IFACE, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ-1] = 0;
    ifr.ifr_data = (caddr_t) &ioc;

    if ((ret = ioctl(g_ioc_fd, SIOCDEVPRIVATE, &ifr)) < 0) {
        /* log if not WLC_SCAN_RESULTS(51) */
        if (cmd != 51) {
            LOGE("easy setup ioctl(cmd=%d) failed: %d(%s)\n", cmd, errno, strerror(errno));
            printf("easy setup ioctl(cmd=%d) failed: %d(%s)\n", cmd, errno, strerror(errno));
        }
        return -1;
    }

    return 0;
}

分析:權(quán)限問題導(dǎo)致姥卢,做出了如下的應(yīng)對:
把apk放在/system/app中、
設(shè)置platform簽名憑證渣聚、以及設(shè)置shareUid独榴,
相應(yīng)的so權(quán)限及用戶組設(shè)置也沒有問題
糾結(jié)了很久,依然沒有解決

直到發(fā)現(xiàn)了和這位仁兄的雷同的細節(jié):http://leave001.blog.163.com/blog/static/1626912932012566429951/

解決辦法如下:

原來在函數(shù)dev_ioctl中奕枝,會檢查CAP_NET_ADMIN權(quán)限棺榔,進入這個函數(shù),發(fā)現(xiàn)檢查的是進程是否在group
AID_NET_ADMIN中:
if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) return 0;
在app中申請系統(tǒng)app才有的權(quán)限: <uses-permission android:name="android.permission.NET_ADMIN"/> 即可以解決權(quán)限問題隘道。

六症歇、Android聯(lián)網(wǎng)處理。

在收到j(luò)ni或者可執(zhí)行文件里面?zhèn)鬟f過來的ssid和password,即可以利用wifimanager來配網(wǎng)
代碼舉例如下:

    private fun startConnectThread(ssid: String, password: String, type: WifiCipherType) {
        val result = openWifi()
        if (!result) {
            RLog.e(TAG, "open wifi failed")
            return
        }

        RLog.e(TAG, "wifi config --- ssid:" + ssid + ",password:" + password)
        val wifiConfig: WifiConfiguration = createWifiInfo(ssid, password, type)
        if (wifiConfig == null) {
            RLog.e(TAG, "wifiConfig is null!")
            return
        }

        val tempConfig: WifiConfiguration? = isExistSSID(ssid)
        tempConfig?.apply {
            wifiManager.removeNetwork(tempConfig.networkId)
        }

        val netId = wifiManager.addNetwork(wifiConfig)
        wifiManager.enableNetwork(netId, true)
        val connected = wifiManager.reconnect()
        if (connected) {
            RLog.e(TAG, "connect success")
        } else {
            RLog.e(TAG, "connect error")
        }

    }

    private fun createWifiInfo(ssid: String, password: String, type: WifiCipherType): WifiConfiguration {
        val config = WifiConfiguration()
        config.allowedAuthAlgorithms.clear()
        config.allowedGroupCiphers.clear()
        config.allowedKeyManagement.clear()
        config.allowedPairwiseCiphers.clear()
        config.allowedProtocols.clear()
        config.SSID = "\"" + ssid + "\""
        when (type) {
            WifiCipherType.WIFICIPHER_INVALID -> {
                config.wepKeys[0] = ""
                config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
                config.wepTxKeyIndex = 0
            }

            WifiCipherType.WIFICIPHER_WEP -> {
                if (!TextUtils.isEmpty(password)) {
                    if (isHexWepKey(password)) {
                        config.wepKeys[0] = password
                    } else {
                        config.wepKeys[0] = "\"" + password + "\""
                    }
                }
                config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN)
                config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED)
                config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE)
                config.wepTxKeyIndex = 0
            }

            WifiCipherType.WIFICIPHER_WPA -> {
                config.preSharedKey = "\"" + password + "\""
                config.hiddenSSID = true
                config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN)
                config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP)
                config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK)
                config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP)
// 此處需要修改否則不能自動重聯(lián)
// config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP)
                config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP)
                config.status = WifiConfiguration.Status.ENABLED
            }
        }
        return config
    }

七谭梗、智能硬件聯(lián)網(wǎng)后返回random值給微信

此處是有巨坑的忘晤,樓主被坑的不要不要的

A. 微信是這么說的:

模塊拿到上面的數(shù)據(jù)以后還需要進行AirKiss微信配網(wǎng)流程的最后一步,利用接收到的SSID和密碼以后連上對應(yīng)的路由器激捏,立即發(fā)送以上面打印出來的random數(shù)為內(nèi)容的UDP廣播包(只有1個數(shù)據(jù))设塔,目的端口號為10000,建議廣播包的個數(shù)至少為20個远舅,發(fā)送方收到該廣播包后就能確認接收方已經(jīng)準確接收到所有數(shù)據(jù)了闰蛔,由于各平臺連接路由器、發(fā)送UDP廣播包的實現(xiàn)差異較大图柏,并且該功能為模塊自帶功能序六,與AirKiss2.0庫無關(guān),這里不進行舉例說明爆办。

那是不是我對著10000端口在連網(wǎng)成功后發(fā)大于20個random值就ok难咕???
然而測試后發(fā)現(xiàn)微信web端只會提示連接超時余佃,而不會顯示聯(lián)網(wǎng)成功暮刃。

B. 廠商會這么說: 俺不知道!1痢椭懊! 或者這么說 你都連上網(wǎng)了,你讓微信端配網(wǎng)一段時間后自動取消那個頁面步势。 果然一些公司是真心做完就不管用戶體驗的氧猬。
  • 在我郁悶的時候,我的給力同事告訴我有一個市場上的設(shè)備正確的回復(fù)了random坏瘩,我們可以來抓包看看盅抚。admire。
    抓包如下圖:


分析:原來別人回復(fù)的是:random(2位)+mac地址(12位){ps:而這個body才7字節(jié)倔矾,我一開始沒注意}于是我依樣畫葫蘆這么做了妄均,發(fā)送代碼如下:結(jié)果還是不行,乖乖抓了個包哪自。發(fā)現(xiàn)了異常丰包,我的是14字節(jié)。如下圖:

又在我司某同學給力支持下壤巷,判斷發(fā)送代碼沒問題邑彪,問題是需要把內(nèi)容變成跟正確的一樣,從14個字節(jié)到7個字節(jié)胧华。比如16進制的cd寄症,就需要來個小trick,char a = 205撑柔,這樣原始的14字節(jié)就變成了7字節(jié)瘸爽。微信端終于顯示配網(wǎng)完成。

SO,發(fā)送的random要么就一個1個字節(jié)的random值铅忿, 要么就是7個字節(jié)的random+mac地址值,根據(jù)硬件平臺來定

跨過大坑灵汪,前面有別的新坑等著檀训,至少,解決問題這一天心情還是很愉悅的享言,咩哈哈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峻凫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子览露,更是在濱河造成了極大的恐慌荧琼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異命锄,居然都是意外死亡堰乔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門脐恩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镐侯,“玉大人,你說我怎么就攤上這事驶冒」斗” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵骗污,是天一觀的道長崇猫。 經(jīng)常有香客問我,道長需忿,這世上最難降的妖魔是什么诅炉? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮贴谎,結(jié)果婚禮上汞扎,老公的妹妹穿的比我還像新娘。我一直安慰自己擅这,他們只是感情好澈魄,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著仲翎,像睡著了一般痹扇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上溯香,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天鲫构,我揣著相機與錄音,去河邊找鬼玫坛。 笑死结笨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的湿镀。 我是一名探鬼主播炕吸,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勉痴!你這毒婦竟也來了赫模?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蒸矛,失蹤者是張志新(化名)和其女友劉穎瀑罗,沒想到半個月后胸嘴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡斩祭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年劣像,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片停忿。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡驾讲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出席赂,到底是詐尸還是另有隱情吮铭,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布颅停,位于F島的核電站谓晌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏癞揉。R本人自食惡果不足惜纸肉,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喊熟。 院中可真熱鬧柏肪,春花似錦、人聲如沸芥牌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壁拉。三九已至谬俄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間弃理,已是汗流浹背溃论。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痘昌,地道東北人钥勋。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像辆苔,于是被迫代替她去往敵國和親笔诵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容