Unity 之 Android 【获取设备的序列号 (Serial Number)/Android_ID】功能的简单封装

Unity 之 Android 【获取设备的序列号 (Serial Number)/Android_ID】功能的简单封装

目录

Unity 之 Android 【获取设备的序列号 (Serial Number)/Android_ID】功能的简单封装

一、简单介绍

二、获取设备的序列号 (Serial Number) 实现原理

1、Android

2、 Unity

三、注意实现

四、案例实现简单步骤

五、关键代码


一、简单介绍

Unity 是一个功能强大的跨平台游戏引擎,广泛用于开发视频游戏和其他实时3D互动内容,如模拟器和虚拟现实应用。

游戏引擎:

  •     Unity:Unity Technologies 开发的跨平台游戏引擎,支持2D和3D图形、物理引擎、音频、视频、网络和多平台发布。
  •     跨平台支持:Unity 支持在多个平台上发布,包括 Windows、macOS、Linux、iOS、Android、WebGL、PlayStation、Xbox、Switch 等。

开发环境:

  •     Unity Editor:用于创建和管理 Unity 项目的集成开发环境(IDE)。开发者可以在其中创建场景、设计关卡、编写代码和调试游戏。
  •     场景(Scene):Unity 中的基本构建块,一个场景可以被视为一个关卡或一个游戏中的独立部分。

编程语言:

  •     C#:主要编程语言。Unity 使用 C# 脚本来控制游戏对象和实现游戏逻辑。
  •     UnityScript(已弃用):曾经支持的 JavaScript 变种,但已经被弃用。

Unity 进阶开发涉及更复杂的技术和更深入的知识,以创建高性能、复杂和专业的游戏和应用程序。以下是一些 Unity 进阶开发的关键领域和技术:

设计模式:

  •     学习和应用常见的设计模式(如单例模式、工厂模式、观察者模式)以便更好地组织和管理代码。

异步编程:

  •     使用 C# 的 async 和 await 关键字进行异步编程,以提高应用的响应速度和性能。

依赖注入:

  •     使用依赖注入(如 Zenject)来管理对象的依赖关系,减少耦合,提高代码的可测试性和可维护性。

二、获取设备的序列号 (Serial Number) 实现原理

1、Android

在 Android 10 及以上版本,由于隐私和安全原因,获取设备的序列号 (SN) 变得更加受限。

在 Android 10 及以上版本,可以使用 Build.getSerial() 方法来获取设备的序列号。不过,这需要获取 READ_PRIVILEGED_PHONE_STATE 权限,该权限仅限于系统应用。因此,对于普通应用,可以使用 Build.SERIAL 作为替代,但在 Android 10 上,这个常量已经被弃用并会返回一个占位符值。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {String serial = Build.getSerial();
} else {String serial = Build.SERIAL;
}

需要注意的是,在 Android 9(API 28)及以下版本,Build.SERIAL 可以直接使用。在 Android 10 及以上版本,需要系统权限。

2、 Unity

在 Unity 中开发 Android 应用时,获取设备的序列号(SN)也受到 Android 10 及以上版本隐私和安全策略的影响。以下是如何在 Unity 中实现这些功能的方法:

对于 Android 10 及以上版本,获取设备序列号需要使用 Build.getSerial() 方法,并且需要特定的权限。由于 Unity 使用 C# 代码,你需要通过调用 Java 方法来实现这一点。

1)首先,需要在 AndroidManifest.xml 文件中声明权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />

2)然后,使用 Unity 的 AndroidJavaObject 类来调用 Java 代码:

using UnityEngine;public class DeviceInfo : MonoBehaviour
{public string GetSerialNumber(){string serialNumber = "Unknown";if (Application.platform == RuntimePlatform.Android){try{using (AndroidJavaClass buildClass = new AndroidJavaClass("android.os.Build")){if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){using (AndroidJavaObject buildObject = buildClass.CallStatic<AndroidJavaObject>("getSerial")){serialNumber = buildObject.Call<string>("toString");}}else{serialNumber = buildClass.GetStatic<string>("SERIAL");}}}catch (System.Exception e){Debug.LogError("Error getting serial number: " + e.Message);}}return serialNumber;}
}

三、注意实现

  1. 权限管理:确保在运行时请求必要的权限,特别是在 Android 6.0(API 23)及以上版本中,动态权限请求是必需的。
  2. 兼容性检查:由于不同 Android 版本的行为可能不同,代码中需要进行版本检查。
  3. 隐私合规:获取设备的敏感信息时,请确保应用符合相关的隐私政策和法律法规,通知用户并获得必要的同意。

