device_id_all 0.0.1
device_id_all: ^0.0.1 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。
| 字段 | 平台 | 说明 |
|---|---|---|
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.bestEffortDeviceId);
print(identifiers.androidId);
print(identifiers.iosIdfa);
注意:getAllDeviceIdentifiers() 只负责读取当前可用值,不会自动弹出 iOS ATT 授权框。需要 IDFA 时,应先按“iOS IDFA 授权”一节主动请求授权。
也可以按标识单独读取:
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。上架应用商店前应评估合规风险。