发表于 2024-7-19 09:31:57

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;
    }
}

三、注意实现


[*]权限管理:确保在运行时请求须要的权限,特别是在 Android 6.0(API 23)及以上版本中,动态权限请求是必需的。
[*]兼容性检查:由于不同 Android 版本的行为可能不同,代码中需要进行版本检查。
[*]隐私合规:获取设备的敏感信息时,请确保应用符合相干的隐私政策和法律法规,关照用户并获得须要的同意。
通过上述步骤,你应该可以大概在 Unity 中乐成获取 Android 10 及以上版本设备的序列号。

四、案例实现简单步骤

1、创建 Unity 工程
https://img-blog.csdnimg.cn/direct/1cd66ffedee24c828957cbb9965b20a9.png

2、新建脚本 DeviceInfo ,编写代码获取设备的序列号
https://img-blog.csdnimg.cn/direct/f6292b951afd465b87d180eda0800dfd.png

3、由于这个可能需要权限申请,编写代码申请权限
https://img-blog.csdnimg.cn/direct/65a06373a276481e967aa86d65ddced9.png

4、实现申请电话权限,获取设备序列号(TestDeviceInfo.cs)
https://img-blog.csdnimg.cn/direct/ec8581c68d084b0ca26c439fa17d5175.png

5、把脚本 TestDeviceInfo.cs 挂载到场景中
https://img-blog.csdnimg.cn/direct/3fd7e33104b244d397ff9b22bfc5f9ce.png

6、在 Player Settings 中的 Build 中勾选 Custom Main Manifest ,添加相干 Phone 权限申请
https://img-blog.csdnimg.cn/direct/c7e60d7941e84be89a69d1c6982d62a7.png
https://img-blog.csdnimg.cn/direct/59bc8992d8074351a7a7938682488d47.png

7、打包运行,可能报如下错误
Exception getting serial number: java.lang.SecurityException: getSerial: The uid 10170 does not meet the requirements to access device identifiers.
https://img-blog.csdnimg.cn/direct/29fd72e3f58043e3b33d645daea949bd.png
错误表明尝试获取设备序列号时碰到了权限问题。在 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_EDITOR
      try
      {
            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);
      }
#endif

      return deviceId;
    }
9、打包运行,能获取到 设备的 Android ID
https://img-blog.csdnimg.cn/direct/50de8de9f57b4c4ea9b5daef5e2664c8.png

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_EDITOR      try      {            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);      }#endif      return serialNumber;    }    /// <summary>    /// 获取版本    /// </summary>    /// <returns></returns>    private static int GetSDKInt()    {      int sdkInt = 0;#if UNITY_ANDROID && !UNITY_EDITOR      using (AndroidJavaClass versionClass = new AndroidJavaClass("android.os.Build$VERSION"))      {            sdkInt = versionClass.GetStatic<int>("SDK_INT");      }#endif      return sdkInt;    }    /// <summary>
    /// 获取设备的 Android ID
    /// </summary>
    /// <returns></returns>
    public static string GetAndroidId()
    {
      string deviceId = string.Empty;

#if UNITY_ANDROID && !UNITY_EDITOR
      try
      {
            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);
      }
#endif

      return 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 = " ";

    // Start is called before the first frame update
    void 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"?>
<manifest
    xmlns: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>


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Unity 之 Android 【获取设备的序列号 (Serial Number)/Android_ID】功能的