2018/10/30

[Android] WIFI Direct Connection

一般做UDP傳輸前,裝置的wifi網路都要先連接到共同一個網域(AP)底下,才能透過IP來進行溝通。
但是如果可以直接利用wifi direct的方式連接的話,不需要連接AP就可以直接溝通了。
在MainActivity.java中,透過implement WifiP2pManager.PeerListListener, 以及WifiP2pManager.ConnectionInfoListener來做。
這個寫法是直接搜尋附近最近一個可以連線的裝置,找到之後會自動連線。

完整程式碼 MainActivity.java:
  1. import android.annotation.SuppressLint;
  2. import android.bluetooth.BluetoothAdapter;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.content.IntentFilter;
  7. import android.net.NetworkInfo;
  8. import android.net.wifi.WifiManager;
  9. import android.net.wifi.WpsInfo;
  10. import android.net.wifi.p2p.WifiP2pConfig;
  11. import android.net.wifi.p2p.WifiP2pDevice;
  12. import android.net.wifi.p2p.WifiP2pDeviceList;
  13. import android.net.wifi.p2p.WifiP2pGroup;
  14. import android.net.wifi.p2p.WifiP2pInfo;
  15. import android.net.wifi.p2p.WifiP2pManager;
  16. import android.support.v7.app.AppCompatActivity;
  17. import android.os.Bundle;
  18. import android.util.Log;
  19. import android.widget.TextView;
  20.  
  21. import java.util.ArrayList;
  22. import java.util.List;
  23.  
  24. public class MainActivity extends AppCompatActivity implements WifiP2pManager.PeerListListener, WifiP2pManager.ConnectionInfoListener {
  25.  
  26. private final String TAG = "MainActivity";
  27.  
  28. private boolean isDeviceFound = false;
  29.  
  30. private TextView tvMacAddress, tvConnectDevice, tvConnectStatus;
  31.  
  32. private WifiP2pManager.Channel mChannel;
  33. private WifiP2pManager mWifiP2pManager;
  34. private final IntentFilter intentFilter = new IntentFilter();
  35. private List peers = new ArrayList<>();
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_main);
  40. // find view by id
  41. tvMacAddress = (TextView)findViewById(R.id.id_tvMacAddress);
  42. tvConnectDevice = (TextView)findViewById(R.id.id_tvConnectDevice);
  43. tvConnectStatus = (TextView)findViewById(R.id.id_tvConnectStatus);
  44. disconnectFunc();
  45. WifiManager mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
  46. BluetoothAdapter myDevice = BluetoothAdapter.getDefaultAdapter();
  47. if (mWifiManager != null) {
  48. // Turn on wifi
  49. mWifiManager.setWifiEnabled(true);
  50. // get my device and mac address
  51. tvMacAddress.setText(myDevice.getName() + ", MAC[" + mWifiManager.getConnectionInfo().getMacAddress() + "]");
  52. }
  53. // setup wifi p2p
  54. intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
  55. intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
  56. intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
  57. intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
  58. registerReceiver(mReceiver, intentFilter);
  59. mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
  60. mChannel = mWifiP2pManager.initialize(this, getMainLooper(), null);
  61. mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
  62. @Override
  63. public void onSuccess() {
  64. Log.d(TAG,"discoverPeers onSuccess");
  65. }
  66. @Override
  67. public void onFailure(int reasonCode) {
  68. Log.d(TAG,"discoverPeers onFailure");
  69. }
  70. });
  71. }
  72. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  73. @Override
  74. public void onReceive(Context context, Intent intent) {
  75. String action = intent.getAction();
  76. if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
  77. Log.d(TAG,"WIFI_P2P_STATE_CHANGED_ACTION");
  78. }
  79. else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
  80. Log.d(TAG,"WIFI_P2P_PEERS_CHANGED_ACTION");
  81. if (mWifiP2pManager != null) {
  82. mWifiP2pManager.requestPeers(mChannel, MainActivity.this);
  83. }
  84. }
  85. else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
  86. Log.d(TAG,"WIFI_P2P_CONNECTION_CHANGED_ACTION");
  87. if (mWifiP2pManager == null) {
  88. return;
  89. }
  90. NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
  91. if (networkInfo.isConnected()) {
  92. mWifiP2pManager.requestConnectionInfo(mChannel, MainActivity.this);
  93. }
  94. }
  95. else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
  96. Log.d(TAG,"WIFI_P2P_THIS_DEVICE_CHANGED_ACTION");
  97. }
  98. }
  99. };
  100. // search available devices and auto connect first one
  101. @Override
  102. public void onPeersAvailable(WifiP2pDeviceList peerList) {
  103. peers.clear();
  104. peers.addAll(peerList.getDeviceList());
  105. String[] peersMacAddress, peersDeviceName;
  106. if (peers.size() == 0) {
  107. Log.d(TAG, "No devices found");
  108. tvConnectStatus.setText("no connected");
  109. peersMacAddress = new String[1];
  110. peersMacAddress[0]="No Devices found";
  111. peersDeviceName = new String[1];
  112. peersDeviceName[0]="No Devices found";
  113. }
  114. else{
  115. peersMacAddress = new String[peers.size()];
  116. peersDeviceName = new String[peers.size()];
  117. int i=0, j=0;
  118. for(WifiP2pDevice device: peers){
  119. peersDeviceName[i++] = device.deviceName;
  120. peersMacAddress[j++] = device.deviceAddress;
  121. // find the first device and auto connect
  122. if(device.deviceAddress.equals(peersMacAddress[0])){
  123. tvConnectDevice.setText(peersDeviceName[0] + ", MAC[" + peersMacAddress[0] + "]");
  124. if(!isDeviceFound){
  125. connectFunc();
  126. isDeviceFound = true;
  127. }
  128. }
  129. }
  130. }
  131. }
  132. // check connect status
  133. @Override
  134. public void onConnectionInfoAvailable(WifiP2pInfo info) {
  135. tvConnectDevice.setText("Stop Searching");
  136. tvConnectStatus.setText("Device already connected");
  137. }
  138. private void connectFunc(){
  139. Log.d(TAG, "connectFunc");
  140. WifiP2pDevice device = peers.get(0);
  141. WifiP2pConfig config = new WifiP2pConfig();
  142. config.deviceAddress = device.deviceAddress;
  143. config.wps.setup = WpsInfo.PBC;
  144. mWifiP2pManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
  145. @Override
  146. public void onSuccess() {
  147. Log.d(TAG,"connect success");
  148. tvConnectStatus.setText("device connected");
  149. }
  150. @Override
  151. public void onFailure(int reason) {
  152. Log.d(TAG,"connect fail");
  153. }
  154. });
  155. }
  156. private void disconnectFunc(){
  157. Log.d(TAG, "disconnectFunc");
  158. if (mWifiP2pManager != null && mChannel != null) {
  159. mWifiP2pManager.requestGroupInfo(mChannel, new WifiP2pManager.GroupInfoListener() {
  160. @Override
  161. public void onGroupInfoAvailable(WifiP2pGroup group) {
  162. if (group != null && mWifiP2pManager != null && mChannel != null && group.isGroupOwner()) {
  163. mWifiP2pManager.removeGroup(mChannel, new WifiP2pManager.ActionListener() {
  164. @Override
  165. public void onSuccess() {
  166. Log.d(TAG, "removeGroup onSuccess -");
  167. }
  168. @Override
  169. public void onFailure(int reason) {
  170. Log.d(TAG, "removeGroup onFailure -" + reason);
  171. }
  172. });
  173. }
  174. }
  175. });
  176. }
  177. }
  178. }

