Skip to content

Commit 3b42025

Browse files
author
Chris Yang
authored
[device_info_platform_interface] handle null value from method channel (flutter#3609)
1 parent bd88615 commit 3b42025

File tree

5 files changed

+344
-52
lines changed

5 files changed

+344
-52
lines changed

packages/device_info/device_info_platform_interface/lib/device_info_platform_interface.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ import 'dart:async';
77
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
88

99
import 'method_channel/method_channel_device_info.dart';
10-
1110
import 'model/android_device_info.dart';
1211
import 'model/ios_device_info.dart';
13-
1412
export 'model/android_device_info.dart';
1513
export 'model/ios_device_info.dart';
1614

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
// Copyright 2017 The Chromium Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
15
import 'dart:async';
26

37
import 'package:flutter/services.dart';
48
import 'package:meta/meta.dart';
5-
69
import 'package:device_info_platform_interface/device_info_platform_interface.dart';
710

811
/// An implementation of [DeviceInfoPlatform] that uses method channels.
@@ -13,16 +16,15 @@ class MethodChannelDeviceInfo extends DeviceInfoPlatform {
1316

1417
// Method channel for Android devices
1518
Future<AndroidDeviceInfo> androidInfo() async {
16-
return AndroidDeviceInfo.fromMap(
17-
(await channel.invokeMethod('getAndroidDeviceInfo'))
18-
.cast<String, dynamic>(),
19-
);
19+
return AndroidDeviceInfo.fromMap((await channel
20+
.invokeMapMethod<String, dynamic>('getAndroidDeviceInfo')) ??
21+
<String, dynamic>{});
2022
}
2123

2224
// Method channel for iOS devices
2325
Future<IosDeviceInfo> iosInfo() async {
2426
return IosDeviceInfo.fromMap(
25-
(await channel.invokeMethod('getIosDeviceInfo')).cast<String, dynamic>(),
26-
);
27+
(await channel.invokeMapMethod<String, dynamic>('getIosDeviceInfo')) ??
28+
<String, dynamic>{});
2729
}
2830
}