通过上述步骤,你应该能够在 Unity 中成功获取 Android 10 及以上版本设备的序列号。

四、案例实现简单步骤

1、创建 Unity 工程

2、新建脚本 DeviceInfo ,编写代码获取设备的序列号

3、由于这个可能需要权限申请,编写代码申请权限

4、实现申请电话权限,获取设备序列号(TestDeviceInfo.cs)

5、把脚本 TestDeviceInfo.cs 挂载到场景中

6、在 Player Settings 中的 Build 中勾选 Custom Main Manifest ,添加相关 Phone 权限申请

7、打包运行,可能报如下错误

Exception getting serial number: java.lang.SecurityException: getSerial: The uid 10170 does not meet the requirements to access device identifiers.

错误表明尝试获取设备序列号时遇到了权限问题。在 Android 10(API level 29)及以上版本中,获取设备的序列号需要特殊权限,而这些权限通常不适用于普通应用程序。使用 Settings.Secure.ANDROID_ID 是一种更合适的替代方案,因为它不需要这些特殊权限。

8、下面是如何正确使用 Settings.Secure.ANDROID_ID 来获取设备的 Android ID:

    /// <summary>/// 获取设备的 Android ID/// </summary>/// <returns></returns>public static string GetAndroidId(){string deviceId = string.Empty;#if UNITY_ANDROID && !UNITY_EDITORtry{using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")){AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");using (AndroidJavaObject contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver")){using (AndroidJavaClass secure = new AndroidJavaClass("android.provider.Settings$Secure")){deviceId = secure.CallStatic<string>("getString", contentResolver, "android_id");}}}}catch (AndroidJavaException e){Debug.LogError("Exception getting Android ID: " + e.Message);}
#endifreturn deviceId;}

9、打包运行,能获取到 设备的 Android ID

10、获取设备的 Android ID的 注意事项

  • 唯一性

    • ANDROID_ID 在设备重置时可能会更改,因此不能作为硬件唯一标识符使用,但对于大多数应用场景,它足够可靠。
  • 权限

    • 由于不涉及敏感权限,你不需要在 AndroidManifest.xml 中添加任何额外权限。

五、关键代码

1、DeviceInfo


using UnityEngine;public class DeviceInfo 
{/// <summary>/// 获取设备序列号/// 需要系统权限/// </summary>public static string GetSerialNumber(){string serialNumber = string.Empty;#if UNITY_ANDROID && !UNITY_EDITORtry{using (AndroidJavaClass buildClass = new AndroidJavaClass("android.os.Build")){if (GetSDKInt() >= 26) // Build.VERSION_CODES.O == 26{serialNumber = buildClass.CallStatic<string>("getSerial");}else{serialNumber = buildClass.GetStatic<string>("SERIAL");}}}catch (AndroidJavaException e){Debug.LogError("Exception getting serial number: " + e.Message);}
#endifreturn serialNumber;}/// <summary>/// 获取版本/// </summary>/// <returns></returns>private static int GetSDKInt(){int sdkInt = 0;#if UNITY_ANDROID && !UNITY_EDITORusing (AndroidJavaClass versionClass = new AndroidJavaClass("android.os.Build$VERSION")){sdkInt = versionClass.GetStatic<int>("SDK_INT");}
#endifreturn sdkInt;}/// <summary>/// 获取设备的 Android ID/// </summary>/// <returns></returns>public static string GetAndroidId(){string deviceId = string.Empty;#if UNITY_ANDROID && !UNITY_EDITORtry{using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")){AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");using (AndroidJavaObject contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver")){using (AndroidJavaClass secure = new AndroidJavaClass("android.provider.Settings$Secure")){deviceId = secure.CallStatic<string>("getString", contentResolver, "android_id");}}}}catch (AndroidJavaException e){Debug.LogError("Exception getting Android ID: " + e.Message);}
#endifreturn deviceId;}
}

2、PermissionWrapper


using UnityEngine;
using UnityEngine.Android;public class PermissionWrapper : MonoSingleton<PermissionWrapper>
{/// <summary>/// 请求权限/// </summary>/// <param name="permission">权限名称</param>/// <param name="callback">权限回调:true 权限获取成功回调,false 权限获取失败回调</param>public void RequestPermission(string permission, System.Action<string, bool> callback){if (Permission.HasUserAuthorizedPermission(permission)){callback?.Invoke(permission, true);}else{StartCoroutine(RequestAndCheckPermission(permission, callback));}}/// <summary>/// 协程请求权限/// </summary>/// <param name="permission">权限名称</param>/// <param name="callback">权限回调:true 权限获取成功回调,false 权限获取失败回调</param>/// <returns></returns>private System.Collections.IEnumerator RequestAndCheckPermission(string permission, System.Action<string, bool> callback){Permission.RequestUserPermission(permission);yield return new WaitForSeconds(1.0f);bool granted = Permission.HasUserAuthorizedPermission(permission);callback?.Invoke(permission, granted);}
}

