Android局域网-WIFI直连

781 阅读6分钟

简介:WIFI是指应用无线通信技术将计算机设备互联起来,构成可以互相通信和实现资源共享的网络体系。

Android设备支持两种主要的无线网络连接方式:WiFi直连(Wi-Fi Direct)和普通WiFi。这两种方式的主要区别在于它们的连接方式和用途。

  1. WiFi直连(Wi-Fi Direct) ‌:

    • 也被称为Wi-Fi P2P,是一种允许设备之间直接连接的技术,无需传统的无线路由器或接入点。
    • 这种技术使得设备间可以快速建立安全的无线连接,实现文件传输、屏幕共享、游戏对战等多种应用,尤其适用于智能手机、平板电脑、打印机、相机等消费电子设备间的近距离通信。
    • 在Android 4.0(API level 14)或更高版本中,WiFi直连作为一项功能被引入,允许设备在不通过互联网或移动网络的情况下直接相互通信。IOS好像是没有这功能。
  2. 普通WiFi‌:

    • 这是通过无线路由器或接入点连接到互联网的标准方式。
    • 用户需要通过输入无线网络名称(SSID)和密码来连接到这些网络,以便访问互联网资源。

API

方法说明
initialize()通过 WLAN 框架注册应用。必须先调用此方法,然后再调用任何其他 WLAN P2P 方法。
connect()启动与具有指定配置的设备的对等连接。
cancelConnect()取消任何正在进行的对等群组协商。
requestConnectInfo()请求设备连接信息。
createGroup()以群组所有者的身份,使用当前设备创建对等群组。
removeGroup()移除当前对等群组。
requestGroupInfo()请求对等群组信息。
discoverPeers()启动对等设备发现
requestPeers()请求已发现对等设备的当前列表。

ACTION

WLAN P2P 事件时会广播的 Intent,例如发现新的对等设备时,或设备的 WLAN 状态更改时。您可以通过创建处理这些 Intent 的广播接收器,在应用中注册接收这些 Intent:

ACTION说明
WIFI_P2P_CONNECTION_CHANGED_ACTION当设备的 WLAN 连接状态更改时广播。
WIFI_P2P_PEERS_CHANGED_ACTION当您调用 discoverPeers() 时广播。如果您在应用中处理此 Intent,则通常需要调用 requestPeers() 以获取对等设备的更新列表。
WIFI_P2P_STATE_CHANGED_ACTION当 WLAN P2P 在设备上启用或停用时广播。
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION当设备的详细信息(例如设备名称)更改时广播。

1.权限申请

<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" />

2.判断是否支持P2P,调用initialize初始化

private fun initP2p(): Boolean {
    // Device capability definition check
    if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
        Log.e("TAG", "Wi-Fi Direct is not supported by this device.")
        return false
    }

    // Hardware capability check
    if (wifiManager == null) {
        Log.e("TAG", "Cannot get Wi-Fi system service.")
        return false
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        if (!wifiManager!!.isP2pSupported) {
            Log.e("TAG", "Wi-Fi Direct is not supported by the hardware or Wi-Fi is off.")
            return false
        }
    }

    if (wifiP2pManager == null) {
        Log.e("TAG", "Cannot get Wi-Fi Direct system service.")
        return false
    }
    //初始化
    channel = wifiP2pManager!!.initialize(this@DirectWifiActivity, mainLooper, null)
    if (channel == null) {
        Log.e("TAG", "Cannot initialize Wi-Fi Direct.")
        return false
    }
    return true
}

3.注册广播

