創建點對點WiFi直連——翻譯自developer.android.com Training

wifi p2p api可以讓設備和身邊的設備相連接,而不需要網絡或者熱點。android的wifi p2p框架使用了wifi-direct認證的程序。wifi p2p讓你的應用快速找到並連接周圍的設備,與之教育,這個範圍要比藍牙更廣。

這節課教你怎樣使用wifi直連來找到和連接周圍的設備。


建立應用的權限

要使用wifip2p,需要在manifest中添加權限CHANGE_WIFI_SATE,ACCESS_WIFI_STATE和INTERNET權限。wifip2p不需要互聯網連接,但是它使用標準的javasocket,所以需要INTERNET權限。所以你需要遵循下面的權限類使用wifip2p。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.nsdchat"
    ...

    <uses-permission
        android:required="true"
        android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission
        android:required="true"
        android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission
        android:required="true"
        android:name="android.permission.INTERNET"/>
    ...

建立一個廣播接聽者和p2p管理器



要使用wifi p2p你需要監聽廣播intent來監聽特定的事件。在你的app中設立一個intentFileter來監聽下面的事情。

WIFI_P2P_STATE_CHANGED_ACTION 指示wifip2p是否可用
WIFI_P2P_PEERS_CHANGED_ACTION 指示wifip2p配對名單是否發生變化Indicates that the available peer list has changed. WIFI_P2P_CONNECTION_CHANGED_ACTION 指示wifip2p連接是否發生變化Indicates the state of Wi-Fi P2P connectivity has changed. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION 指示本設備的細節配置是否發生變化Indicates this device's configuration details have changed.
private final IntentFilter intentFilter = new IntentFilter();
...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    //  Indicates a change in the Wi-Fi P2P status.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);

    // Indicates a change in the list of available peers.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);

    // Indicates the state of Wi-Fi P2P connectivity has changed.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);

    // Indicates this device's details have changed.
    intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

    ...
}
在onCreate方法的末尾,獲取一個一個WifiP2pManager對象,並調用它的initialize()方法。這個方法返回一個WifiP2pManager.Channel對象,一會你講在wifip2p框架當中使用。


@Override

Channel mChannel;

public void onCreate(Bundle savedInstanceState) {
    ....
    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(this, getMainLooper(), null);
}
下面創建一個BroadCastReceiver來監聽系統的wifip2p的狀態變化。在onReceive()方法中,添加一個來處理上面列出的每一種的P2P狀態變化。



@Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
            // Determine if Wifi P2P mode is enabled or not, alert
            // the Activity.判斷wifi P2p的模式有無變化,如果有的話就想activity發出警告。
            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                activity.setIsWifiP2pEnabled(true);
            } else {
                activity.setIsWifiP2pEnabled(false);
            }
        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            // The peer list has changed!  We should probably do something about
            // that.如果配對列表發生變化,我們應該做些什麼

        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {

            // Connection state changed!  We should probably do something about
            // that.連接狀態發生變化,我們要做些什麼

        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
            DeviceListFragment fragment = (DeviceListFragment) activity.getFragmentManager()
                    .findFragmentById(R.id.frag_list);
            fragment.updateThisDevice((WifiP2pDevice) intent.getParcelableExtra(
                    WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));

        }
    }