3、TestDeviceInfo


using UnityEngine;public class TestDeviceInfo : MonoBehaviour
{/// <summary>/// TAG /// </summary>const string TAG = "[TestDeviceInfo] ";// Start is called before the first frame updatevoid Start(){GetSerialNumber();}private void GetSerialNumber(){string permission = "android.permission.READ_PHONE_STATE";string sn = string.Empty;PermissionWrapper.Instance.RequestPermission(permission, (permission, isGranted) => {if (isGranted){//sn = DeviceInfo.GetSerialNumber();sn = DeviceInfo.GetAndroidId();}else{sn = "unknown";}Debug.Log(TAG + "GetAndroidId() = " + sn);});}
}

4、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"package="com.unity3d.player"xmlns:tools="http://schemas.android.com/tools"><!-- 获取 sn 的权限 Start--><uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /><!-- 获取 sn 的权限 End--><application><activity android:name="com.unity3d.player.UnityPlayerActivity"android:theme="@style/UnityThemeSelector"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-data android:name="unityplayer.UnityActivity" android:value="true" /></activity></application>
</manifest>

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

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

相关文章

gem5模拟器入门(一)——环境配置

什么是gem5&#xff1f; gem5是一个模块化的离散事件驱动的计算机系统模拟器平台。这意味着&#xff1a; GEM5 的组件可以轻松重新排列、参数化、扩展或更换&#xff0c;以满足您的需求。它将时间的流逝模拟为一系列离散事件。它的预期用途是以各种方式模拟一个或多个计算机系…

【职业教育培训机构小程序】教培机构“招生+教学”有效解决方案

教培机构“招生教学”有效解决方案在数字化转型的浪潮中&#xff0c;职业教育培训机构面临着提升教学效率、拓宽招生渠道、增强学员互动等多重挑战。小程序作为一种新兴的移动应用平台&#xff0c;为解决这些痛点提供了有效途径。 一、职业教育培训机构小程序的核心功能 &…

Laravel 图片添加水印

和这个配合使用 Laravel ThinkPhP 海报生成_laravel 制作海报-CSDN博客 代码 //水印 $x_length $imageInfo[0]; $y_length $imageInfo[1];$color imagecolorallocatealpha($posterImage, 255, 255, 255, 70); // 增加透明度参数alpha$font_size 40; //字体大小 $angle …

HTML静态网页成品作业(HTML+CSS)——家乡沅陵介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

条款9:利用destructors避免泄露资源

对指针说拜拜。承认吧&#xff0c;你从未真正喜欢过它&#xff0c;对不&#xff1f; 好&#xff0c;你不需要对所有指针说拜拜&#xff0c;但是你真的得对那些用来操控局部性资源(local resources&#xff09;的指针说莎唷娜拉了。 举个例子&#xff0c;你正在为“小动物收养…

godot4.2 + GDextension c++在 vs code 中断点调试配置

游戏开发中如果做不到自己编写的代码做断点调试&#xff0c;无不是瞎子摸象&#xff0c;特别是C这么底层的语言。这2天开始在VS studio中折腾&#xff0c;一直折腾不出结果&#xff0c;几次想要放弃GODOT。最终今天在VS code中搞定了这断点调试C代码。 在上一篇文章我已经做好了…

全网爆火Remini 粘土滤镜风格,我用ComfyUI一键生成了(保姆级教程)!

一、火爆全网的Remini&#xff01; Remini真的火爆了&#xff01;最近大家的朋友应该都被粘土滤镜刷屏了。 小红书上粘土滤镜、粘土特效的帖子动不动就是几百万浏览量&#xff0c;几千赞。 在有些电商平台上还有人接单&#xff0c;帮忙定制remini粘土风格的照片&#xff01; …

vue+three.js实现3d系统的搭建

1.首先node.js是12.22版本的&#xff0c;安装three.js可以参考这篇文章 直接用Threejs入门-安装教程_安装three.js-CSDN博客 直接在终端安装three.js即可 npm install --save three 在相同目录下安装vite构建工具 npm install --save-dev vite 在项目里面看package.json中…

【安装笔记-20240528-Linux-在 Vultr 云服务器上安装 OpenWRT】

