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