補上xml:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context="com.example.chris.myapplication.MainActivity">
  8.  
  9. <TextView
  10. android:id="@+id/id_tvMyDevice"
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"
  13. android:text="My Device:"
  14. app:layout_constraintStart_toStartOf="parent" />
  15.  
  16. <TextView
  17. android:id="@+id/id_tvMacAddress"
  18. android:layout_width="wrap_content"
  19. android:layout_height="wrap_content"
  20. android:text="My Mac Address"
  21. app:layout_constraintTop_toBottomOf="@+id/id_tvMyDevice" />
  22.  
  23. <TextView
  24. android:id="@+id/id_tvDeviceFound"
  25. android:layout_width="wrap_content"
  26. android:layout_height="wrap_content"
  27. android:layout_marginTop="8dp"
  28. android:text="Device Found:"
  29. app:layout_constraintStart_toStartOf="parent"
  30. app:layout_constraintTop_toBottomOf="@+id/id_tvMacAddress" />
  31.  
  32. <TextView
  33. android:id="@+id/id_tvConnectDevice"
  34. android:layout_width="wrap_content"
  35. android:layout_height="wrap_content"
  36. android:text="Searching..."
  37. app:layout_constraintStart_toStartOf="parent"
  38. app:layout_constraintTop_toBottomOf="@+id/id_tvDeviceFound" />
  39.  
  40. <TextView
  41. android:id="@+id/id_tvConnectStatus"
  42. android:layout_width="wrap_content"
  43. android:layout_height="wrap_content"
  44. android:layout_marginTop="8dp"
  45. android:text="no connected"
  46. app:layout_constraintStart_toStartOf="parent"
  47. app:layout_constraintTop_toBottomOf="@+id/id_tvConnectDevice" />
  48.  
  49. </android.support.constraint.ConstraintLayout>
  50.  

在AndroidManifest.xml加入權限:
  1. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  2. <uses-permission android:name="android.permission.BLUETOOTH"/>
  3. <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
  4. <uses-permission android:name="android.permission.INTERNET" />
  5. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

連線成功之後,接下來有時間再來寫加入UDP傳輸試試看。
END

沒有留言:

張貼留言