安装笔记-系列文章目录 安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 文章目录 安装笔记-系列文章目录安装笔记-20240528-Linux-在 Vultr 云服务器上安装测试 OpenWRT 前言一、软件介绍名称&#xff1a;OpenWRT主页官方介绍 二、安装步骤测试版本&#xff1a…

案例研究|MeterSphere助力万物云构建高效自动化测试平台

万物云空间科技服务股份有限公司&#xff08;以下简称为“万物云”&#xff09;&#xff0c;前身为万科物业发展股份有限公司&#xff0c;是国内领先的物管龙头上市公司。作为一家科技引领的全域空间服务商&#xff0c;万物云致力于打造产业级共享服务平台&#xff0c;基于空间…

酒店提前线上订房小程序源码系统 PHP+MySQL组合开发 源码开源可二开 带完整的安装代码包以及搭建教程

系统概述 随着移动互联网的普及&#xff0c;越来越多的人习惯通过手机进行酒店预订。传统的线下订房方式逐渐无法满足用户的需求&#xff0c;酒店提前线上订房小程序的出现成为必然趋势。该源码系统的开发旨在为酒店提供一个便捷、高效的线上订房平台&#xff0c;提升用户体验…

基于微信小程序+ JAVA后端实现的【医院挂号预约系统】 设计与实现 (内附设计LW + PPT+ 源码+ 演示视频 下载)

项目名称 项目名称&#xff1a; 《基于微信小程序的医院挂号预约系统设计与实现》 项目技术栈 该项目采用了以下核心技术栈&#xff1a; 后端框架/库&#xff1a; Java, SSM框架数据库&#xff1a; MySQL前端技术&#xff1a; 微信小程序, uni-app 项目展示 全文概括 本…

MySQL触发器实战:自动执行的秘密

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 MySQL触发器实战&#xff1a;自动执行的秘密 前言触发器的定义和作用触发器的定义和作用触发器的…

SAP 根据报错消息号快速定位问题

通常用户在业务的操作过程中&#xff0c;经常会遇到报错信息&#xff0c;有些报错是系统控制抛出的信息&#xff0c;但是有些报错的信息是根据不同地点业务场景对填写的数据进行判断校验&#xff0c;然后给出的报错信息&#xff0c;正常情况报错信息一般是有文本&#xff0c;或…

【C语言】文件操作讲解

C语言文件操作讲解 文件文件名文件类型数据在内存中的存储 文件缓冲区文件指针文件的打开与关闭fopenfclosefopen与fclose的使用文件的打开方式 文件的顺序读写fputcfgetcfputsfgetsfprintffscanffwritefread输入流与输出流对比scanf\fscanf\sscanf与printf\fprintf\sprintfssc…

汇编原理(二)寄存器——内存访问

一个字 两个字节 双字 字节为8位 字为16位&#xff08;看两格&#xff09; 双子dword32位&#xff08;看四格&#xff09; 内存中字的存储&#xff1a; 0地址单元中存放的字节型数据是多少&#xff1f; 0地址字单元中存放的字型数据是多少&#xff1f; 2地址字单元中存放…

Secure Operation

文章目录 Secure Summation OperationSecure Set Union Operation Secure Summation Operation 让我们通过一个具体的例子来说明这个算法。 假设有三个数据拥有者 S1, S2 和 S3&#xff0c;他们分别持有以下值&#xff1a; S1 持有 value1 10S2 持有 value2 20S3 持有 val…

基坑气膜:建筑工地环保新利器—轻空间

随着城市化进程的加快&#xff0c;建筑行业的飞速发展带来了严重的环境问题&#xff0c;如噪音和粉尘污染&#xff0c;给人们的生活带来诸多不便。为了解决这些问题&#xff0c;建筑行业一直在探索更为环保和高效的施工方式。近年来&#xff0c;基坑气膜技术逐渐崭露头角&#…

Audition 2024 for Mac/Win:音频录制与编辑的卓越之选

随着数字媒体的不断发展&#xff0c;音频内容创作已经成为各行各业中不可或缺的一部分。无论是音乐制作、广播节目、播客录制还是影视配音&#xff0c;都需要高品质的音频录制和编辑工具来实现专业水准的作品。在这个充满竞争的时代&#xff0c;要想在音频创作领域脱颖而出&…

解线性方程组——最速下降法及图形化表示 | 北太天元 or matlab

一、思路转变 A为对称正定矩阵&#xff0c; A x b Ax b Axb 求解向量 x x x这个问题可以转化为一个求 f ( x ) f(x) f(x)极小值点的问题&#xff0c;为什么可以这样&#xff1a; f ( x ) 1 2 x T A x − x T b c f(x) \frac{1}{2}x^TAx - x^Tb c f(x)21​xTAx−xTbc 可…