前言

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 也是十分收欢迎,现在已支撑全渠道。

【FlutterUtilCode】Flutter工具篇之DeviceUtils

一、代码完成

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!;

总结一下:

  1. iOS :经过 identifierForVendor 字段,可以直接获取到设备仅有ID。
  2. Android :先获取 AndroidID ,若获取到则生成设备仅有ID。若获取不到,则生成 UUID 字符串作为仅有标识。
  3. 设备ID是否仅有 :iOS 获取到的设备ID 一定是仅有的。Android 在没有卸载重装的情况下也是仅有的,若是卸载重装,若获取到设备的 AndroidID 则也是仅有的,只要在没有获取到 AndoridID 并且有卸载重装行为的,才会呈现不一致的问题。

二、使用事例

DeviceUtils 使用起来十分简略,只需要一行代码调用即可:

/// 获取设备仅有ID
await DeviceUtils.getDeviceId();
/// 获取设备类型
await DeviceUtils.getModel();
/// 获取设备品牌
await DeviceUtils.getBrand();
/// 获取操作体系版别号
await DeviceUtils.getSystemVersion();
/// 获取体系版别称号
await DeviceUtils.getSystemName();

运行结果:

【FlutterUtilCode】Flutter工具篇之DeviceUtils

结语

好了,今日的东西类整理文章就到这儿,现在插件已发布到 Pub 中,欢迎我们体验。

假如觉得这篇文章对你有所协助的话,不要忘掉一键三连哦,我们的点赞是我更新的动力。

Pub: flutter_util_code

项目源码:FlutterUtilCode

使用事例:Example