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

news2024/11/18 17:21:03

前言

最近在使用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1241862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提升性能测试效率:JMeter中的用户自定义变量!

前言 在测试过程中&#xff0c;我们经常会碰到测试服务地址有改动的情况&#xff0c;为了方便&#xff0c;我们会把访问地址参数化&#xff0c;当访问地址变化了&#xff0c;我们只需要把参数对应的值改动一下就可以了。 一&#xff1a;添加配置元件-用户定义的变量&#xff…

P8599 [蓝桥杯 2013 省 B] 带分数(dfs+全排列+断点判断)

思路&#xff1a;1.深度枚举所有排列情况 2.设置为每个排列设置两个断点&#xff0c;分为三部分&#xff1a;a,b,c 3.转换为乘法判断条件&#xff0c;满足加一 代码如下&#xff1a;&#xff08;可用next_permutation全排列函数代替dfs&#xff09; #include<iostream>…

精通Nginx(18)-FastCGI/SCGI/uWSGI支持

最初用浏览器浏览的网页只能是静态html页面。随着社会发展,动态获取数据、操作数据需要变得日益强烈,CGI应运而生。CGI(Common Gateway Interface)公共网关接口,是外部扩展应用程序与静态Web服务器交互的一个标准接口。它可以使外部程序处理浏览器送来的表单数据并对此作出…

TypeScript 学习笔记 第三部分 贪吃蛇游戏

尚硅谷TypeScript教程&#xff08;李立超老师TS新课&#xff09; 1. 创建开发环境 创建工程&#xff0c;使用学习笔记的第二部分安装css部分 npm i -D less less-loader css-loader style-loader对css部分处理&#xff0c;能够运行在低版本浏览器 npm i -D postcss postcss…

数据结构与算法编程题14

设计一个算法&#xff0c;通过一趟遍历在单链表中确定值最大的结点。 #include <iostream> using namespace std;typedef int Elemtype; #define ERROR 0; #define OK 1;typedef struct LNode {Elemtype data; //结点保存的数据struct LNode* next; //结构体指针…

每日一题 1410. HTML 实体解析器(中等,模拟)

模拟&#xff0c;没什么好说的 class Solution:def entityParser(self, text: str) -> str:entityMap {&quot;: ",&apos;: "",>: >,<: <,&frasl;: /,&amp;: &,}i 0n len(text)res []while i < n:isEntity Falseif …

【从入门到起飞】JavaSE—多线程(3)(生命周期,线程安全问题,同步方法)

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;生命周期&#x1f384;线程的安全问题&#…

opencv-Otsu‘s 二值化分割

Otsu’s 二值化是一种自适应的图像阈值选择方法&#xff0c;它通过最小化类内方差和最大化类间方差来确定一个最佳的阈值。该方法由日本学者大津展之&#xff08;Otsu&#xff09;于1979年提出&#xff0c;广泛用于图像分割。 该算法的核心在于前景与背景图像的类间方差最大 在…

PC8223(CC/CV控制)高耐压输入5V/3.4A同步降压电路内建补偿带恒流恒压输出

概述 PC8233&#xff08;替代CX8853&#xff09;是一款同步降压调节器,输出电流高达3.4A,操作范围从8V到32V的宽电源电压。内部补偿要求最低数量现成的标准外部组件。PC8233在CC&#xff08;恒定输出电流&#xff09;模式或CV&#xff08;恒定输出电压&#xff09;模式&#x…

HarmonyOS元服务开发实战—端云一体化开发

还记得我第一次接触arkui还是在22年的9月份&#xff0c;当时arkui还在一个比较初试的阶段。时隔一年再见方舟框架&#xff0c;它已经发生了令人瞩目的变化&#xff0c;不得不说华为方舟框架在更新迭代的速度已经遥遥领先。新的功能和性能优化让这个框架更加强大和灵活&#xff…

【实用】PPT没几页内存很大怎么解决

