「Android」WiFiP2P入门

应用 WiFi 直连 (WiFiP2P) 技术,能够让具备相应硬件的 Android 4.0(API 级别 14)或更高版本设施在没有两头接入点的状况下,通过 WiFi 进行间接互联。应用这些 API,能够实现反对 WiFi P2P 的设施间互相发现和连贯,从而取得比蓝牙连贯更远距离的高速连贯通信成果。

为了实现一个根底的WiFiP2P,大抵分为如下局部:

  • 权限申请
  • 初始化WiFiP2P的相干对象
  • 定义监听WiFiP2P的播送接收器
  • 连贯设施

对于WiFiP2P中的群组,大抵分为如下局部:

  • 创立群组
  • 连贯群组
  • 移除群组

权限申请

首先,在AndroidManifest.xml中,对WiFi相干权限进行动态申请:

    <uses-sdk android:minSdkVersion="14" />    <!-- WiFi相干权限 -->    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

若后续还须要读写权限则增加:

    <!-- 读写权限 -->    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

而后,在 Android 6.0 及更高版本中,局部危险权限(Dangerous Permissions)权限须要在运行时申请用户批准(动静申请):

    private void checkPermission() {        String[] permissions = new String[]{                Manifest.permission.WRITE_EXTERNAL_STORAGE,                Manifest.permission.READ_EXTERNAL_STORAGE,                Manifest.permission.ACCESS_FINE_LOCATION        };        for (String permission : permissions) {            if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {                Log.i(TAG, permission + " granted.");            } else {                ActivityCompat.requestPermissions(this, permissions, 0);                Log.w(TAG, permission + " not granted.");            }        }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        if (requestCode == 0) {            for (int result : grantResults) {                if (result == PackageManager.PERMISSION_GRANTED) {                    continue;                } else {                    Toast.makeText(this, "权限未获取", Toast.LENGTH_SHORT).show();                }            }        }        super.onRequestPermissionsResult(requestCode, permissions, grantResults);    }

初始化

