android wifi直连 wifip2pmanager;使用WiFi 直连,然后通过udp进行通讯。
Android WiFi 直连(Wi-Fi Direct,也称为Wi-Fi P2P)是一种让两台或多台设备通过Wi-Fi技术直接进行点对点连接的技术,无需借助传统的无线路由器或接入点。这种技术使得设备间可以快速建立安全的无线连接,实现文件传输、屏幕共享、游戏对战等多种应用,尤其适用于智能手机、平板电脑、打印机、相机等消费电子设备间的近距离通信。
以下是Android WiFi 直连的基本工作原理和使用步骤:
工作原理:
设备发现:启用Wi-Fi Direct功能的设备可以通过广播信号搜索和发现附近的其他支持Wi-Fi Direct的设备。设备间可以互相检测到对方的存在,并显示在设备列表中供用户选择。
连接请求:用户在设备列表中选择要连接的目标设备后,发起连接请求。目标设备收到请求后,通常需要手动或自动确认接受连接。
组建立:一旦连接请求被接受,两台设备之间会自动建立一个Wi-Fi Direct组。在这个组中,一台设备会被选为“组主人”(Group Owner,GO),相当于小型网络的接入点,负责管理组内的连接和数据传输。另一台设备则作为“客户端”(Client)加入该组。
数据传输:连接建立后,组主人和客户端设备可以使用各自的IP地址和端口号进行直接的TCP/UDP通信。应用程序可以利用这些网络参数创建Socket连接,进行文件传输、消息传递等操作。
例子代码:
public class WifiConnectActivity extends AppCompatActivity {
private Button btnConnect;
private WifiDirectLink wifiDirectLink;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
setContentView(linearLayout);
btnConnect = new AppCompatButton(this);
btnConnect.setText("链接");
AppCompatButton btnConnect2 = new AppCompatButton(this);
btnConnect2.setText("发送");
linearLayout.addView(btnConnect);
linearLayout.addView(btnConnect2);
wifiDirectLink = new WifiDirectLink(getApplicationContext());
// 按钮点击事件 - 连接到对等设备
btnConnect.setOnClickListener(v -> wifiDirectLink.connectToPeer());
btnConnect2.setOnClickListener(v -> wifiDirectLink.send("hello".getBytes()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION
, Manifest.permission.NEARBY_WIFI_DEVICES}, 119);
} else {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION}, 119);
}
}
@Override
protected void onDestroy() {
wifiDirectLink.release();
super.onDestroy();
}
}
连接工具类:
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public class WifiDirectLink {
private static final String TAG = "WifiDirectLink";
private final WifiP2pManager wifiP2pManager;
private final WifiP2pManager.Channel channel;
private Context context;
private final Handler handler = new Handler(Looper.getMainLooper());
private SyncUDP udp;
private String otherClientIp;
public WifiDirectLink(Context context) {
this.context = context;
Log.i(TAG, "WifiDirectLink: begin start-----------------------------------------------");
if (udp == null) {
udp = new SyncUDP(Config.BROADCAST_PORT + 3);
udp.setListener(this::receiveAction);
}
// 初始化Wi-Fi P2P管理器和通道
wifiP2pManager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);
channel = wifiP2pManager.initialize(context, Looper.getMainLooper(), null);
// 创建意图过滤器并添加所需的意图动作
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
// 注册广播接收器
ContextCompat.registerReceiver(context, broadcastReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED);
handler.postDelayed(new Runnable() {
@Override
public void run() {
try {
discoverPeers();
} catch (Exception e) {
e.printStackTrace();
}
handler.postDelayed(this, 8888);
}
}, 88);
}
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive: " + intent.getAction());
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
// 获取连接信息
WifiP2pInfo wifiP2pInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
if (wifiP2pInfo != null) {
new Thread(() -> {
// 获取groupOwnerAddress
InetAddress groupOwnerAddress = wifiP2pInfo.groupOwnerAddress;
// 在这里可以使用groupOwnerAddress进行相应的操作
if (groupOwnerAddress != null) {
String hostAddress = groupOwnerAddress.getHostAddress();
String hostName = groupOwnerAddress.getHostName();
byte[] address = groupOwnerAddress.getAddress();
String canonicalHostName = groupOwnerAddress.getCanonicalHostName();
Log.i(TAG, "onReceive: get host address:" + hostAddress + "; " + hostName + "; " + address + "; " + canonicalHostName);
// start socket connect
otherClientIp = hostAddress;
if (!TextUtils.isEmpty(otherClientIp)) {
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(context.getApplicationContext(), "获取鬣主任ip", Toast.LENGTH_LONG).show());
}
}
}).start();
}
}
}
};
public void send(byte[] buf) {
// 广播 都接受得到
Log.i(TAG, "send: other client ip:" + otherClientIp);
if (udp == null || otherClientIp == null) return;
new Thread(() -> {
String substring = otherClientIp.substring(0, otherClientIp.lastIndexOf("."));
substring = substring + ".255";
udp.sendAction(buf, substring);
}).start();
}
@SuppressLint("MissingPermission")
public void discoverPeers() throws Exception {
wifiP2pManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "onSuccess: scan wifi node");
}
@Override
public void onFailure(int i) {
Log.i(TAG, "onFailure: No nodes scanned");
}
});
}
@SuppressLint("MissingPermission")
public void connectToPeer() {
Log.i(TAG, "connectToPeer: start connect");
wifiP2pManager.requestPeers(channel, wifiP2pDeviceList -> {
List<WifiP2pDevice> deviceList = new ArrayList<>(wifiP2pDeviceList.getDeviceList());
Log.i(TAG, "connectToPeer: item count:" + deviceList.size());
if (deviceList.size() == 0) {
return;
}
for (WifiP2pDevice item : deviceList) {
Log.i(TAG, "connectToPeer: item name:" + item.deviceName + "; " + item.deviceAddress);
// 创建连接配置
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = item.deviceAddress;
connectItem(config, item);
}
});
}
@SuppressLint("MissingPermission")
private void connectItem(WifiP2pConfig config, WifiP2pDevice item) {
try {
wifiP2pManager.connect(channel, config, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.i(TAG, "onSuccess: Link successful for:" + item.deviceName + "; " + item.deviceAddress);
}
@Override
public void onFailure(int reasonCode) {
Log.i(TAG, "onFailure: Link failure for:" + item.deviceName + "; " + item.deviceAddress);
}
});
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "getDevices: connect item error:" + e.getMessage());
}
}
private void receiveAction(byte[] buffer, int len, String ip) {
Log.i(TAG, "receiveAction: ip:" + ip + "; len:" + len);
}
public void release() {
handler.removeCallbacksAndMessages(null);
if (udp != null) {
udp.release();
udp = null;
}
try {
context.unregisterReceiver(broadcastReceiver);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "release: error:" + e.getMessage());
}
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) channel.close();
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "release:close channel error:" + e.getMessage());
}
}
}
udp 通讯类:
import android.util.Log;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SyncUDP implements Runnable {
private static final String TAG = "ReceiveUDP";
private Thread thread;
private DatagramSocket socket;
private OnUpdateListener listener;
private int port;
public void setListener(OnUpdateListener listener) {
this.listener = listener;
}
public void release() {
if (thread != null && !thread.isInterrupted())
thread.interrupt();
listener = null;
closeSocket();
if (thread != null) {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
thread = null;
}
}
public SyncUDP(int port) {
this.port = port;
thread = new Thread(this);
thread.start();
}
public void sendAction(byte[] buf, String ip) {
if (socket == null || socket.isClosed()) return;
try {
DatagramPacket sendPacket = new DatagramPacket(buf, buf.length);
sendPacket.setAddress(InetAddress.getByName(ip));
sendPacket.setPort(port);
socket.send(sendPacket);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "sendAction: send package error:" + e.getMessage());
}
}
@Override
public void run() {
while (!Thread.interrupted()) {
try {
byte[] by = new byte[16];
socket = new DatagramSocket(port);
socket.setBroadcast(true);
while (!Thread.interrupted()) {
try {
// receive data
DatagramPacket receivePacket = new DatagramPacket(by, by.length);
Log.i(TAG, "run: start wait package");
// Join thread
socket.receive(receivePacket);
String ip = receivePacket.getAddress().getHostAddress();
Log.i(TAG, "run: get package len:" + receivePacket.getLength() + "; ip:" + ip);
if (listener != null)
listener.onUpdateUI(receivePacket.getData(), receivePacket.getLength(), ip);
} catch (Exception e) {
e.printStackTrace();
break;
}
}
closeSocket();
} catch (Exception e) {
e.printStackTrace();
}
}
closeSocket();
}
private void closeSocket() {
if (socket != null) {
if (!socket.isClosed()) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
socket = null;
}
}
public interface OnUpdateListener {
void onUpdateUI(byte[] buffer, int len, String ip);
}
}