閱讀前預備知識:css
學習安曉輝老師的qt for android 核心編程(瞭解怎麼在Qt 裏邊c++ 調用java,java庫怎麼加進qt工程中)java
qt android wifi 開發篇android
如今作智能硬件設備,都是使用模塊化的流行wifi芯片來接入雲端,實現實時通信和數據交互的工做.之前使用wifi芯片咱們常常會遇到一個問題:在wifi設備初始化過程當中,咱們要手動從ap模式配置鏈接路由器,這個操做流程對於咱們開發人員來講看起來很簡單,當換路由器的時候,按復位鍵而後手動配置就行了.甚至如今我看到許多這樣的產品好比網絡攝像頭,一些遠程控制設備都是這個模式.甚至我在學校工做室的時候老師買了一套智能家居設備,咱們要看着一本說明書按着流程來手動配置網絡.也就是如今大部分智能設備仍是存在這個問題(其實已經有解決方案了,也許開發商尚未留意到如今流行的智能網絡配置功能,這個有沒缺點漏洞我不知道,畢竟我也是新手,只用這個技術作過簡單的智能家居系統).c++
比起傳統的ap模式網頁配置wif芯片網絡或者串口配置網絡,smartconfig是一種新型的智能網絡配置功能,操做起來更智能方便,時物聯網芯片產品的一大趨向。
區別:git
ap (所謂ap模式就是把wifi芯片啓動成像路由器同樣,可讓其餘wifi終端鏈接到這個wifi芯片)模式下的網頁形式是經過wifi終端手動搜索wifi芯片開的ap服務,而後鏈接該wifi芯片。接着在wifi終端打開瀏覽器,訪問wifi芯片的地址(好比: http://192.168.0.1 ),因爲wifi芯片原本支持ap模式,它已是一個簡單的網站服務,經過這網頁去獲取權限設置wifi芯片提供的設置項服務,好比重啓鏈接到路由器等等。編程
大部分wifi芯片都支持串口命令控制wifi芯片的全部功能。這時候就須要經過串口命令區控制wifi芯片了。segmentfault
smartconfig 是一個面向軟件開發者的智能網絡配置功能。硬件開發商無需關係本身的wifi芯片怎麼鏈接到路由器,也無需知道動態的路由怎麼被切換。由於smartconfig時經過終端軟件去讓wifi芯片鏈接到路由器的。具體實現原理參考:智能硬件接入雲平臺解決方案瀏覽器
微信硬件平臺裏邊有一個叫作airkiss 技術,下面的兩個產品都支持這個技術,對於實現智能網絡配置功能,它是一個相對完美的平臺和方案.詳細的學習請自行進平臺官網看文檔.微信
hi-fly和esp系列芯片看起來大同小異,知識esp8266芯片實現智能網絡配置比較麻煩,它裏邊只有實現源碼,並無封裝成java庫來使用,hi-fly產品就產商提供了一個java庫,後邊着重介紹怎麼在qt裏邊使用這個庫.網絡
若是有官方評估版能夠徹底參考HF-LPT220wifi模塊評估版使用指南學習搭建完整的調試環境,若是沒有的話請參考HF-LPT220wifi模塊用戶手冊這份文檔作一個調試板子。
這個板子是本身作的,使用的時HF-LPT220芯片。電路設計按狀況,留出串口和復位鍵,就能夠看成官方評估版使用了。
監聽wifi芯片串口傳來的數據
瞭解透傳模式
瞭解串口數據傳輸和wifi串口控制命令。
就拿個人項目來做分析:
咱們在建立qt android項目的時候要把hi-flying 提供的hiflying-iots-android-smartlink7.0.2.jar 拷貝到android/libs目錄下
而後寫給c++調用的java接口類:
SmartLinkManager.java
package com.tommego; //hifly smart link libs import com.hiflying.smartlink.ISmartLinker; import com.hiflying.smartlink.OnSmartLinkListener; import com.hiflying.smartlink.SmartLinkedModule; import com.hiflying.smartlink.v3.SnifferSmartLinker; import com.hiflying.smartlink.v7.MulticastSmartLinker; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.Handler; import android.app.Activity; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.content.IntentFilter; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; //屏幕像素密度 import android.util.DisplayMetrics; public class SmartLinkManager extends org.qtproject.qt5.android.bindings.QtActivity implements OnSmartLinkListener{ private static SmartLinkManager m_instance; //smart link protected static ISmartLinker mSnifferSmartLinker; private static boolean mIsConncting = false; protected static Handler mViewHandler = new Handler(); // protected static ProgressDialog mWaitingDialog; private static BroadcastReceiver mWifiChangedReceiver; private static String mSSID; public SmartLinkManager(){ m_instance = this; //smart linker initialization mSnifferSmartLinker = MulticastSmartLinker.getInstance(); } public static void startSmartLink(String ssid,String pwd){ // TODO Auto-generated method stub if(!mIsConncting){ //設置要配置的ssid 和pswd try { mViewHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(m_instance.getApplicationContext(), "正在後臺配置wifi,請稍後", Toast.LENGTH_LONG).show(); } }); mSnifferSmartLinker.setOnSmartLinkListener(m_instance); // showDialog(); //開始 smartLink mSnifferSmartLinker.start(m_instance.getApplicationContext(), pwd.trim(), ssid.trim()); mIsConncting = true; // mWaitingDialog.show(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void stopSmartLink(){ mSnifferSmartLinker.stop(); mIsConncting = false; // closeDialog(); } public static String getSSID(){ WifiManager conMan = (WifiManager) m_instance.getSystemService(Context.WIFI_SERVICE); return conMan.getConnectionInfo().getSSID(); } @Override public void onLinked(final SmartLinkedModule module) { // TODO Auto-generated method stub // Log.w(TAG, "onLinked"); mViewHandler.post(new Runnable() { @Override public void run() { Toast.makeText(m_instance.getApplicationContext(), "發現新wifi模塊"+ "\n mac:"+module.getMac()+ "\n ip:"+module.getModuleIP(), Toast.LENGTH_SHORT).show(); } }); } @Override public void onCompleted() { // Log.w(TAG, "onCompleted"); mViewHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(m_instance.getApplicationContext(), "智能配置完成!", Toast.LENGTH_SHORT).show(); // mWaitingDialog.dismiss(); mIsConncting = false; // closeDialog(); } }); } @Override public void onTimeOut() { // Log.w(TAG, "onTimeOut"); mViewHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(m_instance.getApplicationContext(), "配置超時!", Toast.LENGTH_SHORT).show(); // mWaitingDialog.dismiss(); mIsConncting = false; } }); } //獲取屏幕像素密度 public static double getDentisy(){ DisplayMetrics metrics=new DisplayMetrics(); m_instance.getWindowManager().getDefaultDisplay().getMetrics(metrics); return metrics.density; } // public static native void showDialog(); // public static native void closeDialog(); }
而後c++ 就能夠調度這個庫了:
wifidevicemanager.h
#ifndef WIFIDEVICEMANAGER_H #define WIFIDEVICEMANAGER_H #include <QObject> #include <QUdpSocket> #include <QHostAddress> #include <QList> #include <QAndroidJniObject> #include <jni.h> #include <QDebug> #include <QByteArray> #include <QTcpSocket> struct WifiDevice{ QString ip,mac; }; class WifiDeviceManager : public QObject { Q_OBJECT public: explicit WifiDeviceManager(QObject *parent = 0); //device list Q_PROPERTY(QString deviceList READ deviceList NOTIFY deviceListChanged) QString deviceList(); Q_PROPERTY(QString revDatas READ revDatas NOTIFY revDatasChanged) QString revDatas(); Q_PROPERTY(QString revTcpDatas READ revTcpDatas NOTIFY revTcpDatasChanged) QString revTcpDatas(); //tcp socket properties Q_PROPERTY(QString tcpState READ tcpState NOTIFY tcpStateChanged) QString tcpState(); //tcp con Q_INVOKABLE void connectTcp(QString ip); Q_INVOKABLE void sendDatasTcp(QString data); //smart config Q_INVOKABLE void startSmartLink(QString SSID,QString pwd); Q_PROPERTY(QString ssID READ ssID NOTIFY ssIDChanged) QString ssID(){ return mssid; } //send udp datas Q_INVOKABLE void searchDevice(); //send datas Q_INVOKABLE void sendDatas(QString datas); Q_INVOKABLE void sendDatas(QString datas,int port); Q_INVOKABLE void setDAddress(QString ad){ this->dAddress=ad; } signals: void deviceListChanged(); void ssIDChanged(); void revDatasChanged(); void tcpStateChanged(); void revTcpDatasChanged(); public slots: void readDatas(); void readTcpDatas(); private: QString myAddress; QList<WifiDevice> mdeviceList; QUdpSocket *socket; QTcpSocket *tcpSocket; int port; QString mssid; QString mrevDatas; QString mRevTcpDatas; QString dAddress; QString m_tcpState; }; #endif // WIFIDEVICEMANAGER_H
wifidevicemanager.cpp
#include "wifidevicemanager.h" WifiDeviceManager::WifiDeviceManager(QObject *parent) : QObject(parent) { //init socket port=48899; socket=new QUdpSocket(this); socket->bind(QHostAddress::Broadcast,port); tcpSocket=new QTcpSocket(); tcpSocket->bind (8899); connect(socket,SIGNAL(readyRead()),this,SLOT(readDatas())); connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readTcpDatas())); this->m_tcpState="unConnected"; tcpStateChanged(); //init ssid QAndroidJniObject str=QAndroidJniObject::callStaticObjectMethod("com/tommego/SmartLinkManager", "getSSID", "()Ljava/lang/String;"); this->mssid=str.toString(); ssIDChanged(); //init address QHostAddress address; myAddress=address.toString(); } QString WifiDeviceManager::deviceList(){ return ""; } void WifiDeviceManager::readDatas(){ socket->waitForReadyRead(100); // qDebug()<<"&&&&&&&&&&&&&&&&&&&&&datas:"<<socket->readAll(); this->mrevDatas=socket->readAll(); while (socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; // currentDatas="aa"; // mdataChanged(); socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); mrevDatas=datagram.data(); revDatasChanged(); // mdataChanged(); } revDatasChanged(); } void WifiDeviceManager::startSmartLink(QString SSID, QString pwd){ QAndroidJniObject cssid=QAndroidJniObject::fromString(SSID); QAndroidJniObject cpwd=QAndroidJniObject::fromString(pwd); QAndroidJniObject::callStaticMethod<void>("com/tommego/SmartLinkManager", "startSmartLink", "(Ljava/lang/String;Ljava/lang/String;)V", cssid.object<jstring>(), cpwd.object<jstring>()); } void WifiDeviceManager::searchDevice(){ QByteArray cmd; cmd.append("HF-A11ASSISTHREAD"); QString address="192.168.0.255"; QHostAddress ad(address); socket->writeDatagram(cmd,ad,port); // socket->writeDatagram(cmd,"192.168.1.255",port); } void WifiDeviceManager::sendDatas(QString datas){ QByteArray cmd; cmd.append(datas); QString address="192.168.0.255"; QHostAddress ad(address); socket->writeDatagram(cmd,ad,port); // socket->writeDatagram(cmd,"192.168.1.255",port); } QString WifiDeviceManager::revDatas(){ return this->mrevDatas; } void WifiDeviceManager::sendDatas(QString datas, int mport){ QByteArray cmd; cmd.append(datas); QString address="192.168.0.255"; QHostAddress ad(address); socket->writeDatagram(cmd,ad,mport); } QString WifiDeviceManager::tcpState (){ return this->m_tcpState; } void WifiDeviceManager::connectTcp (QString ip){ if(tcpSocket->state()==QTcpSocket::ConnectedState) return ; QHostAddress address(ip); tcpSocket->connectToHost(address,8899); if(tcpSocket->state()==QTcpSocket::ConnectedState) this->m_tcpState="connected"; else this->m_tcpState="unConnected"; tcpStateChanged(); } void WifiDeviceManager::sendDatasTcp (QString data){ if(tcpSocket->state()==QTcpSocket::ConnectedState){ QByteArray mdata; mdata.append(data); this->tcpSocket->write (mdata); } } void WifiDeviceManager::readTcpDatas(){ tcpSocket->waitForReadyRead(500); mRevTcpDatas=tcpSocket->readAll(); revTcpDatasChanged(); } QString WifiDeviceManager::revTcpDatas(){ return this->mRevTcpDatas; }
這裏是調用smartlink庫核心實現部分,在實現這個功能過程,遇到了不少java接口的坑.不過還好,整個源碼實現完美在qt中跑起來了.這時候咱們的app,就能夠經過smartlink實現對爲初始化的wifi設備進行一鍵配置網絡了!(就算是有幾十臺wifi設備,都能直接在app中一鍵配置而且搜到wifi設備哈哈!)
功能截圖: