WifiManager的getConnectionInfo被弃用了?快来使用ConnectivityManager获取更全的网络信息吧

前言

最近在使用flutter写桌面端的一个adb工具,可以使用adb命令无线连接设备,需要电脑和手机在同一局域网内,但是需要手机的ip地址。于是我想到写一个android桌面小组件,点一下就获取WiFi的ipv4地址并显示出来,先去找gpt问了一下,告诉我使用WifiManager,浅看一下逻辑非常简单1.png
但是…用起来才发现被弃用了,本着遵循官方的建议,还是去寻找一下替代的方法吧
2.png

实现思路

去官网翻文档发现WifiInfo被移动到ConnectivityManager中的NetworkCapabilities#getTransportInfo(),官方还提示你可以继续用这个被弃用的api,但是这个api不会被支持新的功能了
3.png
3.1.png
而获取IP地址的方法被移动到了android.net.LinkProperties这个类中
4.png
官方还贴了一个例子,大体思路就是先获取ConnectivityManager的实例,然后创建一个networkRequest请求,注册networkcallback的监听,就可以在wifi变化时监听到网络信息了

使用callback监听网络信息

MainActivity.kt

import android.content.Context
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {

    private val TAG = "wifiState"

    var handler = object : Handler(Looper.getMainLooper()){
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                0 -> {
                    val linkProperties = msg.obj as LinkProperties
                    findViewById<TextView>(R.id.ip).text = "${linkProperties.linkAddresses[1]}"
                }
                1->{
                    findViewById<TextView>(R.id.ip).text = "无连接"
                }
            }
        }
    }

    private val networkCallback = object : NetworkCallback(){
        override fun onAvailable(network: Network) {
            super.onAvailable(network)
            Log.w(TAG, "onAvailable: " )
        }

        override fun onLinkPropertiesChanged(
            network: Network,
            linkProperties: LinkProperties
        ) {
            super.onLinkPropertiesChanged(network, linkProperties)
            Log.w(TAG, "onLinkPropertiesChanged: ${linkProperties.linkAddresses}" )
            handler.sendMessage(Message.obtain(handler,0,linkProperties))
        }

        override fun onUnavailable() {
            super.onUnavailable()
            Log.w(TAG, "onUnavailable: " )
        }

        override fun onLost(network: Network) {
            super.onLost(network)
            handler.sendMessage(Message.obtain(handler,1))
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onStart() {
        super.onStart()
        registerWifiState()

    }

    override fun onStop() {
        super.onStop()
        unregisterWifiState()
    }


    private fun registerWifiState(){
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val request = NetworkRequest.Builder()
            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
            .build()
        connectivityManager.registerNetworkCallback(request, networkCallback)
    }

    private fun unregisterWifiState(){
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        connectivityManager.unregisterNetworkCallback(networkCallback)
    }

}

在onStart中注册了一个networkcallback回调,就可以在networkcallback中的onLinkPropertiesChanged中拿到IP地址并且传给id为ip的TextView,如果断开wifi的时候就会设置为无连接。

实现显示IP地址的小组件

目前为止我们已经成功在App内获取到了ip地址,是使用callback的办法,那能不能通过点击获取实时的网络ip呢,当然可以,但我们要使用小组件的方式来实现,就需要先写一个简单的小组件出来
先写一个小组件广播
WifiIpWidget.kt

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiManager
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.RemoteViews
import demo.tdsss.wifistate.R

/**
 * @author TDSSS
 * @datetime 2023/11/22 17:47
 */
class WifiIpWidget : AppWidgetProvider() {

    private val TAG = "wifi state widget"

    override fun onEnabled(context: Context?) {
        super.onEnabled(context)
        updateInfo(context)
        Log.w(TAG, "onEnabled: " )
    }

    override fun onUpdate(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetIds: IntArray?
            ) {
        super.onUpdate(context, appWidgetManager, appWidgetIds)
        Log.w(TAG, "onUpdate: " )
        updateInfo(context)
    }

    override fun onAppWidgetOptionsChanged(
        context: Context?,
        appWidgetManager: AppWidgetManager?,
        appWidgetId: Int,
        newOptions: Bundle?
            ) {
        super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
        Log.w(TAG, "onAppWidgetOptionsChanged: " )
        val intent = Intent(context,this.javaClass)
        intent.action = "touch"
        val remoteViews = RemoteViews(context?.packageName, R.layout.widget_layout).also {
            it.setOnClickPendingIntent(
                R.id.wifi_widget,
                PendingIntent.getBroadcast(
                    context,
                    0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                ))
        }
        appWidgetManager!!.partiallyUpdateAppWidget(appWidgetId, remoteViews)
    }

    override fun onDisabled(context: Context?) {
        super.onDisabled(context)
        Log.w(TAG, "onDisabled: " )
    }

    override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
        super.onDeleted(context, appWidgetIds)
        Log.w(TAG, "onDeleted: ", )
    }

    override fun onReceive(context: Context?, intent: Intent?) {
        super.onReceive(context, intent)
        //        Log.w(TAG, "onReceive: " )
        //        Log.w(TAG, "action: ${intent?.action}" )
        //        updateInfo(context)
        if(intent?.action == "touch"){
            Log.w(TAG, "onReceive: action == touch" )
            updateInfo(context)
        }
        if (intent?.action != null && intent.action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            Log.w(TAG, "onReceive: NETWORK_STATE_CHANGED_ACTION" )
            updateInfo(context)
        }
    }

    private fun updateInfo(context : Context?){
        val connectivityManager = context?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val networkInfo = connectivityManager.activeNetwork
        val capabilities = connectivityManager.getNetworkCapabilities(networkInfo)
        if(capabilities == null || !(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))){
            val appWidgetManager = AppWidgetManager.getInstance(context)
            val ids = appWidgetManager.getAppWidgetIds(ComponentName(context,this.javaClass))
            val remoteViews = RemoteViews(context.packageName, R.layout.widget_layout).also {
                it.setTextViewText(R.id.wifiAddress, "未连接wifi")
            }
            appWidgetManager.partiallyUpdateAppWidget(ids, remoteViews)
            return
        }
        val linkProperties = connectivityManager.getLinkProperties(networkInfo)
        val address = linkProperties?.linkAddresses
        Log.w(TAG, "onReceive address: $address" )
        val appWidgetManager = AppWidgetManager.getInstance(context)
        val ids = appWidgetManager.getAppWidgetIds(ComponentName(context,this.javaClass))
        val intent = Intent(context,this.javaClass)
        intent.action = "touch"
        val remoteViews = RemoteViews(context.packageName, R.layout.widget_layout).also {
            it.setTextViewText(R.id.wifiAddress, "${address?.get(1)}")
            it.setOnClickPendingIntent(
                R.id.wifi_widget,
                PendingIntent.getBroadcast(
                    context,
                    0,
                    intent,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                ))
        }
        appWidgetManager.partiallyUpdateAppWidget(ids, remoteViews)
    }
}