private fun receiveReigst() {
    intentFilter = 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)

    wifiP2pReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION == action) {
                Log.i("tag", "当在设备上启用或停用 Wi-Fi 点对点时广播。")
                val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
                if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                    // WiFi P2P is enabled
                    Log.i("tag", "状态改变 WiFi P2P is enabled")

                    //todo
                    //可搜索周围P2P设备 discoverPeers

                } else {
                    // WiFi P2P is not enabled
                    Log.i("tag", "状态改变 WiFi P2P is not enabled");
                }
            } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION == action) {
                Log.i(
                    "tag",
                    "当您调用 discoverPeers() 时广播。如果您在应用中处理此 intent,则通常需要调用 requestPeers() 来获取更新后的对等设备列表。"
                );
                // Request available peers from the WifiP2pManager

                if (currentDirectState != DIRECT_DISCOVER_SUCCESS) {
                    return
                }
                currentDirectState = DIRECT_REQUEST_PEER
                requestPeers()
            } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION == action) {
                Log.i(
                    "tag",
                    "表明Wi-Fi对等网络的连接状态发生了改变,应用可以使用 requestConnectionInfo()、requestNetworkInfo() 或 requestGroupInfo() 来检索当前连接信息。    "
                );
                // Respond to new connection or disconnections
                if (currentDirectState != DIRECT_REQUEST_CONNECT_SUCCESS) {
                    Log.i("tag", "当前状态不需要请求连接信息")
                    return
                }
                requestConnectionInfo()
            } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION == action) {
                Log.i("tag", "表明该设备的配置信息发生了改变");
                val device: WifiP2pDevice? =
                    intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
                Log.i(
                    "tag",
                    "本设备信息发生变化:" + device!!.deviceName + ", " + device.deviceAddress
                )
                requestDeviceInfo()
                // Respond to this device's wifi state changing
            }
        }
    }
    registerReceiver(wifiP2pReceiver, intentFilter)
}

private fun requestDeviceInfo() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.NEARBY_WIFI_DEVICES
            ) != PackageManager.PERMISSION_GRANTED
        ) {

            return
        }
        wifiP2pManager!!.requestDeviceInfo(channel!!
        ) { p0 -> Log.i("tag", p0!!.toString()) }

    }
}

4.发现可连接的对等设备,请调用 discoverPeers(),以检测范围内的可用对等设备。对此功能的调用为异步操作。 当应用接收到 WIFI_P2P_PEERS_CHANGED_ACTION Intent 时,您可以通过 requestPeers() 请求已发现对等设备的列表。以下代码展示如何完成此项设置:

private fun discoverPeers() {
    // Check if location permission is granted
    if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION
            ),
            PERMISSION_REQUEST_CODE
        )
        return
    }

    // Check if location service is enabled
    if (!wifiManager!!.isWifiEnabled) {
        Toast.makeText(this@DirectWifiActivity, "Please enable WiFi", Toast.LENGTH_SHORT).show()

        val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
        val componentName = panelIntent.resolveActivity(packageManager)
        if (componentName != null) {
            startActivity(panelIntent)
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
        } else {
            wifiManager!!.setWifiEnabled(true)//android Q 默认返回false
        }

        return
    }

    if (!isLocationEnabled()) {
        Toast.makeText(this@DirectWifiActivity, "Please enable Location", Toast.LENGTH_SHORT)
            .show()
        startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
        return
    }

    currentDirectState = DIRECT_DISCOVER_CONNECT
    wifiP2pManager!!.discoverPeers(channel, object : WifiP2pManager.ActionListener {
        override fun onSuccess() {
            // Peers discovery initiated
            currentDirectState = DIRECT_DISCOVER_SUCCESS
            Toast.makeText(this@DirectWifiActivity, "Discovering peers", Toast.LENGTH_SHORT)
                .show()
        }

        override fun onFailure(reason: Int) {
            currentDirectState = DIRECT_DISCOVER_FAIL
            Toast.makeText(
                this@DirectWifiActivity,
                "Failed to discover peers $reason",
                Toast.LENGTH_SHORT
            )
                .show()
        }
    })
}

5.停止寻找

wifiP2pManager!!.stopPeerDiscovery(channel, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Log.i("tag", "停止成功")
    }

    override fun onFailure(p0: Int) {
        Log.i("tag", "停止成功")
    }

})

6.请求WIFI列表数据

private fun requestPeers() {
    if (ActivityCompat.checkSelfPermission(
            this@DirectWifiActivity,
            android.Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            this@DirectWifiActivity,
            arrayOf<String>(android.Manifest.permission.ACCESS_FINE_LOCATION),
            PERMISSION_REQUEST_CODE
        )
        return
    }
    wifiP2pManager!!.requestPeers(channel, peerListListener)
}

/**
 * 收到的设备列表信息
 */
