device_id_all 0.0.4
device_id_all: ^0.0.4 copied to clipboard
Best-effort Flutter plugin for Android and iOS device identifiers, including Android ID, OAID, GAID, IDFA and app UUID.
device_id_all #
一个 Flutter 插件,用于在 Android 和 iOS 上尽可能读取常见设备标识和设备基础信息。
能力边界 #
这些标识受系统版本、权限、用户授权、厂商 SDK 和应用商店政策限制。插件遵循一个规则:能合法读取就返回字符串,不能读取就返回 null。
| 字段 | 平台 | 说明 |
|---|---|---|
platformName |
Android/iOS | 平台名称:android 或 ios。 |
operatingSystemName |
Android/iOS | 操作系统名称,例如 Android 或 iOS。 |
operatingSystemVersion |
Android/iOS | 操作系统版本号。 |
deviceName |
Android/iOS | 设备名称;iOS 通常是用户设置的设备名,Android 尽量读取系统公开名称。 |
deviceManufacturer |
Android/iOS | 设备制造商,例如 Google、Samsung、Apple。 |
deviceBrand |
Android/iOS | 设备品牌。 |
deviceModel |
Android/iOS | 设备型号。 |
deviceProduct |
Android | Android Build.PRODUCT。 |
deviceHardware |
Android | Android Build.HARDWARE。 |
isPhysicalDevice |
Android/iOS | 是否更像真机;Android 为启发式判断,iOS 根据运行环境判断。 |
isSimulator |
Android/iOS | 是否更像模拟器;Android 为启发式判断,iOS 根据运行环境判断。 |
isRooted |
Android | 是否疑似 root;启发式判断,不能作为安全边界。 |
isJailbroken |
iOS | 是否疑似越狱;启发式判断,不能作为安全边界。 |
androidSdkInt |
Android | Android API Level。 |
androidBoard |
Android | Android Build.BOARD。 |
androidBootloader |
Android | Android Build.BOOTLOADER。 |
androidBuildId |
Android | Android Build.ID。 |
androidBuildDisplay |
Android | Android Build.DISPLAY。 |
androidBuildFingerprint |
Android | Android Build.FINGERPRINT。 |
androidBuildHost |
Android | Android Build.HOST。 |
androidBuildTags |
Android | Android Build.TAGS。 |
androidBuildType |
Android | Android Build.TYPE。 |
androidBuildUser |
Android | Android Build.USER。 |
androidSupportedAbis |
Android | 当前设备支持的 ABI 列表。 |
iosSystemName |
iOS | iOS UIDevice.systemName。 |
iosModel |
iOS | iOS UIDevice.model。 |
iosLocalizedModel |
iOS | iOS UIDevice.localizedModel。 |
iosModelIdentifier |
iOS | iOS 硬件型号标识,例如 iPhone15,2。 |
iosUserInterfaceIdiom |
iOS | iOS 界面形态,例如 phone、pad、mac。 |
bestEffortDeviceId |
Android/iOS | Android 为 ANDROID_ID;iOS 为 identifierForVendor。 |
androidId |
Android | Settings.Secure.ANDROID_ID。 |
androidImei |
Android | 需要 READ_PHONE_STATE;Android 10+ 普通应用通常不可读。 |
appInstanceUuid |
Android/iOS | 插件生成并保存在 App 沙盒内的 UUID,卸载重装会变化。 |
iosUdid |
iOS | Apple 禁止普通 App 获取真实 UDID,正常返回 null。 |
androidOaid |
Android | 尝试常见系统来源;宿主 App 集成 HMS/厂商 SDK 时可提高成功率。 |
iosIdfa |
iOS | iOS 14+ 需要 ATT 授权;未授权返回 null。 |
androidGaid |
Android | 需要 Google Play 服务及宿主 App 中存在 Advertising ID 客户端类。 |
Android OAID 配置 #
插件已接入 Android_CN_OAID,Android 侧会优先通过它读取 OAID/AAID,再回退到插件内置的少量厂商 Provider 方案。
如果宿主 App 使用 Gradle 7.0+,并且在 settings.gradle 或 settings.gradle.kts 中启用了 dependencyResolutionManagement,需要确认仓库里包含:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven { url 'https://storage.googleapis.com/download.flutter.io' }
maven { url 'https://jitpack.io' }
maven { url 'https://developer.huawei.com/repo' }
maven { url 'https://developer.hihonor.com/repo' }
}
}
如果已有 dependencyResolutionManagement,只需要合并仓库配置:
repositories {
maven { url 'https://jitpack.io' }
maven { url 'https://developer.huawei.com/repo' }
maven { url 'https://developer.hihonor.com/repo' }
}
Kotlin DSL 写法:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven("https://storage.googleapis.com/download.flutter.io")
maven("https://jitpack.io")
maven("https://developer.huawei.com/repo")
maven("https://developer.hihonor.com/repo")
}
}
如果已有 dependencyResolutionManagement,只需要合并仓库配置:
repositories {
maven("https://jitpack.io")
maven("https://developer.huawei.com/repo")
maven("https://developer.hihonor.com/repo")
}
建议在用户同意隐私政策后预取 OAID:
final plugin = DeviceIdAll();
await plugin.preloadAndroidOaid();
final oaid = await plugin.getAndroidOaid();
注意:OAID 只在部分国产 Android 真机和支持 AAID 的 Google Play 服务环境中可用;模拟器、用户关闭广告标识、系统服务缺失或厂商接口不可用时仍会返回 null。
使用方式 #
final plugin = DeviceIdAll();
final identifiers = await plugin.getAllDeviceIdentifiers();
print(identifiers.operatingSystemVersion);
print(identifiers.deviceModel);
print(identifiers.isPhysicalDevice);
print(identifiers.isSimulator);
print(identifiers.isRooted);
print(identifiers.isJailbroken);
print(identifiers.bestEffortDeviceId);
print(identifiers.androidId);
print(identifiers.iosIdfa);
注意:getAllDeviceIdentifiers() 只负责读取当前可用值,不会自动弹出 iOS ATT 授权框。需要 IDFA 时,应先按“iOS IDFA 授权”一节主动请求授权。
设备基础信息来自系统公开 API,通常不需要额外权限;但不同系统版本、厂商 ROM、模拟器环境可能返回空值或厂商自定义值。
isRooted 与 isJailbroken 是启发式检测,只适合作为风险信号,不适合作为登录、支付、风控等高安全场景的唯一判断依据。
也可以按标识单独读取:
final androidId = await plugin.getAndroidId();
final appUuid = await plugin.getAppInstanceUuid();
final gaid = await plugin.getAndroidGaid();
iOS IDFA 授权 #
IDFA 不是普通设备 ID。iOS 14+ 必须先通过 App Tracking Transparency 授权,用户允许后才可能读取到非空 iosIdfa。
宿主 App 必须先在 Info.plist 中配置:
<key>NSUserTrackingUsageDescription</key>
<string>用于提供更准确的广告归因和效果统计。</string>
推荐调用流程:
final plugin = DeviceIdAll();
final status = await plugin.getIosTrackingAuthorizationStatus();
if (status == IosTrackingAuthorizationStatus.notDetermined) {
final newStatus = await plugin.requestIosTrackingAuthorization();
if (newStatus == IosTrackingAuthorizationStatus.authorized) {
final idfa = await plugin.getIosIdfa();
print(idfa);
}
} else if (status == IosTrackingAuthorizationStatus.authorized) {
final idfa = await plugin.getIosIdfa();
print(idfa);
}
如果页面刚启动就请求授权,部分系统版本可能不会马上展示弹窗。更稳妥的做法是在首帧渲染后再请求,或者由用户点击按钮触发:
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future<void>.delayed(const Duration(milliseconds: 600));
final status = await plugin.requestIosTrackingAuthorization();
final idfa = status == IosTrackingAuthorizationStatus.authorized
? await plugin.getIosIdfa()
: null;
});
系统不弹 ATT 授权框的常见原因:
Info.plist没有配置NSUserTrackingUsageDescription。- 当前状态已经是
denied,用户之前拒绝过;系统不会重复弹窗。 - 系统设置中关闭了“允许 App 请求跟踪”。
- 当前状态是
restricted,例如儿童账号、受管理设备或系统策略限制。 - 已经授权过,状态是
authorized,此时不会再弹窗,直接读取 IDFA。
可以通过 getIosTrackingAuthorizationStatus() 判断当前状态。example 页面也展示了 trackingStatus,并提供“请求 IDFA 授权”按钮,方便真机验证。
Android IMEI 权限 #
如果宿主 App 确实需要尝试读取 IMEI,需要自行在 AndroidManifest 中声明,并在运行时申请权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
注意:Android 10 及以上普通应用即使有权限也通常无法读取 IMEI。上架应用商店前应评估合规风险。