前言之前一段时间一直加班,淦。五一,有点时间,简单的陈述一下,wlan直连页面的跳转和状态获取以及监听。
1. 先看效果
2. 布局文件
2.1 wifi_p2p_actvity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="点击手动获取wlan直连连接状态"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请点击上方按钮获取最新状态值"
android:gravity="center"
android:id="@+id/txt"/>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="@string/hyper_link_tip_direct"
android:gravity="center"
android:id="@+id/hyper_link_tip_direct"/>
</LinearLayout>
2.2 strings.xml
<resources>
<string name="app_name">系统跳转</string>
<string name="hyper_link_tip_direct">请点击:wlan直连 实现跳转</string>
<string name="hyper_link_wlan_direct">wlan直连</string>
</resources>
3. WiFiP2pActivity.kt
3.1 跳转到wlan直连页面方式
// wlan direct页面
private fun startWlanDirectActivity() {
val intent = Intent()
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.action = "android.intent.action.MAIN"
val cn = ComponentName(
"com.android.settings",
"com.android.settings.Settings\$WifiP2pSettingsActivity" // 华为 nova6 wlanDirect页面(亲测)
)
intent.component = cn
startActivity(intent)
}
3.2 定位服务权限检查
如果想获取或者监听wlan直连的设备信息和状态,就必须让你写的activity拥有位置定位信息的权限,否则监听或者获取不到设备信息。
private fun checkLocationPermission(){
// 需要动态检查定位服务的权限是否开启
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_LOCATION_CODE
)
return
}
}
/**
* 请求权限结果
*/
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_LOCATION_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
context,
"请授予该应用定位服务权限,否则无法获取wifi p2p 连接状态",
Toast.LENGTH_SHORT
).show()
}
}
}
3.3 广播监听
想要实时监听wlan直连的连接状态的话,自然少不了广播,而wlan直连的广播监听以后很多,这里只监听设备连接和断开。
//1. 定义一个WiFiDirectBroadcastReceiver 广播
private inner class WiFiDirectBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(p0: Context?, intent: Intent?) {
when (intent?.action) {
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
Log.e(TAG, "intent = ${intent.extras.toString()}")
val networkInfo =
intent.getParcelableExtra<NetworkInfo>(WifiP2pManager.EXTRA_NETWORK_INFO)
val wifiP2pDevice =
intent.getParcelableExtra<WifiP2pDevice>(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
connectState = if (networkInfo?.isConnected == true) {
Log.d(TAG, "Connect to wifi p2p. ${wifiP2pDevice?.deviceName}")
true
} else {
Log.d(TAG, "DisConnect to wifi p2p.")
false
}
updatePage()
}
}
}
}
//2.在onCreate()中注册
private fun registerReceiver() {
if (broadcastReceiver != null) return
broadcastReceiver = WiFiDirectBroadcastReceiver()
val intentFilter = IntentFilter()
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
context?.registerReceiver(broadcastReceiver, intentFilter)
}
//3. 在onDestroy()中反注册
private fun unregisterReceiver() {
if (broadcastReceiver == null) return
context?.unregisterReceiver(broadcastReceiver)
broadcastReceiver = null
}
3.4 判断wlan直连是否有设备的API
仅仅通过监听只能解决动态变化的场景,如果wlan直连一直是连接的状态,此时想获取到信息的话,只能通过调用api来判断了。在android官网上关于wlan Direct 的api都是有介绍的,此处不在赘述。
- 当然想要这个api,你需要在onCreate()中做以下几件事
private var context: Context? = null
private var manager: WifiP2pManager? = null
private var channel: WifiP2pManager.Channel? = null
private var broadcastReceiver: BroadcastReceiver? = null
private var connectState = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.wifi_p2p_activity_main)
checkLocationPermission()
context = this
manager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
channel = manager?.initialize(this, mainLooper, null)
registerReceiver()
updatePage()
- requestPeers用来扫描发现已连接的设备
@SuppressLint("MissingPermission")
private fun startSearch() {
manager?.requestPeers(channel, object : WifiP2pManager.PeerListListener {
override fun onPeersAvailable(p0: WifiP2pDeviceList?) {
connectState = false
p0?.deviceList?.forEach {
if (WifiP2pDevice.CONNECTED == it.status) {
Log.d(TAG, "One device connected.${it?.deviceName}")
connectState = true
updatePage(it?.deviceName)
return
}
}
}
})
}
4 页面跳转和刷新
4.1 在onCtreate()中添加页面跳转逻辑
findViewById<Button>(R.id.btn).setOnClickListener {
startSearch()
}
// wlan直连
setHyperLinkTips(
findViewById<TextView>(R.id.hyper_link_tip_direct),
getString(R.string.hyper_link_tip_direct),
getString(R.string.hyper_link_wlan_direct),
"android.settings.WIFI_P2P_SETTINGS",
this
)
/**
* 设置超链接
* @tipsView: 超链接设置的TextView
* @content:文本所有的内容
* @hyperText:超链接文字
* @action:intent跳转的action
* @context:Context
* Tips:超链接文字hyperText要在content中包含
*/
private fun setHyperLinkTips(
tipsView: TextView?,
content: String,
hyperText: String,
action: String,
context: Context
) {
val spannableString = SpannableStringBuilder(content)
val span = object : ClickableSpan() {
override fun onClick(p0: View) {
Log.i(TAG, "Go to $hyperText page.")
try {
startWlanDirectActivity()
} catch (e: Exception) {
Log.i(TAG, "Go to $hyperText page fail.")
}
}
}
val startIndex = content.indexOf(hyperText)
if (startIndex == -1) {
return
}
val endIndex = startIndex + hyperText.length
spannableString.setSpan(span, startIndex, endIndex, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
tipsView?.movementMethod = LinkMovementMethod.getInstance()
tipsView?.text = spannableString
tipsView?.highlightColor = Color.parseColor("#36969696");
}
4.2 页面刷新
private fun updatePage(deviceName: String? = null) {
Log.i(TAG, "updatePage...isConnected = ${isConnected()}")
findViewById<TextView>(R.id.txt).text = "device: $deviceName state: ${isConnected()}"
}
总结: 广播动态监听 + api 静态调用 = 无死角获取wlan直连连接的设备信息和状态。
(如有错误,欢迎批评指正,请大佬轻喷)