private val peerListListener = object : WifiP2pManager.PeerListListener {
    @SuppressLint("NotifyDataSetChanged")
    override fun onPeersAvailable(peers: WifiP2pDeviceList?) {
        if (peers != null) {
            val peerList = peers.deviceList
            Log.i("tag", peerList.toString())
            if (peerList.isNotEmpty()) {
                if (deviceListAdapter == null) {
                    deviceListAdapter =
                        DeviceListAdapter(this@DirectWifiActivity, peerList.toList())
                    mBinding.recyclerView.layoutManager = LinearLayoutManager(
                        this@DirectWifiActivity,
                        LinearLayoutManager.VERTICAL,
                        false
                    )
                    mBinding.recyclerView.adapter = deviceListAdapter
                } else {
                    deviceListAdapter?.setList(peerList.toList())
                    deviceListAdapter?.notifyDataSetChanged()
                }
         
                if(connectDevice==null) {
                    currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
                }

            } else {
                Log.i("tag", "未找到设备")
                currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
            }
        } else {
            Log.i("tag", "未找到设备")
            currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
        }
    }
}

7.连接设备

/**
     * 连接群组 、连接设备一样
     */
    private fun connect(device: WifiP2pDevice) {
        if (ActivityCompat.checkSelfPermission(
                this@DirectWifiActivity,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ActivityCompat.checkSelfPermission(
                    this@DirectWifiActivity,
                    android.Manifest.permission.NEARBY_WIFI_DEVICES
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                return
            }
        }

        /**
         * WifiP2pDevice.AVAILABLE:可连接
         * WifiP2pDevice.CONNECTED:已连接
         * WifiP2pDevice.INVITED:已请求连接
         */

        when (device.status) {
            WifiP2pDevice.AVAILABLE -> {
                // 请求连接
                Log.i("tag", "发起连接 $device")

                val config = WifiP2pConfig()
                config.deviceAddress = device.deviceAddress
                currentDirectState = DIRECT_REQUEST_CONNECT
                wifiP2pManager!!.connect(channel,
                    config,
                    object : WifiP2pManager.ActionListener {
                        override fun onSuccess() {
                            // Connection initiated
                            currentDirectState = DIRECT_REQUEST_CONNECT_SUCCESS
                            Toast.makeText(
                                this@DirectWifiActivity,
                                "发起成功",
                                Toast.LENGTH_SHORT
                            ).show()
                            Log.i("tag", "发起成功")
                        }

                        override fun onFailure(reason: Int) {
                            // Connection failed
                            currentDirectState = DIRECT_REQUEST_CONNECT_FAIL
                            Toast.makeText(
                                this@DirectWifiActivity,
                                "发起失败",
                                Toast.LENGTH_SHORT
                            ).show()
                            Log.i("tag", "发起失败")
                        }
                    })
            }

            WifiP2pDevice.CONNECTED -> {
                // 断开连接
//                wifiP2pManager!!.removeGroup(channel, object : WifiP2pManager.ActionListener {
//                    override fun onSuccess() {
//                        Log.i("tag", "断开成功")
//                    }
//
//                    override fun onFailure(p0: Int) {
//                        Log.i("tag", "断开失败")
//                    }
//
//                })
                Log.i("tag", "已经连接")
                requestConnectionInfo()
            }

            WifiP2pDevice.INVITED -> {
                // 接受连接
                // 关闭连接请求
                wifiP2pManager!!.cancelConnect(channel, object : WifiP2pManager.ActionListener {
                    override fun onSuccess() {
                        Log.i("TAG", "cancelConnect success.");
                    }

                    override fun onFailure(p0: Int) {
                        Log.i("TAG", "cancelConnect failed.");
                    }
                })
            }
        }
    }

8.断开连接

private fun cancelConnect() {
    wifiP2pManager!!.cancelConnect(channel, object : WifiP2pManager.ActionListener {
        override fun onSuccess() {
            Log.d("tag", "cancel success")
        }

        override fun onFailure(p0: Int) {
            Log.d("tag", "cancel fail")
        }

    })
}

9.连接上后,可通过WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION广播去请求连接信息,作为客户端可以获取到服务端返回的信息,也可以作为服务端创建server

private fun requestConnectionInfo() {
    currentDirectState = DIRECT_REQUEST_INFO
    wifiP2pManager!!.requestConnectionInfo(
        channel,
        connectionInfoListener
    )
}

private val connectionInfoListener =
    WifiP2pManager.ConnectionInfoListener { info ->
        if (info != null) {
            currentDirectState = DIRECT_REQUEST_INFO_SUCCESS
            if (info.groupFormed && info.isGroupOwner) {
                // 服务端不需要做额外处理
                Log.d("Client", "本设备为服务端");
                startServer()
            } else if (info.groupFormed) {
                Log.d("Client", "本设备为客户端")
                Log.d("Client", "服务端ip = ${info.groupOwnerAddress.hostAddress}")
                createClientSocket(info.groupOwnerAddress.hostAddress)
            }
        } else {
            currentDirectState = DIRECT_REQUEST_INFO_FAIL
            Log.d("tag", "connectionInfo 为空");
        }
    }

10.还可以创建组群,移除组群,获取组群信息

wifiP2pManager!!.createGroup(channel, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Toast.makeText(this@DirectWifiActivity, "Group created", Toast.LENGTH_SHORT).show()
    }

    override fun onFailure(reason: Int) {
        Toast.makeText(
            this@DirectWifiActivity,
            "Failed to create group",
            Toast.LENGTH_SHORT
        )
            .show()
    }
})