PPT页数很少但导出内存很大解决方法 1.打开ppt点击左上角 “文件”—“选项” 2.对话框选择 “常规与保存” &#xff08;1&#xff09;如果想要文件特别小时可 取消勾选 “将字体嵌入文件” &#xff08;2&#xff09;文件大小适中 可选择第一个选项 “仅最入文档中所用的字…

【SpringBoot篇】Spring_Task定时任务框架

文章目录 &#x1f339;概述&#x1f33a;应用场景&#x1f384;cron表达式&#x1f6f8;入门案例&#x1f38d;实际应用 &#x1f339;概述 Spring Task 是 Spring 框架提供的一种任务调度和异步处理的解决方案。可以按照约定的时间自动执行某个代码逻辑它可以帮助开发者在 S…

腾讯云 小程序 SDK对象存储 COS使用记录,原生小程序写法。

最近做了一个项目&#xff0c;需求是上传文档&#xff0c;文档类型多种&#xff0c;图片&#xff0c;视频&#xff0c;文件&#xff0c;doc,xls,zip,txt 等等,而且文档类型可能是大文件&#xff0c;可能得上百兆&#xff0c;甚至超过1G。 腾讯云文档地址&#xff1a;https://c…

Altium Designer学习笔记11

画一个LED的封装&#xff1a; 使用这个SMD5050的封装。 我们先看下这个芯片的功能说明&#xff1a; 5050贴片式发光二极管&#xff1a; XL-5050 是单线传输的三通道LED驱动控制芯片&#xff0c;采用的是单极性归零码协议。 数据再生模块的功能&#xff0c;自动将级联输出的数…

BootStrap【表格二、基础表单、被支持的控件、表单状态】(二)-全面详解(学习总结---从入门到深化)

目录 表格二 表单_基础表单 表单_被支持的控件 表单_表单状态 表格二 紧缩表格 通过添加 .table-condensed 类可以让表格更加紧凑&#xff0c;单元格中的内补&#xff08;padding&#xff09;均会减半 <table class"table table-condensed table-bordered"…

信创系列之大数据,分布式数据库产业链跟踪梳理笔记…

并购优塾 投行界的大叔&#xff0c;大叔界的投行 【产业链地图&#xff0c;版权、内容与免责声明】1&#xff09;版权&#xff1a;版权所有&#xff0c;违者必究&#xff0c;未经许可不得翻版、摘编、拷贝、复制、传播。2&#xff09;尊重原创&#xff1a;如有引用未标注来源…

数据结构与算法编程题15

设计一个算法&#xff0c;通过遍历一趟&#xff0c;将链表中所有结点的链接方向逆转&#xff0c;仍利用原表的存储空间。 #include <iostream> using namespace std;typedef int Elemtype; #define ERROR 0; #define OK 1;typedef struct LNode {Elemtype data; …

Cypress-浏览器操作篇

Cypress-浏览器操作篇 页面的前进与后退 后退 cy.go(back); cy.go(-1);前进 cy.go(forward); cy.go(1);页面刷新 cy.reload() cy.reload(forceReload) cy.reload(options) cy.reload(forceReload, options)**options&#xff1a;**只有 timeout 和 log forceReload 是否…

普通平衡树

题意&#xff1a;略&#xff0c;题中较清晰。 用二叉查找树来存储数据&#xff0c;为了增加效率&#xff0c;尽量使左子树和右子树的深度差不超过一&#xff0c;这样可以时间控制在logn&#xff0c;效率比较高。 右旋和左旋&#xff0c;目的是为了维护二叉树的操作&#xff0…

NX二次开发UF_CSYS_ask_matrix_of_object 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CSYS_ask_matrix_of_object Defined in: uf_csys.h int UF_CSYS_ask_matrix_of_object(tag_t object_id, tag_t * matrix_id ) overview 概述 Gets the matrix identifier atta…