All-in-One Solution for Indie Game Development · Empowering Indie Developers' Dreams
📖 Documentation • 🚀 Quick Start
🌐 Language: English | 简体中文 | 繁體中文 | 日本語 | 한국어
A lightweight Unity3D plugin for retrieving device unique identifiers across Android and iOS platforms. It provides a unified C# API to access OAID, IDFA, IMEI, and a stable hardware fingerprint — with zero native dependencies on Android.
- Pure C# on Android — Uses
AndroidJavaClass/AndroidJavaObject(JNI) to call system APIs and vendor SDKs directly. No Java code, no JAR files, no Gradle configuration needed. - Cross-platform — Works seamlessly on Android, iOS, and the Unity Editor. Unsupported APIs gracefully fall back to
SystemInfo.deviceUniqueIdentifier. - Vendor-wide OAID — Supports MSA SDK, Huawei, Xiaomi, OPPO, vivo, and Samsung OAID retrieval on Android via reflection.
- iOS IDFA & SSKeychain — Retrieves IDFA via
ASIdentifierManagerwith ATT support; persists device ID in the Keychain so it survives app reinstalls. - Zero mandatory permissions — No permissions required. Optional permissions can be declared to improve identifier uniqueness.
- Built-in caching — All results are cached in
PlayerPrefsafter the first call, avoiding redundant system queries.
| API | Description | Return Value |
|---|---|---|
DeviceGetOaid |
Get device OAID (Android only) | Raw OAID (stripped -, max 32 chars) |
DeviceGetIdfa |
Get device IDFA (iOS only) | Raw IDFA (stripped -, max 32 chars) |
DeviceGetImei |
Get device IMEI | Raw IMEI (stripped -, max 32 chars) |
DeviceUniqueIdentifier |
Get device unique machine ID | MD5 hash (32-char hex string) |
All APIs cache results via PlayerPrefs. System interfaces are not called again after the first retrieval.
| Platform | DeviceGetOaid |
DeviceGetIdfa |
DeviceGetImei |
DeviceUniqueIdentifier |
|---|---|---|---|---|
| Android | JNI reflection (MSA / Huawei / Xiaomi / OPPO / vivo / Samsung) | SystemInfo.deviceUniqueIdentifier (fallback) |
JNI call to TelephonyManager |
MD5 of IMEI + hardware info + Android ID + WLAN MAC + BT MAC |
| iOS | SystemInfo.deviceUniqueIdentifier (fallback) |
ASIdentifierManager.advertisingIdentifier |
native __DeviceGetIMEI() (IDFV) |
native DeviceUniqueId() (SSKeychain) |
| Editor / Other | SystemInfo.deviceUniqueIdentifier |
SystemInfo.deviceUniqueIdentifier |
SystemInfo.deviceUniqueIdentifier |
SystemInfo.deviceUniqueIdentifier |
This plugin does not require any permissions. It gracefully degrades without them. The plugin does not ship with an AndroidManifest.xml. The following permissions should be declared in the consuming project's AndroidManifest.xml as needed.
| Permission | Improves DeviceUniqueIdentifier uniqueness |
Improves DeviceGetImei uniqueness |
|---|---|---|
READ_PHONE_STATE |
IMEI included in hash | Can retrieve real IMEI |
ACCESS_WIFI_STATE |
WLAN MAC included in hash | - |
BLUETOOTH |
Bluetooth MAC included in hash | - |
<!-- Add to the consuming project's AndroidManifest.xml as needed -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />| Config | Purpose |
|---|---|
NSUserTrackingUsageDescription |
ATT authorization description required for IDFA |
<!-- Add to the consuming project's Info.plist -->
<key>NSUserTrackingUsageDescription</key>
<string>Your advertising identifier will be used to provide better services</string>using GameFrameX.SystemInfo.Runtime;
// Get device OAID (Android only, falls back to SystemInfo.deviceUniqueIdentifier on iOS/Editor)
string oaid = BlankDeviceUniqueIdentifier.DeviceGetOaid;
// Get device IDFA (iOS only, falls back to SystemInfo.deviceUniqueIdentifier on Android/Editor)
string idfa = BlankDeviceUniqueIdentifier.DeviceGetIdfa;
// Get device IMEI
string imei = BlankDeviceUniqueIdentifier.DeviceGetImei;
// Get device unique identifier
string deviceId = BlankDeviceUniqueIdentifier.DeviceUniqueIdentifier;IDFA requires user authorization via ATT (App Tracking Transparency). Add to Info.plist before use:
<key>NSUserTrackingUsageDescription</key>
<string>Your advertising identifier will be used to provide better services</string>And request authorization before calling DeviceGetIdfa:
#if UNITY_IOS || UNITY_IPHONE
// iOS 14+ requires ATT authorization first
if (UnityEngine.iOS.Device.systemVersion.CompareTo("14") >= 0)
{
UnityEngine.iOS.Device.RequestUserAuthorization(UnityEngine.iOS.UserTracking.Authorization);
}
#endif
string idfa = BlankDeviceUniqueIdentifier.DeviceGetIdfa;When unauthorized, DeviceGetIdfa returns an empty string without crashing.
Plugins/
iOS/
BlankDeviceUniqueIdentifier/
AHDeviceUniqueIdentifier.h # iOS native header
AHDeviceUniqueIdentifier.mm # iOS native implementation
SSKeychain.h # SSKeychain keychain utility
SSKeychain.m
Runtime/
BlankDeviceUniqueIdentifier.cs # C# unified interface (Android uses JNI to call system APIs directly, no Java/JAR needed)
On Android,
AndroidJavaClass/AndroidJavaObjectis used to call system APIs and vendor SDKs directly — no Java code compilation or JAR files required.
This project is licensed under the Apache License 2.0.
Copyright 2023 ALianBlank (alianblank@outlook.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
