device_id_manager 1.0.0
device_id_manager: ^1.0.0 copied to clipboard
Cross-platform persistent device ID manager for Flutter. iOS uses Keychain, Android uses MediaDrm + SHA-256 hash. Survives app reinstalls.
📱 device_id_manager #
A cross-platform Flutter plugin that generates and persists unique device IDs — even after reinstalling the app. Built for apps that need a reliable, persistent device identifier with zero permissions.
✨ Features #
- 🔒 Persistent across app reinstalls on both iOS and Android
- 🏷️ Per-app unique IDs on Android (different apps on the same device get different IDs)
- 🚫 No permissions required
- 👤 Identified user support via
logIn()/logOut() - ⚡ Synchronous access after initialization — no
awaitneeded for getters - 🛡️ Secure storage — iOS Keychain (AES-256), Android MediaDrm (hardware-backed)
- 💥 Fail-safe — throws
StateErrorif accessed beforeinitialize()
🧠 How It Works #
🍏 iOS #
- Checks Keychain for an existing ID (
user_device_idkey) - If not found, generates a UUID v4 and stores it in Keychain
- Keychain data persists across app reinstalls
🤖 Android #
- Gets hardware device ID via MediaDrm API
- Combines with app package name:
"$mediaDrmId:$packageName" - Applies SHA-256 hash → per-app unique ID
- Falls back to UUID v4 if MediaDrm is unavailable (rooted devices, emulators, custom ROMs)
📊 Platform Comparison #
| 🍏 iOS | 🤖 Android | |
|---|---|---|
| Generation | UUID v4 | MediaDrm + SHA-256 |
| Storage | Keychain | Hardware (MediaDrm API) |
| Survives reinstall | ✅ Yes | ✅ Yes |
| Per-app unique | ✅ Yes (bundle ID scoped) | ✅ Yes (package name hashed) |
| Permissions | 🚫 None | 🚫 None |
📦 Installation #
Add to your pubspec.yaml:
dependencies:
device_id_manager: ^1.0.0
Then run:
flutter pub get
🍏 iOS Setup #
Add the following to your ios/Runner/Info.plist if not already present (required by flutter_secure_storage):
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to protect your data</string>
🤖 Android Setup #
Minimum SDK 18 is required. In android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 18
}
}
🛠️ Usage #
Basic #
import 'package:device_id_manager/device_id_manager.dart';
// Initialize once at app startup
await DeviceIdManager.initialize();
// Access device ID (synchronous, non-null)
String id = DeviceIdManager.deviceId;
print('Device ID: $id');
👤 Identified Users (Login / Logout) #
// Log in with a custom user ID
await DeviceIdManager.logIn('user_12345');
print(DeviceIdManager.isAnonymous); // false
print(DeviceIdManager.appUserId); // user_12345
print(DeviceIdManager.customUserId); // user_12345
// Log out — reverts to anonymous device ID
await DeviceIdManager.logOut();
print(DeviceIdManager.isAnonymous); // true
print(DeviceIdManager.appUserId); // null
print(DeviceIdManager.customUserId); // <device_id>
🔇 Logging #
// Disable logs
DeviceIdLogger.setEnabled(false);
// Enable logs (default)
DeviceIdLogger.setEnabled(true);
📚 API Reference #
DeviceIdManager #
| Property / Method | Type | Description |
|---|---|---|
initialize() |
Future<void> |
Must be called before anything else |
deviceId |
String |
Persistent device ID |
isAnonymous |
bool |
true if no custom user ID is set |
customUserId |
String |
App user ID if logged in, otherwise device ID |
appUserId |
String? |
Custom user ID, null if anonymous |
isInitialized |
bool |
Whether initialize() has been called |
logIn(String) |
Future<void> |
Set an identified user ID |
logOut() |
Future<void> |
Clear user ID, revert to anonymous |
clearUserId() |
Future<void> |
Clear all stored IDs and reset state |
hasUserId() |
Future<bool> |
Check if a device ID exists |
⚠️ Important: Accessing any getter before
initialize()throws aStateError.
🚧 Limitations #
- MediaDrm only available on Android API ≥ 18
- On some custom or rooted ROMs, MediaDrm may be unreliable
- Factory reset will remove the iOS Keychain ID
- On iOS, Keychain-based ID may reset if iCloud Keychain is disabled or device is restored without backup
🔍 Example #
Clone the repository and run the example app:
cd example
flutter run
📄 License #
MIT License. © 2025