最後,添加代碼,在你的activity激活的時候,註冊intent filter和 broadcastReceiver,當activity pause的時候註銷他們。最好的是在onResume()和onPause()中進行。

    /** register the BroadcastReceiver with the intent values to be matched */
    @Override
    public void onResume() {
        super.onResume();
        receiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
        registerReceiver(receiver, intentFilter);
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

初始化配對發現

想要發現附近的 wifiP2P設備,需要使用下面的參數調用discoverPeers方法。
- 當你初始化peer to peer Manager的時候返回的WifiP2pManager對象。
- 構建一個WifiP2pManager.ActionListener,系統將會在發現設備或者失敗的時候調用其中的方法。
mManager.discoverPeers(mChannel,new WifiP2pManager.ActionListener){
@Override
public void onSuccess(){
但你發現初始化成功的時候就會調用這裏。
還沒有服務被實際的發現呢,所以這個方法經常被留空。配對發現在onRecive方法中,細節見下面。
}
@Overide
public void onFailure(int reasonCode){
當發現初始化失敗的時候調用這裏,警告用戶出現了一些錯誤。
}

}

記住,這僅僅初始化了配對的發下。discoverPeers()方法啓動了發現程序,並立即返回了。系統在發現初始化成功的時候會調用你給的 action listener中的方法來通知你成功。同樣,發現會一直持續,一直到初始化成功或者p2p小組建立。


獲取配對夥伴列表


現在寫獲取對象 和處理列表的代碼。先實現WifiP2pManager.PeerListListener的接口,它可以提供發現的wifiP2p設備的 列表。下面的代碼片作爲例子:


private List peers=new ArrayList();

private PeerListListener peerListListener=new PeerListListener(){
@Override
public void onPeeersAvailable(WifiP2pDeviceList peerList){
//外面是舊的,裏面是新的
peers.clear();
peers.addAll(peerList.getDeviceList());

//如果有AdapterView被這個數據填充了,那麼這時要通知更新。例如,如果你一個可用配對的 列表。
((WiFiPeerListAdapter)getListAdapter()).notifyDataSetChanged();
if(peers.size()==0){
Log.d(WiFiDirectActivity.TAG,"No device found");
return ;
}
}
}

現在修改你的broadcast receiver在接受到action 爲WIFI_p2p_PEERSpCHANGED_ACTIONS的時候在onReceiver中調用requestPeers方法。

如論如何你都要吧listener傳入到receiver當中。一種方法是作爲broadcastReceiver的參數傳遞進去。


public void onReceive(Context context, Intent intent){
……
else if(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)){
//從wifip2p管理者裏面請求可用的對象。指示第一個異步調用,並且調換那個的activity會調用PeerListLisener.onPeersAvailiable()來被通知。
}
Log.d(WifiDirectActivity.TAG,"P2P peers changed);
}


現在,使用action WIFI_P2P_PEERS_CHANGED_ACTION的intent將會觸發一個更新配對列表的請求。


連接到一個配對

爲了連接一個配對,創建一個新的WifiP2PConfig對象,並從你要連接的WifiP2PDevice對象複製信息到前者中。接着調用connect()方法。
Override
    public void connect() {
        // Picking the first device found on the network.
        WifiP2pDevice device = peers.get(0);

        WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = device.deviceAddress;
        config.wps.setup = WpsInfo.PBC;

        mManager.connect(mChannel, config, new ActionListener() {

            @Override
            public void onSuccess() {
                // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
            }

            @Override
            public void onFailure(int reason) {
                Toast.makeText(WiFiDirectActivity.this, "Connect failed. Retry.",
                        Toast.LENGTH_SHORT).show();
            }
        });
    }
上面代碼片中實現的WifiP2PManager.ActionListener接口只能通知初始化成功和失敗。想要監聽其他的連接狀態變化,實現WifiP2pManger.ConnnectionInfoListener接口。其中的onConnetionInfoAvailable方法將會在網絡狀態發生變化的時候回調。 當有多個設備要連接到一個設備的時候(比如說多個玩家的遊戲,或者一個聊天app),那麼這個設備應該作爲羣主。(Group owner)

@Override
    public void onConnectionInfoAvailable(final WifiP2pInfo info) {

        // InetAddress from WifiP2pInfo struct.
        InetAddress groupOwnerAddress = info.groupOwnerAddress.getHostAddress());

        // After the group negotiation, we can determine the group owner.
        if (info.groupFormed && info.isGroupOwner) {
            // Do whatever tasks are specific to the group owner.
            // One common case is creating a server thread and accepting
            // incoming connections.
        } else if (info.groupFormed) {
            // The other device acts as the client. In this case,
            // you'll want to create a client thread that connects to the group
            // owner.
        }
    }

回到BroadCast Receiver的onReceive方法中,定製監聽一個WIFI_P2P_CONNECTION_CHANGED_ACTION intent 模塊。當收到這個intent的時候,調用 requestConnectionInfo()方法。這是一個異步的調用,結果將會通過作爲參數傳入的 listener對象中的方法來接收。
























發佈了60 篇原創文章 · 獲贊 34 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章