【FlutterUtilCode】Flutter工具篇之DeviceUtils
前言
FlutterUtilCode 是一个 Flutter 工具类集合插件,封装了常用的工具类和函数,方便开发者调用。
本篇是 Flutter工具篇之DeviceUtils,系列文章内容主要介绍插件中工具类的功能、用法和代码实现等,感兴趣的同学可以持续关注。
FlutterUtilCode 系列(一)—— Flutter工具篇之LogUtils、SharedPerfsUtils
FlutterUtilCode 系列(二)—— Flutter工具篇之ToastUtils
FlutterUtilCode 系列(三)—— Flutter工具篇之UuidUtils
FlutterUtilCode 系列(四)—— Flutter工具篇之DeviceUtils
Device工具类-DeviceUtils
在 App 开发中,获取安装设备的信息是非常必要的。这些信息不仅可以协助开发者了解用户群体、优化应用程序并提供更好的用户体验和服务,还可以帮助开发者更好地定位和修复应用程序中的漏洞、错误或其他技术问题,从而确保应用程序始终保持高质量和可靠性。
一般来说,我们需要获取设备的设备ID、设备品牌、设备型号、系统版本号、系统版本名称等,我们的 DeviceUtils 就围绕这些信息来实现。
这里我们用到了 pub 上的 device_info_plus 。device_info_plus 是一个获取当前设备信息的插件,其 LIKES 数达到了 1.6K 也是非常收欢迎,目前已支持全平台。
一、代码实现
DeviceUtils 目前暂只支持 Android /iOS 平台设备信息获取,后续会加上其他平台。
我们通过 getDeviceData()
方法获取当前平台的设备信息并缓存下来,方便多次调用。实现代码如下:
/// 获取设备信息
static Future<Map<String, dynamic>> getDeviceData() async {
if (_deviceData != null) {
return _deviceData!;
}
if (kIsWeb) {
_deviceData = _readWebBrowserInfo(await deviceInfoPlugin.webBrowserInfo);
} else {
_deviceData = switch (defaultTargetPlatform) {
TargetPlatform.android => _readAndroidDeviceInfo(await deviceInfoPlugin.androidInfo),
TargetPlatform.iOS => _readIosDeviceInfo(await deviceInfoPlugin.iosInfo),
TargetPlatform.linux => _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo),
TargetPlatform.windows => _readWindowsDeviceInfo(await deviceInfoPlugin.windowsInfo),
TargetPlatform.macOS => _readMacOsDeviceInfo(await deviceInfoPlugin.macOsInfo),
TargetPlatform.fuchsia => <String, dynamic>{'Error:': 'Fuchsia platform isn\'t supported'},
};
}
return _deviceData!;
}
对于设备型号,由于 iOS 和 Android 两个平台的设备型号是同一个字段,所以我们只需要通过 model
字段获取即可。
/// 获取设备型号
static Future<String> getModel() async {
Map<String, dynamic> deviceData = await getDeviceData();
return deviceData['model'] ?? '';
}
对于设备品牌,iOS 中是通过 brand
字段获取, Android 中则是通过 name
字段获取。
/// 设备品牌
static Future<String> getBrand() async {
Map<String, dynamic> deviceData = await getDeviceData();
if (kIsWeb) {
return '';
} else {
return switch (defaultTargetPlatform) {
TargetPlatform.android => deviceData['brand'],
TargetPlatform.iOS => deviceData['name'],
TargetPlatform.linux => '',
TargetPlatform.windows => '',
TargetPlatform.macOS => '',
TargetPlatform.fuchsia => '',
};
}
}
对于系统版本号,在 iOS 中通过 systemVersion
字段获取,在 Android 中通过 version.sdkInt
获取。注意 version.sdkInt
获取的是 Android系统的 SDK_INT
,而不是我们平常称呼的 AndroidXX。
对于系统名称,在 iOS 中通过 systemName
字段获取,在 Android 中通过 display
获取。在 iOS 中获取的是 iOS,而在 Android 中获取的是厂商的系统名称,例如:CH6J-H6211V-Q-OP-201215V091。
/// 获取设备系统版本号
static Future<String> getSystemVersion() async {
Map<String, dynamic> deviceData = await getDeviceData();
if (kIsWeb) {
return '';
} else {
return switch (defaultTargetPlatform) {
TargetPlatform.android => '${deviceData['version.sdkInt']}',
TargetPlatform.iOS => '${deviceData['systemVersion']}',
TargetPlatform.linux => '',
TargetPlatform.windows => '',
TargetPlatform.macOS => '',
TargetPlatform.fuchsia => '',
};
}
}
/// 获取设备系统名称
static Future<String> getSystemName() async {
Map<String, dynamic> deviceData = await getDeviceData();
if (kIsWeb) {
return deviceData['browserName'];
} else {
return switch (defaultTargetPlatform) {
TargetPlatform.android => deviceData['display'],
TargetPlatform.iOS => deviceData['systemName'],
TargetPlatform.linux => '',
TargetPlatform.windows => '',
TargetPlatform.macOS => '',
TargetPlatform.fuchsia => '',
};
}
}
对于最重要的 设备唯一Id 获取,由于其获取方式不同于上面的情况,这里我们需要着重讲解下。
对于 iOS 来说,获取设备唯一Id 非常简单,只需要调用系统API 获取即可。但是,对于 Android 来说,由于其复杂的系统版本、高版本系统对权限的收紧以及第三方厂商的定制化,导致获取设备唯一Id 的方式更加复杂。
针对 Android 系统获取设备的复杂性,我们采用目前行业内比较通用的方式:获取AnroidID + UUID + 本地缓存 来获取设备唯一ID。
/// 获取唯一设备 ID
/// 若没有从设备获取到,则生成一个 UUID 作为设备 ID
static Future<String> getDeviceId() async {
// 如果已经获取过设备ID,则直接返回
if (_deviceId != null && _deviceId!.isNotEmpty) {
return _deviceId!;
}
// 从本地获取设备ID
String? deviceId = await SharedPrefsUtil.getString(SPConstants.deviceId);
if (deviceId != null && deviceId.isNotEmpty) {
_deviceId = deviceId;
return _deviceId!;
}
// 获取设备ID
Map<String, dynamic> deviceData = await getDeviceData();
if (kIsWeb) {
_deviceId = '';
} else {
_deviceId = switch (defaultTargetPlatform) {
TargetPlatform.android => await _getAndroidId(),
TargetPlatform.iOS => deviceData['identifierForVendor'],
TargetPlatform.linux => '',
TargetPlatform.windows => '',
TargetPlatform.macOS => '',
TargetPlatform.fuchsia => '',
};
}
// 如果获取不到,则生成一个UUID
_deviceId = _getUniqueDeviceId(_deviceId);
// 保存到本地
SharedPrefsUtil.putString(SPConstants.deviceId, _deviceId!);
return _deviceId!;
}
对于已获取过的设备Id 直接取出缓存返回,若没有获取过设备Id 的则通过 _getAndroidId()
方法获取 AndroidId
。我们引入 android_id 库,并针对部分系统版本获取的 AndroidId
重复问题进行处理。
/// 获取 AndroidId
static Future<String?> _getAndroidId() async {
String? androidId = await _androidIdPlugin.getId();
if ("9774d56d682e549c" == androidId) return null;
// 根据 AndroidId 生成 UUID
if (androidId != null && androidId.isNotEmpty) {
return UuidUtils.getUuidV5(androidId);
}
return null;
}
若是 AndroidId
没有获取到,则在 _getUniqueDeviceId()
方法中进行判断,并生成 UUID 代替。
/// 获取 设备唯一 ID
static String _getUniqueDeviceId(String? deviceId) {
if (deviceId == null || deviceId.isEmpty) {
return UuidUtils.getUuid();
} else {
return deviceId;
}
}
最后,将获取的设备Id 通过 SharedPrefsUtil 缓存,确保在用户没有卸载应用的情况下,获取到的设备ID 是唯一的。
...
// 如果获取不到,则生成一个UUID
_deviceId = _getUniqueDeviceId(_deviceId);
// 保存到本地
SharedPrefsUtil.putString(SPConstants.deviceId, _deviceId!);
return _deviceId!;
总结一下:
- iOS :通过
identifierForVendor
字段,能够直接获取到设备唯一ID。 - Android :先获取
AndroidID
,若获取到则生成设备唯一ID。若获取不到,则生成 UUID 字符串作为唯一标识。 - 设备ID是否唯一 :iOS 获取到的设备ID 一定是唯一的。Android 在没有卸载重装的情况下也是唯一的,若是卸载重装,若获取到设备的
AndroidID
则也是唯一的,只有在没有获取到AndoridID
并且有卸载重装行为的,才会出现不一致的问题。
二、使用案例
DeviceUtils 使用起来非常简单,只需要一行代码调用即可:
/// 获取设备唯一ID
await DeviceUtils.getDeviceId();
/// 获取设备型号
await DeviceUtils.getModel();
/// 获取设备品牌
await DeviceUtils.getBrand();
/// 获取操作系统版本号
await DeviceUtils.getSystemVersion();
/// 获取系统版本名称
await DeviceUtils.getSystemName();
运行结果:

结语
好了,今天的工具类整理文章就到这里,目前插件已发布到 Pub 中,欢迎大家体验。
如果觉得这篇文章对你有所帮助的话,不要忘记一键三连哦,大家的点赞是我更新的动力🥰。
Pub: flutter_util_code
项目源码:FlutterUtilCode
使用案例:Example
转载自:https://juejin.cn/post/7241861929412362296