首先,须要创立:

  • WifiP2pManager 对象
  • WifiP2pManager.Channel 对象
  • WiFiDirectBroadcastReceiver 对象(稍后介绍该播送接收器的定义)
  • IntentFilter 对象
    private WifiP2pManager mManager;    private WifiP2pManager.Channel mChannel;    private WiFiDirectBroadcastReceiver mReceiver;    private IntentFilter mIntentFilter;    private void initWifip2pHelper() {        // 创立 WifiP2pManager 对象        mManager = (WifiP2pManager) getSystemService(WIFI_P2P_SERVICE);        // 创立 WifiP2pManager.Channel 对象        mChannel = mManager.initialize(this, Looper.getMainLooper(), new WifiP2pManager.ChannelListener() {            @Override            public void onChannelDisconnected() {                Log.i(TAG, "onChannelDisconnected: ");            }        });        // 创立 WiFiDirectBroadcastReceiver 对象        mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);        // 创立 IntentFilter 对象        mIntentFilter = new IntentFilter();        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);        mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);    }
其中, WiFiDirectBroadcastReceiver 对象想要监听的播送,与 IntentFilter 对象增加的action雷同。

而后,在 Activity 的onResume()办法中注册播送接收器,在 Activity 的onPause()办法中勾销注册该播送接收器:

    /* register the broadcast receiver with the intent values to be matched */    @Override    protected void onResume() {        super.onResume();        registerReceiver(mReceiver, mIntentFilter);    }    /* unregister the broadcast receiver */    @Override    protected void onPause() {        super.onPause();        unregisterReceiver(mReceiver);    }

定义监听WiFiP2P的播送接收器

监听WiFiP2P的播送接收器 WiFiDirectBroadcastReceiver 类具体定义如下:

public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {    private static final String TAG = "WiFiDirectBroadcastReceiver";    private WifiP2pManager mManager;    private WifiP2pManager.Channel mChannel;    private Wifip2pActivity mActivity;    private List<WifiP2pDevice> mWifiP2pDeviceList = new ArrayList<>();    WifiP2pManager.PeerListListener mPeerListListener = new WifiP2pManager.PeerListListener() {        @Override        public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {            mWifiP2pDeviceList.clear();            mWifiP2pDeviceList.addAll(wifiP2pDeviceList.getDeviceList());        }    };    /**     * 构造方法     *     * @param manager      WifiP2pManager对象     * @param channel      WifiP2pManager.Channel对象     * @param activity     Wifip2pActivity 对象     */    public WiFiDirectBroadcastReceiver(WifiP2pManager manager, WifiP2pManager.Channel channel, Wifip2pActivity activity) {        super();        this.mManager = manager;        this.mChannel = channel;        this.mActivity = activity;    }    @Override    public void onReceive(Context context, Intent intent) {        String action = intent.getAction();        switch (action) {            case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION:                // Check to see if Wi-Fi is enabled and notify appropriate activity                Log.i(TAG, "onReceive: WIFI_P2P_STATE_CHANGED_ACTION");                int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);                if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {                    // Wifi P2P is enabled                    Log.i(TAG, "onReceive: Wifi P2P is enabled");                    mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {                        @Override                        public void onSuccess() {                            Log.d(TAG, "onSuccess: ");                        }                        @Override                        public void onFailure(int i) {                            Log.d(TAG, "onFailure: ");                        }                    });                } else {                    // Wi-Fi P2P is not enabled                    Log.i(TAG, "onReceive: Wi-Fi P2P is not enabled");                }                break;            case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION:                // Call WifiP2pManager.requestPeers() to get a list of current peers                Log.i(TAG, "onReceive: WIFI_P2P_PEERS_CHANGED_ACTION");                if (mManager == null) {                    return;                }                mManager.requestPeers(mChannel, mPeerListListener);                break;            case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION:                // Respond to new connection or disconnections                Log.i(TAG, "onReceive: WIFI_P2P_CONNECTION_CHANGED_ACTION");                // NetworkInfo                NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);                // WifiP2pInfo                WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);                // WifiP2pGroup                WifiP2pGroup wifiP2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);                if (networkInfo.isConnected()) {                    if (wifiP2pInfo.isGroupOwner) {                        Toast.makeText(mActivity, "设施连贯,本设施为GO", Toast.LENGTH_LONG).show();                    } else {                        Toast.makeText(mActivity, "设施连贯,本设施非GO", Toast.LENGTH_LONG).show();                    }                } else {                    Toast.makeText(mActivity, "设施断开", Toast.LENGTH_LONG).show();                }                break;            case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:                // Respond to this device's wifi state changing                Log.i(TAG, "onReceive: WIFI_P2P_THIS_DEVICE_CHANGED_ACTION");                WifiP2pDevice device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);                Log.d(TAG, "onReceive: " +device.deviceAddress);                break;            case WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION:                Log.i(TAG, "onReceive: WIFI_P2P_DISCOVERY_CHANGED_ACTION");                break;        }    }}

上述播送接收器用于监听系统对于WiFiP2P相干的播送。通常在onReceive()办法中,通过intent.getAction()办法获取到action,并依据action去匹配不同的对于WiFiP2P相干的播送,别离为:

  • WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION
  • WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION
  • WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
  • WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
  • WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION

WIFI_P2P_STATE_CHANGED_ACTION:WiFiP2P状态产生扭转时的播送

WiFiP2P具体有两个状态:

  • WifiP2pManager.WIFI_P2P_STATE_ENABLED:可用
  • WifiP2pManager.WIFI_P2P_STATE_DISABLED:不可用

而该状态的获取是由:

    int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);

当WiFiP2P状态为可用时,调用discoverPeers()办法开始搜寻左近WiFiP2P设施:

    mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {        @Override        public void onSuccess() {            Log.d(TAG, "onSuccess: ");        }        @Override        public void onFailure(int i) {            Log.d(TAG, "onFailure: ");        }    });

WIFI_P2P_PEERS_CHANGED_ACTION:发现左近WiFiP2P设施时的播送

当搜寻发现左近存在WiFiP2P设施时,调用requestPeers()办法开始获取左近WiFiP2P设施列表:

    mManager.requestPeers(mChannel, mPeerListListener);

当胜利获取左近WiFiP2P设施列表后,会回调侦听器 WifiP2pManager.PeerListListener 中的onPeersAvailable()办法,并传递一个 WifiP2pDeviceList 对象作为参数,能够用一个 List<WifiP2pDevice> 对象接管并保留该参数:

    WifiP2pManager.PeerListListener mPeerListListener = new WifiP2pManager.PeerListListener() {        @Override        public void onPeersAvailable(WifiP2pDeviceList wifiP2pDeviceList) {            mWifiP2pDeviceList.clear();            mWifiP2pDeviceList.addAll(wifiP2pDeviceList.getDeviceList());        }    };

WIFI_P2P_CONNECTION_CHANGED_ACTION:连贯状态产生扭转时的播送

当连贯状态产生扭转时(如连贯了一个设施,断开了一个设施),都会接管到该播送。当接管到该播送后,能够应用intent.getParcelableExtra()办法别离获取到 NetworkInfo , WifiP2pInfo , WifiP2pGroup 对象:

    // 获取 NetworkInfo 对象    NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);    // 获取 WifiP2pInfo 对象    WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);    // 获取 WifiP2pGroup 对象    WifiP2pGroup wifiP2pGroup = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);

获取到上述对象后,能够应用networkInfo.isConnected()办法来判断连贯状态具体是“设施连贯”还是“设施断开”,还能够依据wifiP2pInfo.isGroupOwner的值来判断设施是否为GroupOwner:

    if (networkInfo.isConnected()) {        if (wifiP2pInfo.isGroupOwner) {            Toast.makeText(mActivity, "设施连贯,本设施为GroupOwner", Toast.LENGTH_LONG).show();        } else {            Toast.makeText(mActivity, "设施连贯,本设施非GroupOwner", Toast.LENGTH_LONG).show();        }    } else {        Toast.makeText(mActivity, "设施断开", Toast.LENGTH_LONG).show();    }

WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:以后设施状态产生扭转时的播送

通常能够在这个播送中获取到以后设施的信息:

    WifiP2pDevice device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);

WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION:搜寻状态产生扭转时的播送

启动搜寻:

    mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {        @Override        public void onSuccess() {            Log.d(TAG, "onSuccess: ");        }        @Override        public void onFailure(int i) {            Log.d(TAG, "onFailure: ");        }    });

