xref: /expo/packages/expo-device/src/Device.ts (revision a000174d)
1import { UnavailabilityError } from 'expo-modules-core';
2
3import { DeviceType } from './Device.types';
4import ExpoDevice from './ExpoDevice';
5
6export { DeviceType };
7
8/**
9 * `true` if the app is running on a real device and `false` if running in a simulator or emulator.
10 * On web, this is always set to `true`.
11 */
12export const isDevice: boolean = ExpoDevice ? ExpoDevice.isDevice : true;
13
14/**
15 * The device brand. The consumer-visible brand of the product/hardware. On web, this value is always `null`.
16 *
17 * @example
18 * ```js
19 * Device.brand; // Android: "google", "xiaomi"; iOS: "Apple"; web: null
20 * ```
21 * @platform android
22 * @platform ios
23 */
24export const brand: string | null = ExpoDevice ? ExpoDevice.brand : null;
25
26/**
27 * The actual device manufacturer of the product or hardware. This value of this field may be `null` if it cannot be determined.
28 *
29 * To view difference between `brand` and `manufacturer` on Android see [official documentation](https://developer.android.com/reference/android/os/Build).
30 *
31 * @example
32 * ```js
33 * Device.manufacturer; // Android: "Google", "xiaomi"; iOS: "Apple"; web: "Google", null
34 * ```
35 */
36export const manufacturer: string | null = ExpoDevice ? ExpoDevice.manufacturer : null;
37
38/**
39 * The internal model ID of the device. This is useful for programmatically identifying the type of device and is not a human-friendly string.
40 * On web and Android, this value is always `null`.
41 *
42 * @example
43 * ```js
44 * Device.modelId; // iOS: "iPhone7,2"; Android: null; web: null
45 * ```
46 * @platform ios
47 */
48export const modelId = ExpoDevice ? ExpoDevice.modelId || null : null;
49
50/**
51 * The human-friendly name of the device model. This is the name that people would typically use to refer to the device rather than a programmatic model identifier.
52 * This value of this field may be `null` if it cannot be determined.
53 *
54 * @example
55 * ```js
56 * Device.modelName; // Android: "Pixel 2"; iOS: "iPhone XS Max"; web: "iPhone", null
57 * ```
58 */
59export const modelName: string | null = ExpoDevice ? ExpoDevice.modelName : null;
60
61/**
62 * The specific configuration or name of the industrial design. It represents the device's name when it was designed during manufacturing into mass production.
63 * On Android, it corresponds to [`Build.DEVICE`](https://developer.android.com/reference/android/os/Build#DEVICE). On web and iOS, this value is always `null`.
64 *
65 * @example
66 * ```js
67 * Device.designName; // Android: "kminilte"; iOS: null; web: null
68 * ```
69 * @platform android
70 */
71export const designName: string | null = ExpoDevice ? ExpoDevice.designName || null : null;
72
73/**
74 * The device's overall product name chosen by the device implementer containing the development name or code name of the device.
75 * Corresponds to [`Build.PRODUCT`](https://developer.android.com/reference/android/os/Build#PRODUCT). On web and iOS, this value is always `null`.
76 *
77 * @example
78 * ```js
79 * Device.productName; // Android: "kminiltexx"; iOS: null; web: null
80 * ```
81 * @platform android
82 */
83export const productName: string | null = ExpoDevice ? ExpoDevice.productName || null : null;
84
85/**
86 * The type of the device as a [`DeviceType`](#devicetype) enum value.
87 *
88 * On Android, for devices other than TVs, the device type is determined by the screen resolution (screen diagonal size), so the result may not be completely accurate.
89 * If the screen diagonal length is between 3" and 6.9", the method returns `DeviceType.PHONE`. For lengths between 7" and 18", the method returns `DeviceType.TABLET`.
90 * Otherwise, the method returns `DeviceType.UNKNOWN`.
91 *
92 * @example
93 * ```js
94 * Device.deviceType; // UNKNOWN, PHONE, TABLET, TV, DESKTOP
95 * ```
96 */
97export const deviceType: DeviceType | null = ExpoDevice ? ExpoDevice.deviceType : null;
98
99/**
100 * The [device year class](https://github.com/facebook/device-year-class) of this device. On web, this value is always `null`.
101 */
102export const deviceYearClass: number | null = ExpoDevice ? ExpoDevice.deviceYearClass : null;
103
104/**
105 * The device's total memory, in bytes. This is the total memory accessible to the kernel, but not necessarily to a single app.
106 * This is basically the amount of RAM the device has, not including below-kernel fixed allocations like DMA buffers, RAM for the baseband CPU, etc…
107 * On web, this value is always `null`.
108 *
109 * @example
110 * ```js
111 * Device.totalMemory; // 17179869184
112 * ```
113 */
114export const totalMemory: number | null = ExpoDevice ? ExpoDevice.totalMemory : null;
115
116/**
117 * A list of supported processor architecture versions. The device expects the binaries it runs to be compiled for one of these architectures.
118 * This value is `null` if the supported architectures could not be determined, particularly on web.
119 *
120 * @example
121 * ```js
122 * Device.supportedCpuArchitectures; // ['arm64 v8', 'Intel x86-64h Haswell', 'arm64-v8a', 'armeabi-v7a", 'armeabi']
123 * ```
124 */
125export const supportedCpuArchitectures: string[] | null = ExpoDevice
126  ? ExpoDevice.supportedCpuArchitectures
127  : null;
128
129/**
130 * The name of the OS running on the device.
131 *
132 * @example
133 * ```js
134 * Device.osName; // Android: "Android"; iOS: "iOS" or "iPadOS"; web: "iOS", "Android", "Windows"
135 * ```
136 */
137export const osName: string | null = ExpoDevice ? ExpoDevice.osName : null;
138
139/**
140 * The human-readable OS version string. Note that the version string may not always contain three numbers separated by dots.
141 *
142 * @example
143 * ```js
144 * Device.osVersion; // Android: "4.0.3"; iOS: "12.3.1"; web: "11.0", "8.1.0"
145 * ```
146 */
147export const osVersion: string | null = ExpoDevice ? ExpoDevice.osVersion : null;
148
149/**
150 * The build ID of the OS that more precisely identifies the version of the OS. On Android, this corresponds to `Build.DISPLAY` (not `Build.ID`)
151 * and currently is a string as described [here](https://source.android.com/setup/start/build-numbers). On iOS, this corresponds to `kern.osversion`
152 * and is the detailed OS version sometimes displayed next to the more human-readable version. On web, this value is always `null`.
153 *
154 * @example
155 * ```js
156 * Device.osBuildId; // Android: "PSR1.180720.075"; iOS: "16F203"; web: null
157 * ```
158 */
159export const osBuildId: string | null = ExpoDevice ? ExpoDevice.osBuildId : null;
160
161/**
162 * The internal build ID of the OS running on the device. On Android, this corresponds to `Build.ID`.
163 * On iOS, this is the same value as [`Device.osBuildId`](#deviceosbuildid). On web, this value is always `null`.
164 *
165 * @example
166 * ```js
167 * Device.osInternalBuildId; // Android: "MMB29K"; iOS: "16F203"; web: null,
168 * ```
169 */
170export const osInternalBuildId: string | null = ExpoDevice ? ExpoDevice.osInternalBuildId : null;
171
172/**
173 * A string that uniquely identifies the build of the currently running system OS. On Android, it follows this template:
174 * - `$(BRAND)/$(PRODUCT)/$(DEVICE)/$(BOARD):$(VERSION.RELEASE)/$(ID)/$(VERSION.INCREMENTAL):$(TYPE)/\$(TAGS)`
175 * On web and iOS, this value is always `null`.
176 *
177 * @example
178 * ```js
179 * Device.osBuildFingerprint;
180 * // Android: "google/sdk_gphone_x86/generic_x86:9/PSR1.180720.075/5124027:user/release-keys";
181 * // iOS: null; web: null
182 * ```
183 * @platform android
184 */
185export const osBuildFingerprint: string | null = ExpoDevice
186  ? ExpoDevice.osBuildFingerprint || null
187  : null;
188
189/**
190 * The Android SDK version of the software currently running on this hardware device. This value never changes while a device is booted,
191 * but it may increase when the hardware manufacturer provides an OS update. See [here](https://developer.android.com/reference/android/os/Build.VERSION_CODES.html)
192 * to see all possible version codes and corresponding versions. On iOS and web, this value is always `null`.
193 *
194 * @example
195 * ```js
196 * Device.platformApiLevel; // Android: 19; iOS: null; web: null
197 * ```
198 * @platform android
199 */
200export const platformApiLevel: number | null = ExpoDevice
201  ? ExpoDevice.platformApiLevel || null
202  : null;
203
204/**
205 * The human-readable name of the device, which may be set by the device's user. If the device name is unavailable, particularly on web, this value is `null`.
206 *
207 * > On iOS 16 and newer, this value will be set to generic "iPhone" until you add the correct entitlement, see [iOS Capabilities page](/build-reference/ios-capabilities)
208 * > to learn how to add one and check out [Apple documentation](https://developer.apple.com/documentation/uikit/uidevice/1620015-name#discussion)
209 * > for more details on this change.
210 *
211 * @example
212 * ```js
213 * Device.deviceName; // "Vivian's iPhone XS"
214 * ```
215 */
216export const deviceName: string | null = ExpoDevice ? ExpoDevice.deviceName : null;
217
218/**
219 * Checks the type of the device as a [`DeviceType`](#devicetype) enum value.
220 *
221 * On Android, for devices other than TVs, the device type is determined by the screen resolution (screen diagonal size), so the result may not be completely accurate.
222 * If the screen diagonal length is between 3" and 6.9", the method returns `DeviceType.PHONE`. For lengths between 7" and 18", the method returns `DeviceType.TABLET`.
223 * Otherwise, the method returns `DeviceType.UNKNOWN`.
224 *
225 * @return Returns a promise that resolves to a [`DeviceType`](#devicetype) enum value.
226 * @example
227 * ```js
228 * await Device.getDeviceTypeAsync();
229 * // DeviceType.PHONE
230 * ```
231 */
232export async function getDeviceTypeAsync(): Promise<DeviceType> {
233  if (!ExpoDevice.getDeviceTypeAsync) {
234    throw new UnavailabilityError('expo-device', 'getDeviceTypeAsync');
235  }
236  return await ExpoDevice.getDeviceTypeAsync();
237}
238
239/**
240 * Gets the uptime since the last reboot of the device, in milliseconds. Android devices do not count time spent in deep sleep.
241 * @return Returns a promise that resolves to a `number` that represents the milliseconds since last reboot.
242 * @example
243 * ```js
244 * await Device.getUptimeAsync();
245 * // 4371054
246 * ```
247 * @platform android
248 * @platform ios
249 */
250export async function getUptimeAsync(): Promise<number> {
251  if (!ExpoDevice.getUptimeAsync) {
252    throw new UnavailabilityError('expo-device', 'getUptimeAsync');
253  }
254  return await ExpoDevice.getUptimeAsync();
255}
256
257/**
258 * Returns the maximum amount of memory that the Java VM will attempt to use. If there is no inherent limit then `Number.MAX_SAFE_INTEGER` is returned.
259 * @return Returns a promise that resolves to the maximum available memory that the Java VM will use, in bytes.
260 * @example
261 * ```js
262 * await Device.getMaxMemoryAsync();
263 * // 402653184
264 * ```
265 * @platform android
266 */
267export async function getMaxMemoryAsync(): Promise<number> {
268  if (!ExpoDevice.getMaxMemoryAsync) {
269    throw new UnavailabilityError('expo-device', 'getMaxMemoryAsync');
270  }
271  let maxMemory = await ExpoDevice.getMaxMemoryAsync();
272  if (maxMemory === -1) {
273    maxMemory = Number.MAX_SAFE_INTEGER;
274  }
275  return maxMemory;
276}
277
278/**
279 * > **warning** This method is experimental and is not completely reliable. See description below.
280 *
281 * Checks whether the device has been rooted (Android) or jailbroken (iOS). This is not completely reliable because there exist solutions to bypass root-detection
282 * on both [iOS](https://www.theiphonewiki.com/wiki/XCon) and [Android](https://tweakerlinks.com/how-to-bypass-apps-root-detection-in-android-device/).
283 * Further, many root-detection checks can be bypassed via reverse engineering.
284 * - On Android, it's implemented in a way to find all possible files paths that contain the `"su"` executable but some devices that are not rooted may also have this executable. Therefore, there's no guarantee that this method will always return correctly.
285 * - On iOS, [these jailbreak checks](https://www.theiphonewiki.com/wiki/Bypassing_Jailbreak_Detection) are used to detect if a device is rooted/jailbroken. However, since there are closed-sourced solutions such as [xCon](https://www.theiphonewiki.com/wiki/XCon) that aim to hook every known method and function responsible for informing an application of a jailbroken device, this method may not reliably detect devices that have xCon or similar packages installed.
286 * - On web, this always resolves to `false` even if the device is rooted.
287 * @return Returns a promise that resolves to a `boolean` that specifies whether this device is rooted.
288 * @example
289 * ```js
290 * await Device.isRootedExperimentalAsync();
291 * // true or false
292 * ```
293 */
294export async function isRootedExperimentalAsync(): Promise<boolean> {
295  if (!ExpoDevice.isRootedExperimentalAsync) {
296    throw new UnavailabilityError('expo-device', 'isRootedExperimentalAsync');
297  }
298  return await ExpoDevice.isRootedExperimentalAsync();
299}
300
301/**
302 * **Using this method requires you to [add the `REQUEST_INSTALL_PACKAGES` permission](./../config/app/#permissions).**
303 * Returns whether applications can be installed for this user via the system's [`ACTION_INSTALL_PACKAGE`](https://developer.android.com/reference/android/content/Intent.html#ACTION_INSTALL_PACKAGE)
304 * mechanism rather than through the OS's default app store, like Google Play.
305 * @return Returns a promise that resolves to a `boolean` that represents whether the calling package is allowed to request package installation.
306 * @example
307 * ```js
308 * await Device.isSideLoadingEnabledAsync();
309 * // true or false
310 * ```
311 * @platform android
312 */
313export async function isSideLoadingEnabledAsync(): Promise<boolean> {
314  if (!ExpoDevice.isSideLoadingEnabledAsync) {
315    throw new UnavailabilityError('expo-device', 'isSideLoadingEnabledAsync');
316  }
317  return await ExpoDevice.isSideLoadingEnabledAsync();
318}
319
320/**
321 * Gets a list of features that are available on the system. The feature names are platform-specific.
322 * See [Android documentation](<https://developer.android.com/reference/android/content/pm/PackageManager#getSystemAvailableFeatures()>)
323 * to learn more about this implementation.
324 * @return Returns a promise that resolves to an array of strings, each of which is a platform-specific name of a feature available on the current device.
325 * On iOS and web, the promise always resolves to an empty array.
326 * @example
327 * ```js
328 * await Device.getPlatformFeaturesAsync();
329 * // [
330 * //   'android.software.adoptable_storage',
331 * //   'android.software.backup',
332 * //   'android.hardware.sensor.accelerometer',
333 * //   'android.hardware.touchscreen',
334 * // ]
335 * ```
336 * @platform android
337 */
338export async function getPlatformFeaturesAsync(): Promise<string[]> {
339  if (!ExpoDevice.getPlatformFeaturesAsync) {
340    return [];
341  }
342  return await ExpoDevice.getPlatformFeaturesAsync();
343}
344
345/**
346 * Tells if the device has a specific system feature.
347 * @param feature The platform-specific name of the feature to check for on the device. You can get all available system features with `Device.getSystemFeatureAsync()`.
348 * See [Android documentation](<https://developer.android.com/reference/android/content/pm/PackageManager#hasSystemFeature(java.lang.String)>) to view acceptable feature strings.
349 * @return Returns a promise that resolves to a boolean value indicating whether the device has the specified system feature.
350 * On iOS and web, the promise always resolves to `false`.
351 * @example
352 * ```js
353 * await Device.hasPlatformFeatureAsync('amazon.hardware.fire_tv');
354 * // true or false
355 * ```
356 * @platform android
357 */
358export async function hasPlatformFeatureAsync(feature: string): Promise<boolean> {
359  if (!ExpoDevice.hasPlatformFeatureAsync) {
360    return false;
361  }
362  return await ExpoDevice.hasPlatformFeatureAsync(feature);
363}
364