packages/device_info/device_info_platform_interface/lib/model/android_device_info.dart

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,39 +38,63 @@ class AndroidDeviceInfo {
3838
final AndroidBuildVersion version;
3939

4040
/// The name of the underlying board, like "goldfish".
41+
///
42+
/// The value is an empty String if it is not available.
4143
final String board;
4244

4345
/// The system bootloader version number.
46+
///
47+
/// The value is an empty String if it is not available.
4448
final String bootloader;
4549

4650
/// The consumer-visible brand with which the product/hardware will be associated, if any.
51+
///
52+
/// The value is an empty String if it is not available.
4753
final String brand;
4854

4955
/// The name of the industrial design.
56+
///
57+
/// The value is an empty String if it is not available.
5058
final String device;
5159

5260
/// A build ID string meant for displaying to the user.
61+
///
62+
/// The value is an empty String if it is not available.
5363
final String display;
5464

5565
/// A string that uniquely identifies this build.
66+
///
67+
/// The value is an empty String if it is not available.
5668
final String fingerprint;
5769

5870
/// The name of the hardware (from the kernel command line or /proc).
71+
///
72+
/// The value is an empty String if it is not available.
5973
final String hardware;
6074

6175
/// Hostname.
76+
///
77+
/// The value is an empty String if it is not available.
6278
final String host;
6379

6480
/// Either a changelist number, or a label like "M4-rc20".
81+
///
82+
/// The value is an empty String if it is not available.
6583
final String id;
6684

6785
/// The manufacturer of the product/hardware.
86+
///
87+
/// The value is an empty String if it is not available.
6888
final String manufacturer;
6989

7090
/// The end-user-visible name for the end product.
91+
///
92+
/// The value is an empty String if it is not available.
7193
final String model;
7294

7395
/// The name of the overall product.
96+
///
97+
/// The value is an empty String if it is not available.
7498
final String product;
7599

76100
/// An ordered list of 32 bit ABIs supported by this device.
@@ -83,15 +107,23 @@ class AndroidDeviceInfo {
83107
final List<String> supportedAbis;
84108

85109
/// Comma-separated tags describing the build, like "unsigned,debug".
110+
///
111+
/// The value is an empty String if it is not available.
86112
final String tags;
87113

88114
/// The type of build, like "user" or "eng".
115+
///
116+
/// The value is an empty String if it is not available.
89117
final String type;
90118

91-
/// `false` if the application is running in an emulator, `true` otherwise.
119+
/// The value is `true` if the application is running on a physical device.
120+
///
121+
/// The value is `false` when the application is running on a emulator, or the value is unavailable.
92122
final bool isPhysicalDevice;
93123

94124
/// The Android hardware device ID that is unique between the device + user and app signing.
125+
///
126+
/// The value is an empty String if it is not available.
95127
final String androidId;
96128

97129
/// Describes what features are available on the current device.
@@ -113,35 +145,41 @@ class AndroidDeviceInfo {
113145
/// Deserializes from the message received from [_kChannel].
114146
static AndroidDeviceInfo fromMap(Map<String, dynamic> map) {
115147
return AndroidDeviceInfo(
116-
version:
117-
AndroidBuildVersion._fromMap(map['version']!.cast<String, dynamic>()),
118-
board: map['board']!,
119-
bootloader: map['bootloader']!,
120-
brand: map['brand']!,
121-
device: map['device']!,
122-
display: map['display']!,
123-
fingerprint: map['fingerprint']!,
124-
hardware: map['hardware']!,
125-
host: map['host']!,
126-
id: map['id']!,
127-
manufacturer: map['manufacturer']!,
128-
model: map['model']!,
129-
product: map['product']!,
130-
supported32BitAbis: _fromList(map['supported32BitAbis']!),
131-
supported64BitAbis: _fromList(map['supported64BitAbis']!),
132-
supportedAbis: _fromList(map['supportedAbis']!),
133-
tags: map['tags']!,
134-
type: map['type']!,
135-
isPhysicalDevice: map['isPhysicalDevice']!,
136-
androidId: map['androidId']!,
137-
systemFeatures: _fromList(map['systemFeatures']!),
148+
version: AndroidBuildVersion._fromMap(map['version'] != null
149+
? map['version'].cast<String, dynamic>()
150+
: <String, dynamic>{}),
151+
board: map['board'] ?? '',
152+
bootloader: map['bootloader'] ?? '',
153+
brand: map['brand'] ?? '',
154+
device: map['device'] ?? '',
155+
display: map['display'] ?? '',
156+
fingerprint: map['fingerprint'] ?? '',
157+
hardware: map['hardware'] ?? '',
158+
host: map['host'] ?? '',
159+
id: map['id'] ?? '',
160+
manufacturer: map['manufacturer'] ?? '',
161+
model: map['model'] ?? '',
162+
product: map['product'] ?? '',
163+
supported32BitAbis: _fromList(map['supported32BitAbis']),
164+
supported64BitAbis: _fromList(map['supported64BitAbis']),
165+
supportedAbis: _fromList(map['supportedAbis']),
166+
tags: map['tags'] ?? '',
167+
type: map['type'] ?? '',
168+
isPhysicalDevice: map['isPhysicalDevice'] ?? false,
169+
androidId: map['androidId'] ?? '',
170+
systemFeatures: _fromList(map['systemFeatures']),
138171
);
139172
}
140173

141174
/// Deserializes message as List<String>
142175
static List<String> _fromList(dynamic message) {
143-
final List<dynamic> list = message;
144-
return List<String>.from(list);
176+
if (message == null) {
177+
return <String>[];
178+
}
179+
assert(message is List<dynamic>);
180+
final List<dynamic> list = List<dynamic>.from(message)
181+
..removeWhere((value) => value == null);
182+
return list.cast<String>();
145183
}
146184
}
147185

@@ -173,17 +211,25 @@ class AndroidBuildVersion {
173211
final String? securityPatch;
174212

175213
/// The current development codename, or the string "REL" if this is a release build.
214+
///
215+
/// The value is an empty String if it is not available.
176216
final String codename;
177217

178218
/// The internal value used by the underlying source control to represent this build.
219+
///
220+
/// The value is an empty String if it is not available.
179221
final String incremental;
180222

181223
/// The user-visible version string.
224+
///
225+
/// The value is an empty String if it is not available.
182226
final String release;
183227

184228
/// The user-visible SDK version of the framework.
185229
///
186230
/// Possible values are defined in: https://developer.android.com/reference/android/os/Build.VERSION_CODES.html
231+
///
232+
/// The value is -1 if it is unavailable.
187233
final int sdkInt;
188234

189235
/// Deserializes from the map message received from [_kChannel].
@@ -192,10 +238,10 @@ class AndroidBuildVersion {
192238
baseOS: map['baseOS'],
193239
previewSdkInt: map['previewSdkInt'],
194240
securityPatch: map['securityPatch'],
195-
codename: map['codename']!,
196-
incremental: map['incremental']!,
197-
release: map['release']!,
198-
sdkInt: map['sdkInt']!,
241+
codename: map['codename'] ?? '',
242+
incremental: map['incremental'] ?? '',
243+
release: map['release'] ?? '',
244+
sdkInt: map['sdkInt'] ?? -1,
199245
);
200246
}
201247
}

packages/device_info/device_info_platform_interface/lib/model/ios_device_info.dart

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,60 @@ class IosDeviceInfo {
1919
});
2020