wifiP2pManager!!.removeGroup(channel, object : WifiP2pManager.ActionListener {
    override fun onSuccess() {
        Log.i("TAG", "onSuccess: removeGroup")
    }

    override fun onFailure(i: Int) {
        Log.i("TAG", "onFailure: removeGroup")
    }
})

wifiP2pManager!!.requestGroupInfo(channel) { wifiP2pGroup ->
    if (wifiP2pGroup != null) {
        Log.i("tag", "onGroupInfoAvailable: wifiP2pGroup != null")
    } else {
        Log.i("tag", "onGroupInfoAvailable: wifiP2pGroup == null")
    }
}

11.案例

import android.Manifest
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.net.wifi.WifiManager
import android.net.wifi.p2p.WifiP2pConfig
import android.net.wifi.p2p.WifiP2pDevice
import android.net.wifi.p2p.WifiP2pDeviceList
import android.net.wifi.p2p.WifiP2pManager
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.common.base.BaseActivity
import com.common.viewmodel.EmptyViewModel
import com.fei.firstproject.databinding.ActivityDirectWifiBinding
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket
import kotlin.random.Random

/***
 *
 *  点对点wifi
 * 以下 API 还需要启用位置信息模式:
 *
 * discoverPeers()
 * discoverServices()
 * requestPeers()
 *
 */
class DirectWifiActivity : BaseActivity<EmptyViewModel, ActivityDirectWifiBinding>() {

