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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络之运输层

一、概述 物理层、数据链路层以及网络层它们共同解决了将主机通过异构网络互联起来所面临的的问题&#xff0c;实现了主机到主机的通信 但实际上在计算机网络中进行通信的真正实体是位于通信两端主机中的进程 如何为运行在不同主机上的应用进程提供直接的通信服务时运输层的任务…

【深度学习】Transformer简介

近年来&#xff0c;Transformer模型在自然语言处理&#xff08;NLP&#xff09;领域中横扫千军&#xff0c;以BERT、GPT为代表的模型屡屡屠榜&#xff0c;目前已经成为了该领域的标准模型。同时&#xff0c;在计算机视觉等领域中&#xff0c;Transformer模型也逐渐得到了重视&a…

第十一章 docker swarm集群部署

文章目录 前言一、安装docker1.1 解压1.2 配置docker 存储目录和dns1.3 添加docker.service文件1.4 docker 启动验证 二、docker swarm 集群配置2.1 关闭selinux2.2 设置主机名称并加入/etc/hosts2.3 修改各个服务器名称&#xff08;uname -a 进行验证&#xff09;2.4 初始化sw…

【SpringBoot篇】Spring_Task定时任务框架

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

PTA 六度空间

“六度空间”理论又称作“六度分隔&#xff08;Six Degrees of Separation&#xff09;”理论。这个理论可以通俗地阐述为&#xff1a;“你和任何一个陌生人之间所间隔的人不会超过六个&#xff0c;也就是说&#xff0c;最多通过五个人你就能够认识任何一个陌生人。”如图1所示…

Springboot+vue的新冠病毒密接者跟踪系统(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的新冠病毒密接者跟踪系统(有报告)。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的新冠病毒密接者跟踪系统&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;v…

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

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

【数组栈】实现

目录 栈的概念及其结构 栈的实现 数组栈 链式栈 栈的常见接口实现 主函数Test.c 头文件&函数声明Stack.h 头文件 函数声明 函数实现Stack.c 初始化SLInit 扩容Createcapacity 压栈STPush 出栈STPop 栈顶元素STTop 判断栈是否为空STempty 栈内元素个数STSzi…

ABB机 器 人 操 作 培 训

目 录 1 培训手册介绍 ---------------------------------------------2 2 系统安全与环境保护 ---------------------------------------------3 3 机器人综述 ---------------------------------------------5 4 机器人示教 --------------------------------------------12…

普通平衡树

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

CSGO搬砖项目全面讲解 ,CSGO搬砖注意事项

Steam/CSGO游戏搬砖全套操作流程之如何选品&#xff08;第二课&#xff09; 一个游戏只要能搬&#xff0c;只要体量不够大&#xff0c;很快就会货币价格暴跌&#xff0c;直接凉凉。市面上的能稳定手动搬砖的游戏越来越少。所以对于兼职赚点外快的散人搬砖党来说&#xff0c;找一…

【Vue入门篇】基础篇—Vue指令,Vue生命周期

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;Vue概述&#x1f384;快速入门&#x1f33a;Vue指令⭐v-…

微信小程序登录获取不到头像和昵称解决办法

微信小程序登录获取不到头像和昵称主要原因是&#xff1a;小程序wx.getUserProfile接口被收回&#xff01; 大家可以按照文档操作↓ PS&#xff1a; 针对小程序wx.getUserProfile接口将被收回后做出的授权调整 小程序文档中提出的调整说明 对于此次变化&#xff0c;现将小程…

如何满足BMW EDI项目的PKT需求?

近期宝马BMW&#xff08;以下简称BMW&#xff09;在其部分供应商之间试点推进PKT项目&#xff0c;BMW为什么要启动 PKT 计划呢&#xff1f; 业务系统全面升级统一全球所有宝马工厂的流程 宝马内部的物流供货流程 近期BMW PKT需求主要针对其内部物流供货流程展开&#xff1a; …

Android : Spinner(列表选项框) + BaseAdapter -简单应用

​​容器与适配器&#xff1a;​​​​​ http://t.csdnimg.cn/ZfAJ7 示例图&#xff1a; 实体类 Demo.java package com.example.mygridviewadapter.entity;public class Demo {private String text;private int img;public Demo(String text, int img) {this.text…

QQ怎么备份聊天记录?3个方法教你快速备份!

QQ聊天记录作为用户和亲人、好友以及同事之间沟通的凭证&#xff0c;可以帮助我们回忆起过去的交流内容。如果我们不小心误删了QQ聊天记录或者更换了新手机&#xff0c;那么这时候就需要备份聊天记录。qq怎么备份聊天记录呢&#xff1f;本文将介绍3个简单方法&#xff0c;帮助您…

Oracle-客户端连接报错ORA-12545问题

问题背景: 用户在客户端服务器通过sqlplus通过scan ip登陆访问数据库时&#xff0c;偶尔会出现连接报错ORA-12545: Connect failed because target host or object does not exist的情况。 问题分析&#xff1a; 首先&#xff0c;登陆到连接有问题的客户端数据库上&#xff0c;…

va-Q-tec实现温度敏感产品运输过程质量控制温控无忧

摘要&#xff1a;温度敏感产品运输对供应链全流程的温度质量要求较高&#xff0c;往往需要借助特殊的温湿度监测技术产品。va-Q-tec与虹科Comet合作&#xff0c;采用虹科Comet的U系列温度记录仪&#xff0c;为集装箱运输过程提供完整的温控包装解决方案。 一、客户背景 va-Q-…

算法通关村第十二关-白银挑战字符串经典题目

大家好我是苏麟 , 今天带来字符串相关的题目 . 大纲 反转问题字符串反转K个一组反转仅仅反转字母反转字符串中的单词 反转问题 字符串反转 描述 : 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s的形式给出。 题目 : LeetCode 344. 反转…

【PPspliT】ppt转pdf-保留过渡动画

网址 http://www.maxonthenet.altervista.org/ppsplit.php 下载安装 使用 再次打开ppt&#xff0c;就能在上方的选项栏里头看到了&#xff1a;