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.pswp.cn/bicheng/17581.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/17581.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/17581.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

九型人格介紹

協調型人格 作為“好好先生”的何炅是典型的協調型人格者&#xff0c;他總是將大家的利益放在第一位&#xff0c;很少顧及自己的感受;當他周圍的人產生沖突時&#xff0c;他總是力圖找到一個有利于雙方的解決方案;本著息事寧人的態度&#xff0c;他對利益的追逐和向往很低&…

gem5模擬器入門(一)——環境配置

什么是gem5&#xff1f; gem5是一個模塊化的離散事件驅動的計算機系統模擬器平臺。這意味著&#xff1a; GEM5 的組件可以輕松重新排列、參數化、擴展或更換&#xff0c;以滿足您的需求。它將時間的流逝模擬為一系列離散事件。它的預期用途是以各種方式模擬一個或多個計算機系…

掌握并發控制的“急剎車”藝術!

當一個線程運行時&#xff0c;另外一個線程可以直接通過interrupt方法對其設置中斷標志位。 判斷線程是否中斷的2個方法&#xff1a; // 判斷目標線程是否被中斷&#xff0c;不會清除中斷標記。 Thread.currentThread().isInterrupted() // 判斷目標線程是否被中斷&#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;你正在為“小動物收養…

Flutter 中的 CircularProgressIndicator 小部件:全面指南

Flutter 中的 CircularProgressIndicator 小部件&#xff1a;全面指南 在 Flutter 應用開發中&#xff0c;加載指示器是提供用戶反饋的重要組成部分&#xff0c;特別是在需要等待數據加載的場景中。CircularProgressIndicator 是 Flutter 提供的一個表現圓形加載動畫的小部件。…

Python進階:探索Python標準庫和第三方庫

在前兩篇文章中,我們介紹了Python的基本語法和面向對象編程。在這篇文章中,我們將深入探索Python的標準庫以及一些常用的第三方庫。Python的強大之處不僅在于其簡潔的語法,還在于豐富的庫生態系統。通過使用這些庫,你可以更高效地完成各種任務,從文件操作到數據分析、網絡…

godot4.2 + GDextension c++在 vs code 中斷點調試配置

游戲開發中如果做不到自己編寫的代碼做斷點調試&#xff0c;無不是瞎子摸象&#xff0c;特別是C這么底層的語言。這2天開始在VS studio中折騰&#xff0c;一直折騰不出結果&#xff0c;幾次想要放棄GODOT。最終今天在VS code中搞定了這斷點調試C代碼。 在上一篇文章我已經做好了…

React hooks - useContext

useContext 用法使用以非侵入的方式使用 Context使用 useContext 重構 useReducer 案例 用法 實現多層組件的數據傳遞 在全局創建 Context 對象在父組件中使用 Context.Provider 提供數據在子組件中使用 useContext 使用數據 import React, { useContext } from react // 全局…

全網爆火Remini 粘土濾鏡風格,我用ComfyUI一鍵生成了(保姆級教程)!

一、火爆全網的Remini&#xff01; Remini真的火爆了&#xff01;最近大家的朋友應該都被粘土濾鏡刷屏了。 小紅書上粘土濾鏡、粘土特效的帖子動不動就是幾百萬瀏覽量&#xff0c;幾千贊。 在有些電商平臺上還有人接單&#xff0c;幫忙定制remini粘土風格的照片&#xff01; …

解釋瀏覽器緩存和本地存儲的區別,以及如何實現事件的防抖和節流

1:瀏覽器緩存和本地存儲的區別: 瀏覽器緩存:瀏覽器緩存是一種臨時性的數據存儲,用于提高網頁加載速度。緩存的數據存儲在內存或磁盤中,當用戶再次訪問相同的資源時,瀏覽器會優先從緩存中讀取數據,而不是從服務器重新請求。緩存的數據可以在瀏覽器關閉后自動清除,或者根據 HTT…

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中…

神秘顧客調查:第三方渠道監測如何操作?

第三方渠道監測是指通過專業的第三方機構或服務商&#xff0c;對企業的銷售渠道進行系統化的監督和評估。這種監測幫助企業了解各渠道的表現&#xff0c;確保合規性&#xff0c;提升市場競爭力。深圳神秘顧客市場調查限公司&#xff08;SMS&#xff09;總結了第三方渠道監測的操…

【安裝筆記-20240528-Linux-在 Vultr 云服務器上安裝 OpenWRT】

安裝筆記-系列文章目錄 安裝筆記-20240528-Linux-在 Vultr 云服務器上安裝測試 OpenWRT 文章目錄 安裝筆記-系列文章目錄安裝筆記-20240528-Linux-在 Vultr 云服務器上安裝測試 OpenWRT 前言一、軟件介紹名稱&#xff1a;OpenWRT主頁官方介紹 二、安裝步驟測試版本&#xff1a…

多function-calling 調用

多function-calling 調用 接上一篇function-calling調用&#xff0c;本篇實現了一個多function-calling的調用。OpenAI會根據function的描述自己來判斷應該調用哪個function。最終調用function的動作是由我們來決定的&#xff0c;當然你也可以不調對應的函數。 兩個函數分別是…

案例研究|MeterSphere助力萬物云構建高效自動化測試平臺

萬物云空間科技服務股份有限公司&#xff08;以下簡稱為“萬物云”&#xff09;&#xff0c;前身為萬科物業發展股份有限公司&#xff0c;是國內領先的物管龍頭上市公司。作為一家科技引領的全域空間服務商&#xff0c;萬物云致力于打造產業級共享服務平臺&#xff0c;基于空間…

1. lambda初體驗

首先聲明一個函數式接口&#xff0c;就只接口內只有一個抽象方法 //函數式接口 public interface Factory {Object getObject();}接口實現類 public class SubClass implements Factory {Overridepublic Object getObject() {return new User();}}User類 public class User …

酒店提前線上訂房小程序源碼系統 PHP+MySQL組合開發 源碼開源可二開 帶完整的安裝代碼包以及搭建教程

系統概述 隨著移動互聯網的普及&#xff0c;越來越多的人習慣通過手機進行酒店預訂。傳統的線下訂房方式逐漸無法滿足用戶的需求&#xff0c;酒店提前線上訂房小程序的出現成為必然趨勢。該源碼系統的開發旨在為酒店提供一個便捷、高效的線上訂房平臺&#xff0c;提升用戶體驗…