核心逻辑其实就在updateInfo()中,先通过connectivityManager获取当前的networkInfo,然后根据networkInfo获取NetworkCapabilities,判断网络连接类型是否为WiFi,如果不仅仅想获取WiFi的就不用判断类型
然后通过connectivityManager和networkInfo获取LinkProperties,再从LinkProperties的实例中获取linkAddresses就可以啦,这里的linkAddresses其实是一个List类型,里面可能会有多端IP地址,包含IPv6和IPv4的,看你需要什么就取什么。

小组件布局很简单,就两行文字
widget_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center"
  android:background="@color/white"
  android:id="@+id/wifi_widget"
  >
  <TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="点击获取Wi-Fi地址:" />

  <TextView
    android:id="@+id/wifiAddress"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="未连接" />

</LinearLayout>

别忘了在AndroidManifest.xml中注册小组件广播以及权限添加

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<receiver android:name=".widget.WifiIpWidget"
  android:exported="false"
  >
  <intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    <action android:name="android.net.wifi.STATE_CHANGE"/>
  </intent-filter>
  <meta-data android:name="android.appwidget.provider"
    android:resource="@xml/wifi_ip_widget_info" />
</receiver>

注:这里我们虽然静态注册了"android.net.wifi.STATE_CHANGE"的wifi变化广播监听,但其实在Android O(8.0)即API 26之后,静态广播就受到限制,如果想让小组件在onReceiver中实时监听网络信息需要修改target Sdk 为26以下(不包含26),详细信息可以查看文档↓
广播概览 | Android 开发者 | Android Developers

最后我们安装完App,把小组件添加到桌面上,点击就会实时获取当前WiFi的局域网IP地址啦
5.jpg
源码地址:https://github.com/TDSSSzero/AndroidWifiStateWidget

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
是的,从Android 9(API级别28)开始,`WifiManager.startScan()`已被标记为过时。取而代之的是`WifiManager.startScan()`方法的替代方法`WifiManager.getScanResults()`。 以下是一个更新后的示例代码: ```java public class WifiScanner extends AppCompatActivity { private WifiManager wifiManager; private List<ScanResult> scanResults; private StringBuilder stringBuilder = new StringBuilder(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wifi_scanner); wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); Button scanButton = findViewById(R.id.scanButton); scanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { scanWifi(); } }); TextView wifiListTextView = findViewById(R.id.wifiListTextView); wifiListTextView.setMovementMethod(new ScrollingMovementMethod()); } private void scanWifi() { stringBuilder = new StringBuilder(); if (!wifiManager.isWifiEnabled()) { wifiManager.setWifiEnabled(true); } wifiManager.startScan(); Toast.makeText(this, "Scanning WiFi ...", Toast.LENGTH_SHORT).show(); new Handler().postDelayed(new Runnable() { @Override public void run() { scanResults = wifiManager.getScanResults(); for (ScanResult scanResult : scanResults) { stringBuilder.append("SSID: ") .append(scanResult.SSID) .append(" , BSSID: ") .append(scanResult.BSSID) .append(" , RSSI: ") .append(scanResult.level) .append("\n\n"); } TextView wifiListTextView = findViewById(R.id.wifiListTextView); wifiListTextView.setText(stringBuilder.toString()); } }, 5000); // 5 seconds delay } } ``` 在此示例中,我们使用了`WifiManager.getScanResults()`方法来获取扫描结果。我们还使用了`Handler`来添加5秒的延迟,以便给WiFi扫描一些时间来完成。一旦扫描完成,我们遍历每个扫描结果,并将它们附加到`StringBuilder`中,最后将其显示在TextView中。 虽然`WifiManager.startScan()`仍然可以在Android 10及更低版本中使用,但我们建议使用`WifiManager.getScanResults()`,以确保代码在未来的Android版本中仍然可以正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TDSSS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值