    private val PERMISSION_REQUEST_CODE = 1
    private val wifiManager: WifiManager? by lazy(LazyThreadSafetyMode.NONE) {
        applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
    }
    private val wifiP2pManager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) {
        getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager?
    }

    private var currentDirectState = -1
    private var channel: WifiP2pManager.Channel? = null
    private var wifiP2pReceiver: BroadcastReceiver? = null
    private var intentFilter: IntentFilter? = null
    private var connectDevice: WifiP2pDevice? = null
    private var deviceListAdapter: DeviceListAdapter? = null

    private val DIRECT_DISCOVER_CONNECT = 1 //发现连接
    private val DIRECT_DISCOVER_SUCCESS = 2 //发现成功
    private val DIRECT_DISCOVER_FAIL = 3 //发现失败
    private val DIRECT_REQUEST_PEER = 4 //请求peer
    private val DIRECT_REQUEST_PEER_FOUND = 5 //找到
    private val DIRECT_REQUEST_PEER_UNFOUND = 6 //找不到
    private val DIRECT_REQUEST_CONNECT = 7//发起连接
    private val DIRECT_REQUEST_CONNECT_SUCCESS = 8//还请连接成功
    private val DIRECT_REQUEST_CONNECT_FAIL = 9//发起连接失败
    private val DIRECT_REQUEST_INFO = 10 //发起获取设备信息
    private val DIRECT_REQUEST_INFO_SUCCESS = 11 //获取设备信息成功
    private val DIRECT_REQUEST_INFO_FAIL = 12 //获取设备信息失败

    override fun createObserver() {

    }

    override fun initViewAndData(savedInstanceState: Bundle?) {
        mBinding.btnCreateGroup.setOnClickListener {
            createGroup()
        }
        mBinding.btnConnectGroup.setOnClickListener {
            connectDevice?.let { connectGroup(it) }
        }
        mBinding.btnRemoveGroup.setOnClickListener {
            removeGroup()
        }
        mBinding.btnDiscover.setOnClickListener {
            discoverPeers()
        }
        mBinding.btnConnect.setOnClickListener {
            connectDevice?.let { connect(it) }
        }
        mBinding.btnSend.setOnClickListener {
            sendMessage()
        }
        mBinding.btnCancel.setOnClickListener {
            cancelConnect()
        }
        mBinding.btnRequestGroupInfo.setOnClickListener {
            requestGroupInfo()
        }
        mBinding.btnConnectInfo.setOnClickListener {
            requestConnectionInfo()
        }

        if (initP2p()) {
            receiveReigst()
        }
    }

    private fun receiveReigst() {
        intentFilter = 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)

        wifiP2pReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val action = intent.action
                if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION == action) {
                    Log.i("tag", "当在设备上启用或停用 Wi-Fi 点对点时广播。")
                    val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
                    if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                        // WiFi P2P is enabled
                        Log.i("tag", "状态改变 WiFi P2P is enabled")

                        //todo
                        //可搜索周围P2P设备 discoverPeers

                    } else {
                        // WiFi P2P is not enabled
                        Log.i("tag", "状态改变 WiFi P2P is not enabled");
                    }
                } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION == action) {
                    Log.i(
                        "tag",
                        "当您调用 discoverPeers() 时广播。如果您在应用中处理此 intent,则通常需要调用 requestPeers() 来获取更新后的对等设备列表。"
                    );
                    // Request available peers from the WifiP2pManager

                    if (currentDirectState != DIRECT_DISCOVER_SUCCESS) {
                        return
                    }
                    currentDirectState = DIRECT_REQUEST_PEER
                    requestPeers()
                } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION == action) {
                    Log.i(
                        "tag",
                        "表明Wi-Fi对等网络的连接状态发生了改变,应用可以使用 requestConnectionInfo()、requestNetworkInfo() 或 requestGroupInfo() 来检索当前连接信息。    "
                    );
                    // Respond to new connection or disconnections
                    if (currentDirectState != DIRECT_REQUEST_CONNECT_SUCCESS) {
                        Log.i("tag", "当前状态不需要请求连接信息")
                        return
                    }
                    requestConnectionInfo()
                } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION == action) {
                    Log.i("tag", "表明该设备的配置信息发生了改变");
                    val device: WifiP2pDevice? =
                        intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
                    Log.i(
                        "tag",
                        "本设备信息发生变化:" + device!!.deviceName + ", " + device.deviceAddress
                    )
                    requestDeviceInfo()
                    // Respond to this device's wifi state changing
                }
            }
        }
        registerReceiver(wifiP2pReceiver, intentFilter)
    }

    private fun requestDeviceInfo() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.ACCESS_FINE_LOCATION
                ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.NEARBY_WIFI_DEVICES
                ) != PackageManager.PERMISSION_GRANTED
            ) {

                return
            }
            wifiP2pManager!!.requestDeviceInfo(channel!!
            ) { p0 -> Log.i("tag", p0!!.toString()) }

        }
    }


    private fun requestPeers() {
        if (ActivityCompat.checkSelfPermission(
                this@DirectWifiActivity,
                android.Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this@DirectWifiActivity,
                arrayOf<String>(android.Manifest.permission.ACCESS_FINE_LOCATION),
                PERMISSION_REQUEST_CODE
            )
            return
        }
        wifiP2pManager!!.requestPeers(channel, peerListListener)
    }

    private fun requestConnectionInfo() {
        currentDirectState = DIRECT_REQUEST_INFO
        wifiP2pManager!!.requestConnectionInfo(
            channel,
            connectionInfoListener
        )
    }

    private fun connectGroup(
        wifiP2pDevice: WifiP2pDevice
    ) {
        // 如果连接对象为群组GroupOwner
        if (wifiP2pDevice.isGroupOwner) {
            connect(wifiP2pDevice)
        } else {
            Log.i("TAG", "对方设备不是群组")
        }
    }

    private fun requestGroupInfo() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ActivityCompat.checkSelfPermission(
                    this@DirectWifiActivity,
                    android.Manifest.permission.NEARBY_WIFI_DEVICES
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                return
            }
        }
        wifiP2pManager!!.requestGroupInfo(channel) { wifiP2pGroup ->
            if (wifiP2pGroup != null) {
                Log.i("tag", "onGroupInfoAvailable: wifiP2pGroup != null")
            } else {
                Log.i("tag", "onGroupInfoAvailable: wifiP2pGroup == null")
            }
        }
    }

    private fun removeGroup() {
        wifiP2pManager!!.removeGroup(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.i("TAG", "onSuccess: removeGroup")
            }

            override fun onFailure(i: Int) {
                Log.i("TAG", "onFailure: removeGroup")
            }
        })
    }

    private fun cancelConnect() {
        wifiP2pManager!!.cancelConnect(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("tag", "cancel success")
            }

            override fun onFailure(p0: Int) {
                Log.d("tag", "cancel fail")
            }

        })
    }

    private var serverSocket: ServerSocket? = null
    private fun startServer() {
        // 创建服务器 Socket
        if (serverSocket != null) {
            return
        }
        try {
            serverSocket = ServerSocket(8888)
            Toast.makeText(this@DirectWifiActivity, "服务器 Socket 已创建", Toast.LENGTH_LONG)
                .show()
        } catch (e: IOException) {
            e.printStackTrace()
        }

        // 开启接收线程监听客户端连接
        val acceptThread = Thread {

            try {
                // 等待客户端连接
                val socket: Socket = serverSocket!!.accept()
                Toast.makeText(this@DirectWifiActivity, "客户端已连接", Toast.LENGTH_LONG).show()

                while (true) {
                    // 读取客户端发送的数据
                    val reader = BufferedReader(InputStreamReader(socket.getInputStream()))
                    val data = reader.readLine()

                    runOnUiThread {
                        Toast.makeText(this@DirectWifiActivity, "收到数据$data", Toast.LENGTH_LONG)
                            .show()
                    }

                    // 发送响应给客户端
                    val writer =
                        BufferedWriter(OutputStreamWriter(socket.getOutputStream()))
                    writer.write(Random.nextInt(1000).toString())
                    writer.newLine()
                    writer.flush()
                }

            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        acceptThread.start()
    }

    private var clientSocket: Socket? = null
    private fun sendMessage() {
        if (clientSocket == null && connectDevice != null) {
            createClientSocket(connectDevice!!.deviceAddress)
        }
        if (clientSocket == null) {
            return
        }
        val thread = Thread {
            try {
                // 向服务端发送数据
                val writer = BufferedWriter(OutputStreamWriter(clientSocket!!.getOutputStream()))
                writer.write(Random.nextInt(1000).toString())
                writer.newLine()
                writer.flush()

                // 读取服务端响应数据
                val reader = BufferedReader(InputStreamReader(clientSocket!!.getInputStream()))
                val data = reader.readLine()

                runOnUiThread {
                    Toast.makeText(this@DirectWifiActivity, "收到数据$data", Toast.LENGTH_LONG)
                        .show()
                }

                Log.d("Client", "服务端返回的响应:$data")
            } catch (e: IOException) {
                e.printStackTrace()
                clientSocket!!.close()
                clientSocket = null
            }
        }
        thread.start()
    }

    /**
     * 连接群组 、连接设备一样
     */
    private fun connect(device: WifiP2pDevice) {
        if (ActivityCompat.checkSelfPermission(
                this@DirectWifiActivity,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ActivityCompat.checkSelfPermission(
                    this@DirectWifiActivity,
                    android.Manifest.permission.NEARBY_WIFI_DEVICES
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                return
            }
        }

        /**
         * WifiP2pDevice.AVAILABLE:可连接
         * WifiP2pDevice.CONNECTED:已连接
         * WifiP2pDevice.INVITED:已请求连接
         */

        when (device.status) {
            WifiP2pDevice.AVAILABLE -> {
                // 请求连接
                Log.i("tag", "发起连接 $device")

                val config = WifiP2pConfig()
                config.deviceAddress = device.deviceAddress
                currentDirectState = DIRECT_REQUEST_CONNECT
                wifiP2pManager!!.connect(channel,
                    config,
                    object : WifiP2pManager.ActionListener {
                        override fun onSuccess() {
                            // Connection initiated
                            currentDirectState = DIRECT_REQUEST_CONNECT_SUCCESS
                            Toast.makeText(
                                this@DirectWifiActivity,
                                "发起成功",
                                Toast.LENGTH_SHORT
                            ).show()
                            Log.i("tag", "发起成功")
                        }

                        override fun onFailure(reason: Int) {
                            // Connection failed
                            currentDirectState = DIRECT_REQUEST_CONNECT_FAIL
                            Toast.makeText(
                                this@DirectWifiActivity,
                                "发起失败",
                                Toast.LENGTH_SHORT
                            ).show()
                            Log.i("tag", "发起失败")
                        }
                    })
            }

            WifiP2pDevice.CONNECTED -> {
                // 断开连接
//                wifiP2pManager!!.removeGroup(channel, object : WifiP2pManager.ActionListener {
//                    override fun onSuccess() {
//                        Log.i("tag", "断开成功")
//                    }
//
//                    override fun onFailure(p0: Int) {
//                        Log.i("tag", "断开失败")
//                    }
//
//                })
                Log.i("tag", "已经连接")
                requestConnectionInfo()
            }

            WifiP2pDevice.INVITED -> {
                // 接受连接
                // 关闭连接请求
                wifiP2pManager!!.cancelConnect(channel, object : WifiP2pManager.ActionListener {
                    override fun onSuccess() {
                        Log.i("TAG", "cancelConnect success.");
                    }

                    override fun onFailure(p0: Int) {
                        Log.i("TAG", "cancelConnect failed.");
                    }
                })
            }
        }
    }

    override fun onResume() {
        super.onResume()
    }


    override fun onPause() {
        super.onPause()

    }

    private fun createGroup() {

        if (serverSocket != null) {
            return
        }

        // Check if location permission is granted
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
                PERMISSION_REQUEST_CODE
            )
            return
        }

        // Check if location service is enabled
        if (!wifiManager!!.isWifiEnabled) {
            Toast.makeText(this, "Please enable WiFi", Toast.LENGTH_SHORT).show()
            startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
            return
        }
        wifiP2pManager!!.createGroup(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Toast.makeText(this@DirectWifiActivity, "Group created", Toast.LENGTH_SHORT).show()
            }

            override fun onFailure(reason: Int) {
                Toast.makeText(
                    this@DirectWifiActivity,
                    "Failed to create group",
                    Toast.LENGTH_SHORT
                )
                    .show()
            }
        })
    }

    /**
     * 初始化
     */
    private fun initP2p(): Boolean {
        // Device capability definition check
        if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) {
            Log.e("TAG", "Wi-Fi Direct is not supported by this device.")
            return false
        }

        // Hardware capability check
        if (wifiManager == null) {
            Log.e("TAG", "Cannot get Wi-Fi system service.")
            return false
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (!wifiManager!!.isP2pSupported) {
                Log.e("TAG", "Wi-Fi Direct is not supported by the hardware or Wi-Fi is off.")
                return false
            }
        }

        if (wifiP2pManager == null) {
            Log.e("TAG", "Cannot get Wi-Fi Direct system service.")
            return false
        }
        channel = wifiP2pManager!!.initialize(this@DirectWifiActivity, mainLooper, null)
        if (channel == null) {
            Log.e("TAG", "Cannot initialize Wi-Fi Direct.")
            return false
        }
        return true
    }

    private fun isLocationEnabled(): Boolean {
        val locationMode: Int
        val locationProviders: String
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            locationMode = Settings.Secure.getInt(
                contentResolver,
                Settings.Secure.LOCATION_MODE,
                Settings.Secure.LOCATION_MODE_OFF
            )
            locationMode != Settings.Secure.LOCATION_MODE_OFF
        } else {
            locationProviders = Settings.Secure.getString(
                contentResolver,
                Settings.Secure.LOCATION_PROVIDERS_ALLOWED
            )
            !TextUtils.isEmpty(locationProviders)
        }
    }


    private fun discoverPeers() {
        // Check if location permission is granted
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION
                ),
                PERMISSION_REQUEST_CODE
            )
            return
        }

        // Check if location service is enabled
        if (!wifiManager!!.isWifiEnabled) {
            Toast.makeText(this@DirectWifiActivity, "Please enable WiFi", Toast.LENGTH_SHORT).show()

            val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
            val componentName = panelIntent.resolveActivity(packageManager)
            if (componentName != null) {
                startActivity(panelIntent)
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                startActivity(Intent(Settings.ACTION_WIFI_SETTINGS))
            } else {
                wifiManager!!.setWifiEnabled(true)//android Q 默认返回false
            }

            return
        }

        if (!isLocationEnabled()) {
            Toast.makeText(this@DirectWifiActivity, "Please enable Location", Toast.LENGTH_SHORT)
                .show()
            startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
            return
        }

        currentDirectState = DIRECT_DISCOVER_CONNECT
        wifiP2pManager!!.discoverPeers(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                // Peers discovery initiated
                currentDirectState = DIRECT_DISCOVER_SUCCESS
                Toast.makeText(this@DirectWifiActivity, "Discovering peers", Toast.LENGTH_SHORT)
                    .show()
            }

            override fun onFailure(reason: Int) {
                currentDirectState = DIRECT_DISCOVER_FAIL
                Toast.makeText(
                    this@DirectWifiActivity,
                    "Failed to discover peers $reason",
                    Toast.LENGTH_SHORT
                )
                    .show()
            }
        })
    }

    private val connectionInfoListener =
        WifiP2pManager.ConnectionInfoListener { info ->
            if (info != null) {
                currentDirectState = DIRECT_REQUEST_INFO_SUCCESS
                if (info.groupFormed && info.isGroupOwner) {
                    // 服务端不需要做额外处理
                    Log.d("Client", "本设备为服务端");
                    startServer()
                } else if (info.groupFormed) {
                    Log.d("Client", "本设备为客户端")
                    Log.d("Client", "服务端ip = ${info.groupOwnerAddress.hostAddress}")
                    createClientSocket(info.groupOwnerAddress.hostAddress)
                }
            } else {
                currentDirectState = DIRECT_REQUEST_INFO_FAIL
                Log.d("tag", "connectionInfo 为空");
            }
        }

    private fun createClientSocket(address: String) {
        val thread = Thread {
            if (clientSocket == null) {
                try {
                    clientSocket = Socket()
                    val inetSocketAddress = InetSocketAddress(address, 8888)
                    clientSocket!!.bind(null)
                    clientSocket!!.connect(inetSocketAddress, 5000)
                    Log.d("Client", "连接服务器成功:" + clientSocket!!.inetAddress)
                } catch (e: Exception) {
                    e.printStackTrace()
                }

            }
        }
        thread.start()
    }

    private fun stopPeerDiscovery() {
        Log.i("tag", "停止找寻设备")
        wifiP2pManager!!.stopPeerDiscovery(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.i("tag", "停止成功")
            }

            override fun onFailure(p0: Int) {
                Log.i("tag", "停止成功")
            }

        })
    }

    /**
     */
    private fun disconnectP2pWifi() {
        wifiP2pManager!!.removeGroup(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.i("tag", "断开成功")

            }

            override fun onFailure(p0: Int) {
                Log.i("tag", "断开失败")
            }
        })
    }

    /**
     * discover 收到的设备信息
     */
    private val peerListListener = object : WifiP2pManager.PeerListListener {
        @SuppressLint("NotifyDataSetChanged")
        override fun onPeersAvailable(peers: WifiP2pDeviceList?) {
            if (peers != null) {
                val peerList = peers.deviceList
                Log.i("tag", peerList.toString())
                if (peerList.isNotEmpty()) {
                    if (deviceListAdapter == null) {
                        deviceListAdapter =
                            DeviceListAdapter(this@DirectWifiActivity, peerList.toList())
                        mBinding.recyclerView.layoutManager = LinearLayoutManager(
                            this@DirectWifiActivity,
                            LinearLayoutManager.VERTICAL,
                            false
                        )
                        mBinding.recyclerView.adapter = deviceListAdapter
                    } else {
                        deviceListAdapter?.setList(peerList.toList())
                        deviceListAdapter?.notifyDataSetChanged()
                    }
                    peerList.forEach {
                        if (it.deviceName == "Android_79b2") {
                            connectDevice = it
                            currentDirectState = DIRECT_REQUEST_PEER_FOUND
                            Log.i("tag", "找到设备了")
                        } else if (it.status == WifiP2pDevice.CONNECTED) {
                            //断开其他设备,才能连接该设备
                            Log.i("tag", "断开${it.deviceName}")
                            disconnectP2pWifi()
                            return@forEach
                        }
                    }

                    if(connectDevice==null) {
                        currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
                    }

                } else {
                    Log.i("tag", "未找到设备")
                    currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
                }
            } else {
                Log.i("tag", "未找到设备")
                currentDirectState = DIRECT_REQUEST_PEER_UNFOUND
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (wifiP2pReceiver != null) {
            unregisterReceiver(wifiP2pReceiver)
        }
        if (clientSocket != null) {
            clientSocket!!.close()
        }
        if (serverSocket != null) {
            serverSocket!!.close()
        }
    }
}

qrcode_for_gh_cde562595b7f_258.jpg

文章上如有错误,欢迎留言,谢谢大家支持