android wifi直连 wifip2pmanager

发布于:2024-04-19 ⋅ 阅读:(22) ⋅ 点赞:(0)

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);
    }
}