进行搜寻:

    mManager.stopPeerDiscovery(mChannel, new WifiP2pManager.ActionListener() {        @Override        public void onSuccess() {            Log.d(TAG, "onSuccess: ");        }        @Override        public void onFailure(int i) {            Log.d(TAG, "onFailure: ");        }    });

连贯设施

首先,抉择一个须要连贯的设施,并获取到该设施的 WifiP2pDevice 对象。而后,判断该设施的状态,设施状态通常为三种:

  • WifiP2pDevice.AVAILABLE:可连贯
  • WifiP2pDevice.CONNECTED:已连贯
  • WifiP2pDevice.INVITED:已申请连贯

依据不同的设施状态,进行不同的具体逻辑:

    @Override    public void onClick(View view) {        // 获取到该设施的 WifiP2pDevice 对象        WifiP2pDevice wifiP2pDevice = mWifiP2pDeviceList.get(viewHolder.getAdapterPosition());        // 判断该设施的状态        switch (wifiP2pDevice.status) {            case WifiP2pDevice.AVAILABLE:                // 申请连贯                WifiP2pConfig config = new WifiP2pConfig();                config.deviceAddress = wifiP2pDevice.deviceAddress;                mManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {                    @Override                    public void onSuccess() {                        Log.i(TAG, "connect success.");                    }                    @Override                    public void onFailure(int i) {                        Log.i(TAG, "connect failed.");                    }                });                break;            case WifiP2pDevice.CONNECTED:                // 断开连接                mManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {                    @Override                    public void onSuccess() {                        Log.i(TAG, "removeGroup success.");                    }                    @Override                    public void onFailure(int i) {                        Log.i(TAG, "removeGroup failed.");                    }                });                break;            case WifiP2pDevice.INVITED:                // 敞开连贯申请                mManager.cancelConnect(mChannel, new WifiP2pManager.ActionListener() {                    @Override                    public void onSuccess() {                        Log.i(TAG, "cancelConnect success.");                    }                    @Override                    public void onFailure(int i) {                        Log.i(TAG, "cancelConnect failed.");                    }                });                break;        }    }

创立群组

GroupOwner创立Group:

    private static final String NETWORKNAME_P60 = "DIRECT-HUAWEI-P60";    private static final String PASSPHRASE_P60 = "12345678";    private static void createWiFiP2PGroup(final Activity context, final WifiP2pManager manager, final WifiP2pManager.Channel channel) {        WifiP2pConfig config = new WifiP2pConfig.Builder()                .setGroupOperatingBand(WifiP2pConfig.GROUP_OWNER_BAND_AUTO)                .setNetworkName(NETWORKNAME_P60)                .setPassphrase(PASSPHRASE_P60)                .build();        manager.createGroup(channel, config, new WifiP2pManager.ActionListener() {            @Override            public void onSuccess() {                Log.i(TAG, "onSuccess: createGroup");                Toast.makeText(context, "onSuccess: createGroup", Toast.LENGTH_SHORT).show();            }            @Override            public void onFailure(int i) {                Log.i(TAG, "onFailure: createGroup " + i);                Toast.makeText(context, "onFailure: createGroup " + i, Toast.LENGTH_SHORT).show();            }        });    }

连贯群组

Client连贯GroupOwner:

    public static void connectWiFiP2P(final Activity context, final WifiP2pManager manager, final WifiP2pManager.Channel channel, final WifiP2pDevice wifiP2pDevice) {        // 如果连贯对象为群组GroupOwner        if (wifiP2pDevice.isGroupOwner()) {            Log.d(TAG, "connectWiFiP2P: " + wifiP2pDevice.deviceName);            WifiP2pConfig config;            if (needPassphrase) {                // 以PIN的形式连贯                config = new WifiP2pConfig.Builder()                        .setNetworkName(NETWORKNAME_iPhone)                        .setPassphrase(PASSPHRASE_iPhone)                        .build();            } else {                // 以默认的形式连贯                config = new WifiP2pConfig();                config.deviceAddress = wifiP2pDevice.deviceAddress;            }            manager.connect(channel, config, new WifiP2pManager.ActionListener() {                @Override                public void onSuccess() {                    Log.i(TAG, "onSuccess: connect");                }                @Override                public void onFailure(int i) {                    Log.i(TAG, "onFailure: connect " + i);                }            });        }    }

移除群组

GroupOwner移除Group:

    manager.requestGroupInfo(channel, new WifiP2pManager.GroupInfoListener() {        @Override        public void onGroupInfoAvailable(WifiP2pGroup wifiP2pGroup) {            if (wifiP2pGroup != null) {                Log.i(TAG, "onGroupInfoAvailable: wifiP2pGroup != null");                manager.removeGroup(channel, new WifiP2pManager.ActionListener() {                    @Override                    public void onSuccess() {                        Log.i(TAG, "onSuccess: removeGroup");                    }                    @Override                    public void onFailure(int i) {                        Log.i(TAG, "onFailure: removeGroup");                    }                });            } else {                Log.i(TAG, "onGroupInfoAvailable: wifiP2pGroup == null");            }        }    });

参考文档

WLAN 直连(对等连贯或 P2P)概览

通过 Wi-Fi 直连创立点对点连贯

Android WiFi P2P开发实际笔记