1. 程式人生 > >android 熱點開發、WiFi熱點通訊

android 熱點開發、WiFi熱點通訊

對於熱點。我們需要能夠開啟和關閉,自己設定熱點名和密碼以及鎖的型別。然後呢,還要能夠獲取連線此熱點的裝置資訊。關於熱點,沒有找到相應的操作類,查閱資料後得知要用method反射機制來實現。反射機制不瞭解的自行百度。下面直接貼上相關程式碼及解析

public class Mywifiap {

    private static final int NO_PASS=0;
    private static final int WPA_PSK=1;
    private static final int WPA2_PSK=2;

    private WifiManager wifiManager;
    private WifiConfiguration apconfig;

    public Mywifiap(Context context) {
        wifiManager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    }

    //開啟熱點
    public void openwifiap(String name,String password,int type){
        if(wifiManager.isWifiEnabled())
            wifiManager.setWifiEnabled(false);//如果WiFi是開啟的就關閉WiFi。
        apconfig=new WifiConfiguration();
        apconfig.SSID=name;//設定WiFi名字

        //熱點相關設定
        switch (type){
            case NO_PASS:
                apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
                apconfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                apconfig.wepKeys[0]="";
                apconfig.wepTxKeyIndex=0;
                break;
            case WPA_PSK:
                apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
                apconfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
                apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                apconfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                apconfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                apconfig.preSharedKey=password;
                break;
            case WPA2_PSK:
                //由於wpa2是不能直接訪問的,但是KeyMgmt中卻有。所以我們這樣寫
                for(int i=0;i<WifiConfiguration.KeyMgmt.strings.length;i++){
                    if("WPA2_PSK".equals(WifiConfiguration.KeyMgmt.strings[i])) {
                        apconfig.allowedKeyManagement.set(i);//直接給它賦索引的值
                        Log.e("wpa2索引", String.valueOf(i));//不同手機索引不同
                    }
                }
                apconfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
                apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
                apconfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
                apconfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                apconfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
                apconfig.preSharedKey=password;
                break;
        }

        try {

            Method method=wifiManager.getClass().getMethod("setWifiApEnabled",WifiConfiguration.class,boolean.class);
            method.invoke(wifiManager,apconfig,true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //關閉熱點
    public void closewifiap(){
        try {
//            Method method1=wifiManager.getClass().getMethod("getWifiApConfiguration");
//            method1.setAccessible(true);
//            WifiConfiguration nowconfig= (WifiConfiguration) method1.invoke(wifiManager);//獲取當前熱點
            Method method=wifiManager.getClass().getMethod("setWifiApEnabled",WifiConfiguration.class,boolean.class);
            method.invoke(wifiManager,apconfig,false);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    //獲取連線列表
    public StringBuffer getconnectlist(){
        /*
        連線裝置的資訊都存在一個檔案裡面,讀這個檔案獲取資訊
        讀取檔案後每為這樣的格式,每連線一個裝置增加一行,沒有連線時只有一行
        IP address       HW type     Flags       HW address            Mask     Device
        192.168.43.115   0x1         0x2         c4:0b:cb:8a:4c:f1     *        ap0
        192.168.43.115   0x1         0x2         c4:0b:cb:8a:4c:f1     *        ap0
         */
        StringBuffer sb=new StringBuffer();
        try {
            BufferedReader br=new BufferedReader(new FileReader("/proc/net/arp"));
            String line;
            while((line=br.readLine())!=null){
                Log.e("連線列表",line);
                sb.append(line+"\n");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb;
    }

}
關於監聽熱點狀態,它是有一個廣播的,通過這個廣播就可以監聽到了熱點開關的實時狀態
public class ApReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        String action=intent.getAction();
        if("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)){
            //"android.net.wifi.WIFI_AP_STATE_CHANGED"這個是熱點狀態改變的廣播
            int state=intent.getIntExtra("wifi_state",0);
            Log.e("熱點狀態", String.valueOf(state));
            /* state:
            12:正在開啟熱點
            13:已開啟熱點
            10:正在關閉熱點
            11:已關閉熱點
             */
        }

    }
}
然後來說說WiFi、熱點通訊,其實WiFi連線熱點後,他們就在一個區域網中了,也就是說,他們可以通過socket來通訊。然後就要在原來的基礎上加上聯網許可權。
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"></uses-permission>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
既然用socket,埠可以自己設但是客戶端必須要知道服務端的IP地址才能通訊,所以,在之前WiFi開發的類上加上獲取服務端IP的方法。
//獲取連線熱點的IP地址
    public static String getserverip(Context context){
        WifiManager manager= (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        DhcpInfo dhcpInfo=manager.getDhcpInfo();
        int ip=dhcpInfo.serverAddress;
        //整形轉化為IP地址
        String sip=(ip&0xff)+"."+((ip>>8)&0xff)+"."+((ip>>16)&0xff)+"."+((ip>>24)&0xff);
        Log.e("伺服器IP",sip);
        return sip;
    }
客戶(WiFi)端的socket程式碼
public class WifiSocket extends AppCompatActivity{
    private EditText msg;
    private Button putmsg;
    private OutputStream out;

    Handler handler=new Handler(){

        @Override
        public void handleMessage(Message msg) {
            if(msg.what==1){
                Toast.makeText(WifiSocket.this, (String) msg.obj,Toast.LENGTH_SHORT).show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.wifisocket);

        msg= (EditText) findViewById(R.id.msg);
        putmsg= (Button) findViewById(R.id.putmsg);

        putmsg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    //傳送訊息
                    out.write(msg.getText().toString().getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        thread();

    }

    public void thread(){
        final String ip=Mywifi.getserverip(WifiSocket.this);
        final int port=1234;
        new Thread(){
            @Override
            public void run() {
                try {
                    Socket socket=new Socket(ip,port);
                    Log.e("wifisocket","建立連線");
                    InputStream in=socket.getInputStream();
                    out=socket.getOutputStream();

                    //接收訊息
                    while (true){
                        byte[] buffer=new byte[1024];
                        int len=0;
                        if((len=in.read(buffer))!=-1){
                            byte[] data=new byte[len];
                            for(int i=0;i<data.length;i++)
                                data[i]=buffer[i];
                            String msg=new String(data);
                            Log.e("收到訊息",msg);

                            Message message=new Message();
                            message.what=1;
                            message.obj=msg;
                            handler.sendMessage(message);
                        }
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }.start();
    }
}
服務(熱點)端的socket程式碼
public class Server extends Thread{
    public ServerSocket serverSocket;
    public Socket socket;
    public static final int PORT=1234;

    public Context context;
    public Handler handler;

    public Server(Context context,Handler handler){
        this.context=context;
        this.handler=handler;
    }

    @Override
    public void run() {
        try {
            serverSocket=new ServerSocket(PORT);
            Log.e("wifi伺服器","已開啟");
            socket=serverSocket.accept();
            Log.e("wifi伺服器","裝置已連線");

            InputStream in=socket.getInputStream();
            OutputStream out=socket.getOutputStream();

            //接收到訊息後,馬上傳送一條訊息
            while(true){
                byte[] buffer=new byte[1024];
                int len=0;
                if((len=in.read(buffer))!=-1){
                    byte[] data=new byte[len];
                    for(int i=0;i<data.length;i++)
                        data[i]=buffer[i];
                    String msg=new String(data);
                    Log.e("收到訊息",msg);
                    //通過handle來彈出Toast。
                    Message message=new Message();
                    message.obj=msg;
                    message.what=1;
                    handler.sendMessage(message);

                    //傳送訊息
                    out.write("對方已接收訊息".getBytes());
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:這個專案在6.0以下裝置有限,在6.0及以上裝置,會丟擲一個沒有授權讀寫系統設定的異常,因為6.0是裝置,隱私許可權必須動態獲取,開關熱點等屬於隱私許可權必須在程式碼裡動態獲取。如果是6.0及以上裝置,那就自己加幾行動態獲取許可權的程式碼