获取Android设备序列号的可靠方法:兼容不同设备和Android版本

获取android设备序列号的可靠方法:兼容不同设备和android版本

本文旨在提供一个健壮且兼容性强的方案,用于在Android应用中获取设备序列号。由于不同设备制造商和Android版本在序列号的存储方式上存在差异,直接依赖单一方法可能导致部分设备无法获取。本文将介绍一种通过尝试多种系统属性来获取序列号的方法,并提供相应的代码示例和注意事项,确保应用能够尽可能地获取到设备序列号。

序列号获取的挑战

在Android开发中,获取设备序列号看似简单,但实际情况却复杂得多。不同厂商的设备可能将序列号存储在不同的系统属性中,而 Build.SERIAL 在某些情况下可能返回 “unknown” 或需要特定的权限才能访问。因此,一个可靠的解决方案需要考虑这些差异,并尝试多种方法来获取序列号。

解决方案:尝试多种系统属性

以下代码展示了一种尝试多种系统属性来获取设备序列号的方法。该方法通过反射访问 android.os.SystemProperties 类,并依次尝试不同的属性名称,直到成功获取序列号或所有属性都尝试完毕。

import android.Manifestimport android.content.Contextimport android.content.pm.PackageManagerimport android.os.Buildimport androidx.core.app.ActivityCompatimport androidx.core.content.ContextCompatimport android.widget.Toastfun getDeviceSerial(applicationContext: Context): String {    var serialNumber: String = ""    try {        val c = Class.forName("android.os.SystemProperties")        val get = c.getMethod("get", String::class.java)        serialNumber = get.invoke(c, "gsm.sn1") as String        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ril.serialnumber") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.serialno") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "sys.serialnumber") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.boot.serialno") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.ril.oem.sno") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ril.cdma.esn") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "vendor.gsm.serial") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.boot.un") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.boot.uniqueno") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.ril.oem.wifimac") as String        }        when (serialNumber) {            "" -> serialNumber = get.invoke(c, "ro.ril.oem.btmac") as String        }        @Suppress("DEPRECATION")        when (serialNumber) {            "" -> serialNumber = Build.SERIAL        }        when (serialNumber) {            "" -> serialNumber = ""        }    } catch (e: Exception) {        e.printStackTrace()        Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()        serialNumber = ""    }    if (serialNumber == "unknown") {        try {            val c = Class.forName("android.os.SystemProperties")            val get = c.getMethod(                "get",                String::class.java,                String::class.java            )            serialNumber = get.invoke(c, "ril.serialnumber", "unknown") as String        } catch (ignored: Exception) {            Toast.makeText(                applicationContext,                "ignored ${ignored.message}",                Toast.LENGTH_LONG            )                .show()        }    }    try {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && serialNumber == "unknown") {            if (ActivityCompat.checkSelfPermission(                    applicationContext,                    Manifest.permission.READ_PHONE_STATE                ) == PackageManager.PERMISSION_GRANTED            ) {                serialNumber = Build.getSerial()            }        }    } catch (e: Exception) {        serialNumber = ""    }    return serialNumber}fun openTelePhony(context: Context?) {    context?.let {        var a = ""        try {            //check permission            if (ContextCompat.checkSelfPermission(                    context,                    Manifest.permission.CALL_PHONE                ) == PackageManager.PERMISSION_GRANTED            ) {                a = getDeviceSerial(context)            } else {                a = Build.SERIAL            }            System.out.print(a)        } catch (e: Exception) {            System.out.print()        }    }}

代码解释:

权限检查: 在Android 8.0 (API level 26) 及以上,Build.getSerial() 需要 READ_PHONE_STATE 权限。 代码中包含权限检查和请求的逻辑(虽然在提供的openTelePhony函数中,权限不足时直接使用Build.SERIAL可能返回”unknown”,应考虑处理这种情况)。反射机制: 使用反射访问 android.os.SystemProperties 类,避免直接依赖该类的API,提高代码的兼容性。多种属性尝试: 依次尝试多个常见的系统属性,例如 gsm.sn1, ril.serialnumber, ro.serialno 等。错误处理: 使用 try-catch 块捕获可能出现的异常,例如 ClassNotFoundException 或 NoSuchMethodException,保证程序的健壮性。

注意事项

权限声明: 在 AndroidManifest.xml 文件中声明 READ_PHONE_STATE 权限。


权限请求: 在运行时请求 READ_PHONE_STATE 权限。请参考Android官方文档了解如何在运行时请求权限。

“unknown” 值处理: 即使使用了多种方法,仍然可能无法获取到序列号,或者获取到 “unknown” 值。 在应用中需要对这种情况进行妥善处理,例如使用其他唯一标识符作为备选方案。

设备兼容性: 不同设备的系统属性可能存在差异。 建议在多种设备上进行测试,并根据实际情况调整代码中的属性列表。

Android 10 (API level 29) 及更高版本: 从 Android 10 开始,访问设备序列号受到更多限制,并且需要满足特定条件才能获取。请务必仔细阅读 Android 官方文档,了解相关限制和最佳实践。

总结

获取Android设备序列号是一个具有挑战性的任务,但通过尝试多种系统属性、进行适当的错误处理和权限管理,可以大大提高获取序列号的成功率。请务必根据实际情况进行测试和调整,并遵守Android平台的安全和隐私政策。

以上就是获取Android设备序列号的可靠方法:兼容不同设备和Android版本的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/79307.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月15日 08:24:08
下一篇 2025年11月15日 09:09:53

相关推荐

  • PHP二维数组日期数据分组求和:如何高效合并和计算?

    PHP二维数组日期数据的高效合并与求和 本文介绍一种高效的方法,用于处理包含日期数据和对应数值的PHP二维数组。目标是将日期数据按指定数量分组,并计算每组数值的总和。 问题描述: 我们拥有一个PHP二维数组,包含categories(日期字符串数组)和data(对应数值数组)两个键值对。 需要将ca…

    2025年12月12日
    000
  • Dockerfile中PHP Event扩展安装失败:如何解决?

    本文分析并解决了一个在Dockerfile中构建PHP镜像时,安装event扩展失败的问题。 用户原先的Dockerfile在安装其他扩展时成功,唯独event扩展安装失败。 问题源于Dockerfile中冗余且可能冲突的docker-php-ext-configure event命令。 用户使用了…

    2025年12月12日
    000
  • Laravel队列延迟分发失效:如何排查并解决延迟任务执行失败及超时问题?

    Laravel 队列延迟分发失效:深度排查与解决方案 本文针对 Laravel 队列延迟分发失效问题进行深入分析,并提供相应的排查和解决方法。 在 Laravel 8.78.1 版本,使用 Redis 驱动程序的队列系统中,dispatch()->delay() 方法用于实现订单状态延迟更新时…

    2025年12月12日
    000
  • Laravel队列延迟分发失效:如何排查并解决60秒延迟任务执行失败的问题?

    Laravel 8.78.1 延迟队列失效及超时错误解决方案 本文分析并解决在Laravel 8.78.1环境下,延迟队列任务执行失败的问题。 问题表现为:开发者试图使用队列机制在60秒后更新订单状态,但延迟分发功能失效,并出现AppJobsSettlementOrder has been atte…

    2025年12月12日
    000
  • Laravel队列延迟分发失效:任务超时导致延迟任务失败怎么办?

    排查 Laravel 队列延迟分发失效问题 本文分析并解答 Laravel 队列延迟分发失效的常见原因。 问题场景:在 Laravel 8.78.1 (LNMP 环境:CentOS 7.6,PHP 7.4.21,MySQL 5.7.34,Redis 6.2.4) 使用 Redis 驱动进行队列延迟分…

    2025年12月12日
    000
  • Laravel延迟队列任务无法按时执行是什么原因?

    排查Laravel延迟队列任务执行失败 本文分析并解决Laravel 8.78.1版本下Redis队列延迟任务失效的问题,该问题表现为任务未按预期执行,并出现“AppJobsSettlementOrder has been attempted too many times or run too lo…

    2025年12月12日
    000
  • Windows 11更新失败,错误代码0xc1900204该怎么解决?

    windows 11更新失败,错误代码0xc1900204如何解决? 升级Windows 11系统时,错误代码0xc1900204是常见的难题。 即使尝试了诸如停止Windows Update服务、清理SoftwareDistribution文件夹中的下载文件并重启等常规方法,问题依然可能存在。 即…

    2025年12月12日
    000
  • 网站系统消息的已读未读状态:如何高效地追踪用户阅读情况?

    网站系统消息的已读未读状态实现方案探讨 许多网站都包含系统消息功能,方便向用户传递重要信息。那么,如何高效地实现消息的已读未读状态呢?一个常见的问题是:系统该如何跟踪每个用户对每条系统消息的阅读状态? 用户提出了一种方案,即在数据库中建立一张表,记录每个用户对每条消息的阅读状态。例如,表中包含“用户…

    好文分享 2025年12月12日
    000
  • Windows 11更新失败,错误代码0xc1900204该如何解决?

    Windows 11系统更新遇到0xc1900204错误?别慌!本文将为您分析此错误原因及解决方法。 一位用户在下载完成后,安装Windows 11更新时遇到0xc1900204错误,即使清理了Windows Update缓存(删除SoftwareDistribution/Download文件夹内容…

    2025年12月12日
    000
  • PHP避免数据库脏数据:如何安全执行多条SQL语句?

    PHP数据库操作:防止脏数据产生的有效策略 在PHP应用中,常常需要执行多条SQL语句来完成单次数据插入或更新操作。然而,如果其中一条语句执行失败,可能会导致数据库数据不一致,产生“脏数据”。本文将介绍几种有效方法,确保数据库操作的完整性和一致性,避免脏数据的产生。 推荐方法:数据库事务 数据库事务…

    2025年12月12日
    000
  • Nginx配置HTTPS和跨域访问后端API时遇到问题怎么办?

    解决Nginx HTTPS配置下跨域访问后端API的问题 部署Vue前端项目到Nginx并启用HTTPS后,常常遇到跨域访问后端API接口失败的问题。本文提供Nginx配置文件的正确配置方法,解决此类问题。 在现有Nginx配置文件中,添加以下代码段,将请求代理到后端API接口: location …

    2025年12月12日
    000
  • ThinkPHP中如何安全地获取指定ID的Session数据?

    ThinkPHP安全获取指定ID的Session数据方法详解 ThinkPHP的session()方法不支持直接使用指定ID获取Session数据,这是因为直接修改Session ID违反了Session机制的规范,存在安全风险。 尝试在会话已启动后更改Session ID会导致错误。 为了实现类似…

    2025年12月12日
    000
  • ThinkPHP5缓存写入失败:Windows服务器下“Permission denied”错误如何解决?

    ThinkPHP5框架Windows服务器缓存写入失败的有效解决方法 在使用ThinkPHP5框架的Windows服务器环境中,常常会遇到缓存写入失败,并提示“failed to open stream: Permission denied”错误。这并非简单的权限问题,而是由多种因素共同作用导致的。…

    2025年12月12日
    000
  • PHP函数代码风格的最新动态

    PHP 函数代码风格的最新动态 在当今快速发展的 PHP 生态系统中,函数代码风格至关重要,它不仅能提高可读性,还能增强可维护性。本文将探讨 PHP 中函数代码风格的最新趋势,并通过实际示例说明这些趋势。 无空格括号和换行符 最近,无空格括号和换行符的风格越来越流行,这可以增强函数定义的可读性。 立…

    2025年12月12日
    000
  • 违反php函数命名规范的后果

    违反 php 函数命名规范会降低可读性、增加维护难度、提高错误风险,并且可能与自动化工具不兼容。遵守规范可使用小写字母开头、驼峰式命名法和使用动词作为名称,以提高代码质量。 违反 PHP 函数命名规范的后果 PHP 函数命名规范对于组织和可读性至关重要。违反这些规范会导致不良的编码实践,甚至可能导致…

    2025年12月12日
    000
  • PHP 函数与 Java 函数比较

    php 和 java 函数比较:语法:php 函数使用 function 声明,java 函数使用 public/protected/private 声明;返回类型:php 函数可选,java 函数必选;命名:php 函数可以字母、下划线或 $ 开头,java 函数只能以字母或下划线开头;参数传递:…

    2025年12月12日
    000
  • 使用 PHP 函数案例分析指南

    使用 php 函数可以简化编程任务,包括:字符串处理:使用 str_replace() 替换字符串中的空格。数组操作:使用 array_sum() 将数组元素求和。数学计算:使用 pow() 计算平方,使用 – 运算符减去两个平方差。完整的函数列表及其用法可在官方文档中找到。 PHP 函…

    2025年12月12日
    000
  • php和java、python等语言的函数对比

    php、java 和 python 都支持函数,用于封装特定任务。php 函数以 function 关键字开头,java 函数(方法)定义在类中,python 函数以 def 关键字开头。三个语言的实战用例类似,以计算两个数之和为例,php 使用独立函数,java 定义在类中,python 使用缩进…

    2025年12月12日
    000
  • PHP 函数名称中使用大写字母的规范

    php 函数名称使用大写字母的规范如下:函数名称以大写字母开头。如果函数名称包含多个单词,单词之间的首字母也应大写。私有函数或方法名称以单个下划线开头,后跟大写字母。当函数名称包含缩写时,才使用全大写字母。遵守这些规范提高了代码的可读性、避免名称冲突,并提供了代码的一致性。 PHP 函数名称中使用大…

    2025年12月12日
    000
  • PHP框架社区活跃程度如何比较?

    php框架社区活跃度比较表明,laravel拥有庞大的活跃社区,codeigniter活跃度稍低,symfony专注于企业级支持,zend framework社区规模较小。衡量社区活跃度的指标包括问题解决响应时间、文档质量、代码示例可用性、版本更新频率和社交媒体参与。 PHP 框架社区活跃度比较 P…

    2025年12月12日
    000

发表回复

登录后才能评论
关注微信