2121
/// Device name.
22+
///
23+
/// The value is an empty String if it is not available.
2224
final String name;
2325

2426
/// The name of the current operating system.
27+
///
28+
/// The value is an empty String if it is not available.
2529
final String systemName;
2630

2731
/// The current operating system version.
32+
///
33+
/// The value is an empty String if it is not available.
2834
final String systemVersion;
2935

3036
/// Device model.
37+
///
38+
/// The value is an empty String if it is not available.
3139
final String model;
3240

3341
/// Localized name of the device model.
42+
///
43+
/// The value is an empty String if it is not available.
3444
final String localizedModel;
3545

3646
/// Unique UUID value identifying the current device.
47+
///
48+
/// The value is an empty String if it is not available.
3749
final String identifierForVendor;
3850

39-
/// `false` if the application is running in a simulator, `true` otherwise.
51+
/// The value is `true` if the application is running on a physical device.
52+
///
53+
/// The value is `false` when the application is running on a simulator, or the value is unavailable.
4054
final bool isPhysicalDevice;
4155

4256
/// Operating system information derived from `sys/utsname.h`.
57+
///
58+
/// The value is an empty String if it is not available.
4359
final IosUtsname utsname;
4460

4561
/// Deserializes from the map message received from [_kChannel].
4662
static IosDeviceInfo fromMap(Map<String, dynamic> map) {
4763
return IosDeviceInfo(
48-
name: map['name']!,
49-
systemName: map['systemName']!,
50-
systemVersion: map['systemVersion']!,
51-
model: map['model']!,
52-
localizedModel: map['localizedModel']!,
53-
identifierForVendor: map['identifierForVendor']!,
54-
isPhysicalDevice: map['isPhysicalDevice'] == 'true',
55-
utsname: IosUtsname._fromMap(map['utsname']!.cast<String, dynamic>()),
64+
name: map['name'] ?? '',
65+
systemName: map['systemName'] ?? '',
66+
systemVersion: map['systemVersion'] ?? '',
67+
model: map['model'] ?? '',
68+
localizedModel: map['localizedModel'] ?? '',
69+
identifierForVendor: map['identifierForVendor'] ?? '',
70+
isPhysicalDevice: map['isPhysicalDevice'] != null
71+
? map['isPhysicalDevice'] == 'true'
72+
: false,
73+
utsname: IosUtsname._fromMap(map['utsname'] != null
74+
? map['utsname'].cast<String, dynamic>()
75+
: <String, dynamic>{}),
5676
);
5777
}
5878
}
@@ -69,28 +89,38 @@ class IosUtsname {
6989
});
7090

7191
/// Operating system name.
92+
///
93+
/// The value is an empty String if it is not available.
7294
final String sysname;
7395

7496
/// Network node name.
97+
///
98+
/// The value is an empty String if it is not available.
7599
final String nodename;
76100

77101
/// Release level.
102+
///
103+
/// The value is an empty String if it is not available.
78104
final String release;
79105

80106
/// Version level.
107+
///
108+
/// The value is an empty String if it is not available.
81109
final String version;
82110

83111
/// Hardware type (e.g. 'iPhone7,1' for iPhone 6 Plus).
112+
///
113+
/// The value is an empty String if it is not available.
84114
final String machine;
85115

86116
/// Deserializes from the map message received from [_kChannel].
87117
static IosUtsname _fromMap(Map<String, dynamic> map) {
88118
return IosUtsname._(
89-
sysname: map['sysname']!,
90-
nodename: map['nodename']!,
91-
release: map['release']!,
92-
version: map['version']!,
93-
machine: map['machine']!,
119+
sysname: map['sysname'] ?? '',
120+
nodename: map['nodename'] ?? '',
121+
release: map['release'] ?? '',
122+
version: map['version'] ?? '',
123+
machine: map['machine'] ?? '',
94124
);
95125
}
96126
}

0 commit comments

Comments
 (0)