@symbiote-native/device 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/build/angular/index.d.ts +1 -0
- package/build/angular/index.js +4 -0
- package/build/core/device.d.ts +138 -0
- package/build/core/device.js +194 -0
- package/build/core/index.d.ts +2 -0
- package/build/core/index.js +2 -0
- package/build/core/native-module.d.ts +29 -0
- package/build/core/native-module.js +4 -0
- package/build/core/types.d.ts +13 -0
- package/build/core/types.js +17 -0
- package/build/react/index.d.ts +1 -0
- package/build/react/index.js +6 -0
- package/build/vue/index.d.ts +1 -0
- package/build/vue/index.js +4 -0
- package/build-ngc/angular/index.d.ts +1 -0
- package/build-ngc/angular/index.js +5 -0
- package/build-ngc/angular/index.js.map +1 -0
- package/build-ngc/core/device.d.ts +138 -0
- package/build-ngc/core/device.js +195 -0
- package/build-ngc/core/device.js.map +1 -0
- package/build-ngc/core/index.d.ts +2 -0
- package/build-ngc/core/index.js +3 -0
- package/build-ngc/core/index.js.map +1 -0
- package/build-ngc/core/native-module.d.ts +29 -0
- package/build-ngc/core/native-module.js +5 -0
- package/build-ngc/core/native-module.js.map +1 -0
- package/build-ngc/core/types.d.ts +13 -0
- package/build-ngc/core/types.js +18 -0
- package/build-ngc/core/types.js.map +1 -0
- package/native-link.json +12 -0
- package/package.json +107 -0
- package/src/angular/index.ts +4 -0
- package/src/core/device.test.ts +202 -0
- package/src/core/device.ts +222 -0
- package/src/core/index.ts +28 -0
- package/src/core/native-module.ts +42 -0
- package/src/core/types.ts +17 -0
- package/src/react/index.ts +6 -0
- package/src/vue/index.ts +4 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 A. Prokopenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# @symbiote-native/device
|
|
2
|
+
|
|
3
|
+
A wrapper package for [SymbioteNative](../../README.md) that makes
|
|
4
|
+
[`expo-device`](https://github.com/expo/expo/tree/main/packages/expo-device)
|
|
5
|
+
— physical device information: brand/model/OS constants, uptime, max-memory,
|
|
6
|
+
root/jailbreak detection, side-loading detection, and platform-feature queries — usable from
|
|
7
|
+
**every** adapter, React, Vue, and Angular, not just React. Like
|
|
8
|
+
[`@symbiote-native/local-auth`](../local-auth) and unlike this repo's stateful Expo wrapper
|
|
9
|
+
([`@symbiote-native/sensors`](../sensors), an `EventEmitter` + live-subscription surface), every
|
|
10
|
+
export here is either an eagerly-resolved constant or a one-shot async call with no per-instance
|
|
11
|
+
state, so there is no hook/composable/service to wrap — the React, Vue, and Angular entry points
|
|
12
|
+
are plain re-exports of the same `core`.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @symbiote-native/device
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`expo-device` and `expo-modules-core` come along as regular dependencies, pinned to exact
|
|
21
|
+
versions — never install either yourself, and never add the `expo` meta-package to your project
|
|
22
|
+
(it bundles its own Metro/Babel pipeline, which conflicts with this project's own).
|
|
23
|
+
|
|
24
|
+
## Required one-time step: native autolinking wiring
|
|
25
|
+
|
|
26
|
+
Unlike a plain RN native module, `expo-device`'s native code is discovered by
|
|
27
|
+
`expo-modules-autolinking`, not RN's own `react-native.config.cjs` mechanism — this needs wiring
|
|
28
|
+
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
29
|
+
package with zero further changes:
|
|
30
|
+
|
|
31
|
+
| Platform | Touches |
|
|
32
|
+
|---|---|
|
|
33
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
34
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
35
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
36
|
+
| Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
|
|
37
|
+
|
|
38
|
+
Full mechanics live in the `symbiote-expo-native-module` project skill. Reference
|
|
39
|
+
implementation: `examples/expo-react/ios/Podfile` and
|
|
40
|
+
`examples/expo-react/android/app/src/main/java/com/canaryexpo/MainApplication.kt`.
|
|
41
|
+
|
|
42
|
+
`expo-device` needs no runtime permission on either platform — every constant and function here
|
|
43
|
+
reads plain system/build information, nothing gated by a permission prompt.
|
|
44
|
+
|
|
45
|
+
## Shape
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
src/core/ Eager constants (isDevice, brand, manufacturer, modelId, modelName, designName,
|
|
49
|
+
productName, deviceType, deviceYearClass, totalMemory,
|
|
50
|
+
supportedCpuArchitectures, osName, osVersion, osBuildId, osInternalBuildId,
|
|
51
|
+
osBuildFingerprint, platformApiLevel, deviceName), plus getDeviceTypeAsync /
|
|
52
|
+
getUptimeAsync / getMaxMemoryAsync / isRootedExperimentalAsync /
|
|
53
|
+
isSideLoadingEnabledAsync / getPlatformFeaturesAsync / hasPlatformFeatureAsync,
|
|
54
|
+
and the DeviceType enum. native-module.ts resolves the native module via
|
|
55
|
+
expo-modules-core's requireNativeModule.
|
|
56
|
+
src/react/ @symbiote-native/device/react — export * from '../core'
|
|
57
|
+
src/vue/ @symbiote-native/device/vue — export * from '../core'
|
|
58
|
+
src/angular/ @symbiote-native/device/angular — export * from '../core'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
No per-adapter lifecycle wrapper exists because there's nothing to subscribe to or clean up —
|
|
62
|
+
each adapter entry is a single-file re-export.
|
|
63
|
+
|
|
64
|
+
## Use it
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
// React
|
|
68
|
+
import { useEffect, useState } from 'react';
|
|
69
|
+
import { Text, View } from '@symbiote-native/react';
|
|
70
|
+
import {
|
|
71
|
+
brand,
|
|
72
|
+
deviceName,
|
|
73
|
+
getMaxMemoryAsync,
|
|
74
|
+
getUptimeAsync,
|
|
75
|
+
isDevice,
|
|
76
|
+
modelName,
|
|
77
|
+
osName,
|
|
78
|
+
osVersion,
|
|
79
|
+
} from '@symbiote-native/device/react';
|
|
80
|
+
|
|
81
|
+
function DeviceScreen() {
|
|
82
|
+
const [uptime, setUptime] = useState<number | null>(null);
|
|
83
|
+
const [maxMemory, setMaxMemory] = useState<number | null>(null);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
getUptimeAsync().then(setUptime);
|
|
87
|
+
getMaxMemoryAsync().then(setMaxMemory);
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<View>
|
|
92
|
+
<Text>{isDevice ? 'Real device' : 'Simulator/emulator'}</Text>
|
|
93
|
+
<Text>{`${brand ?? 'unknown'} ${modelName ?? ''}`}</Text>
|
|
94
|
+
<Text>{`${osName ?? 'unknown OS'} ${osVersion ?? ''}`}</Text>
|
|
95
|
+
<Text>{deviceName ?? 'unnamed device'}</Text>
|
|
96
|
+
<Text>{uptime === null ? 'checking uptime…' : `Uptime: ${uptime}ms`}</Text>
|
|
97
|
+
<Text>{maxMemory === null ? 'checking memory…' : `Max memory: ${maxMemory} bytes`}</Text>
|
|
98
|
+
</View>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```vue
|
|
104
|
+
<!-- Vue -->
|
|
105
|
+
<script setup lang="ts">
|
|
106
|
+
import { onMounted, ref } from 'vue';
|
|
107
|
+
import { Text, View } from '@symbiote-native/vue';
|
|
108
|
+
import {
|
|
109
|
+
brand,
|
|
110
|
+
deviceName,
|
|
111
|
+
getMaxMemoryAsync,
|
|
112
|
+
getUptimeAsync,
|
|
113
|
+
isDevice,
|
|
114
|
+
modelName,
|
|
115
|
+
osName,
|
|
116
|
+
osVersion,
|
|
117
|
+
} from '@symbiote-native/device/vue';
|
|
118
|
+
|
|
119
|
+
const uptime = ref<number | null>(null);
|
|
120
|
+
const maxMemory = ref<number | null>(null);
|
|
121
|
+
|
|
122
|
+
onMounted(() => {
|
|
123
|
+
void getUptimeAsync().then(value => (uptime.value = value));
|
|
124
|
+
void getMaxMemoryAsync().then(value => (maxMemory.value = value));
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
|
|
128
|
+
<template>
|
|
129
|
+
<View>
|
|
130
|
+
<Text>{{ isDevice ? 'Real device' : 'Simulator/emulator' }}</Text>
|
|
131
|
+
<Text>{{ `${brand ?? 'unknown'} ${modelName ?? ''}` }}</Text>
|
|
132
|
+
<Text>{{ `${osName ?? 'unknown OS'} ${osVersion ?? ''}` }}</Text>
|
|
133
|
+
<Text>{{ deviceName ?? 'unnamed device' }}</Text>
|
|
134
|
+
<Text>{{ uptime === null ? 'checking uptime…' : `Uptime: ${uptime}ms` }}</Text>
|
|
135
|
+
<Text>{{ maxMemory === null ? 'checking memory…' : `Max memory: ${maxMemory} bytes` }}</Text>
|
|
136
|
+
</View>
|
|
137
|
+
</template>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// Angular
|
|
142
|
+
import { Component, signal } from '@angular/core';
|
|
143
|
+
import { Text, View } from '@symbiote-native/angular';
|
|
144
|
+
import {
|
|
145
|
+
brand,
|
|
146
|
+
deviceName,
|
|
147
|
+
getMaxMemoryAsync,
|
|
148
|
+
getUptimeAsync,
|
|
149
|
+
isDevice,
|
|
150
|
+
modelName,
|
|
151
|
+
osName,
|
|
152
|
+
osVersion,
|
|
153
|
+
} from '@symbiote-native/device/angular';
|
|
154
|
+
|
|
155
|
+
@Component({
|
|
156
|
+
standalone: true,
|
|
157
|
+
imports: [Text, View],
|
|
158
|
+
template: `
|
|
159
|
+
<View>
|
|
160
|
+
<Text>{{ isDevice ? 'Real device' : 'Simulator/emulator' }}</Text>
|
|
161
|
+
<Text>{{ brand ?? 'unknown' }} {{ modelName ?? '' }}</Text>
|
|
162
|
+
<Text>{{ osName ?? 'unknown OS' }} {{ osVersion ?? '' }}</Text>
|
|
163
|
+
<Text>{{ deviceName ?? 'unnamed device' }}</Text>
|
|
164
|
+
<Text>{{ uptime() === null ? 'checking uptime…' : 'Uptime: ' + uptime() + 'ms' }}</Text>
|
|
165
|
+
<Text>{{ maxMemory() === null ? 'checking memory…' : 'Max memory: ' + maxMemory() + ' bytes' }}</Text>
|
|
166
|
+
</View>
|
|
167
|
+
`,
|
|
168
|
+
})
|
|
169
|
+
export class DeviceScreen {
|
|
170
|
+
readonly isDevice = isDevice;
|
|
171
|
+
readonly brand = brand;
|
|
172
|
+
readonly modelName = modelName;
|
|
173
|
+
readonly osName = osName;
|
|
174
|
+
readonly osVersion = osVersion;
|
|
175
|
+
readonly deviceName = deviceName;
|
|
176
|
+
|
|
177
|
+
readonly uptime = signal<number | null>(null);
|
|
178
|
+
readonly maxMemory = signal<number | null>(null);
|
|
179
|
+
|
|
180
|
+
constructor() {
|
|
181
|
+
getUptimeAsync().then(value => this.uptime.set(value));
|
|
182
|
+
getMaxMemoryAsync().then(value => this.maxMemory.set(value));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
There's no per-instance service to `inject()` in the Angular case — every constant/function is a
|
|
188
|
+
plain export off the core package, read straight in the constructor or class-field initializer.
|
|
189
|
+
These snippets are not yet demoed in a real canary screen — no `DeviceScreen.*` exists yet in
|
|
190
|
+
`examples/expo-*` — so treat them as realistic reference code, not a trimmed-down copy of a
|
|
191
|
+
running demo.
|
|
192
|
+
|
|
193
|
+
## API
|
|
194
|
+
|
|
195
|
+
Eagerly-resolved constants, plus a handful of one-shot async functions — no event stream, no
|
|
196
|
+
per-instance state — so the React/Vue/Angular entry points above are plain re-exports of `core`
|
|
197
|
+
with nothing adapter-specific to add.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
// Constants — resolved once, at import time, straight off the native module:
|
|
201
|
+
isDevice: boolean
|
|
202
|
+
brand: string | null
|
|
203
|
+
manufacturer: string | null
|
|
204
|
+
modelId: string | null // iOS only
|
|
205
|
+
modelName: string | null
|
|
206
|
+
designName: string | null // Android only
|
|
207
|
+
productName: string | null // Android only
|
|
208
|
+
deviceType: DeviceType | null
|
|
209
|
+
deviceYearClass: number | null
|
|
210
|
+
totalMemory: number | null
|
|
211
|
+
supportedCpuArchitectures: string[] | null
|
|
212
|
+
osName: string | null
|
|
213
|
+
osVersion: string | null
|
|
214
|
+
osBuildId: string | null
|
|
215
|
+
osInternalBuildId: string | null
|
|
216
|
+
osBuildFingerprint: string | null // Android only
|
|
217
|
+
platformApiLevel: number | null // Android only
|
|
218
|
+
deviceName: string | null
|
|
219
|
+
|
|
220
|
+
// Functions:
|
|
221
|
+
getDeviceTypeAsync(): Promise<DeviceType>
|
|
222
|
+
getUptimeAsync(): Promise<number> // Android + iOS
|
|
223
|
+
getMaxMemoryAsync(): Promise<number> // Android only; -1 sentinel normalized to Number.MAX_SAFE_INTEGER
|
|
224
|
+
isRootedExperimentalAsync(): Promise<boolean> // best-effort root/jailbreak check
|
|
225
|
+
isSideLoadingEnabledAsync(): Promise<boolean> // Android only
|
|
226
|
+
getPlatformFeaturesAsync(): Promise<string[]> // Android only; [] elsewhere, never throws
|
|
227
|
+
hasPlatformFeatureAsync(feature: string): Promise<boolean> // Android only; false elsewhere, never throws
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Plus `DeviceType` (`UNKNOWN`/`PHONE`/`TABLET`/`DESKTOP`/`TV`) — ported from upstream's
|
|
231
|
+
`Device.types.ts`.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { getDeviceTypeAsync, isDevice } from '@symbiote-native/device';
|
|
235
|
+
// or the framework-scoped entry points — identical surface, re-exported verbatim:
|
|
236
|
+
import { getDeviceTypeAsync } from '@symbiote-native/device/react';
|
|
237
|
+
import { getDeviceTypeAsync } from '@symbiote-native/device/vue';
|
|
238
|
+
import { getDeviceTypeAsync } from '@symbiote-native/device/angular';
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Notes
|
|
242
|
+
|
|
243
|
+
- **Every function except `getPlatformFeaturesAsync`/`hasPlatformFeatureAsync` throws an
|
|
244
|
+
`UnavailabilityError` when the native method is missing.** Those two are the deliberate
|
|
245
|
+
exceptions — they resolve to `[]`/`false` instead, matching upstream, since a platform-feature
|
|
246
|
+
query on a platform with no such concept (iOS) is a normal "no" answer, not an error.
|
|
247
|
+
- **`getMaxMemoryAsync`'s `-1` native sentinel means "no inherent limit"** and is normalized to
|
|
248
|
+
`Number.MAX_SAFE_INTEGER` before it reaches your code — you never see the raw `-1`.
|
|
249
|
+
- **`isRootedExperimentalAsync` is a best-effort check, not a guarantee** — root/jailbreak
|
|
250
|
+
detection bypasses exist on both platforms; a `false` result does not prove the device is
|
|
251
|
+
unmodified.
|
|
252
|
+
|
|
253
|
+
## Test it
|
|
254
|
+
|
|
255
|
+
No Fabric/Descriptor angle at all — every export here is a pure constant or async-function
|
|
256
|
+
surface, never a view or per-instance state. Tests inject a fake native-module object in place of
|
|
257
|
+
the real `requireNativeModule` resolution (`src/core/device.test.ts`, `vitest`) — no
|
|
258
|
+
`installFabric()`, no ViewConfig. Native rendering itself is verified on-device (see the parent
|
|
259
|
+
[README](../../README.md) for the project's testing model).
|
|
260
|
+
|
|
261
|
+
Native autolinking wiring for `expo-modules-core` packages is already done in the four Expo
|
|
262
|
+
canary apps (`examples/expo-react`, `examples/expo-vue-sfc`, `examples/expo-vue-tsx`,
|
|
263
|
+
`examples/expo-angular`) via `@symbiote-native/local-auth`/`@symbiote-native/sensors` — this
|
|
264
|
+
package reuses that same wiring with zero further app-side changes, since
|
|
265
|
+
`expo-modules-autolinking` discovers any `expo-modules-core` package already present in
|
|
266
|
+
`node_modules`. A dedicated `DeviceScreen` demo has not been wired into those canaries yet.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../core';
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { DeviceType } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `true` if the app is running on a real device and `false` if running in a simulator or
|
|
4
|
+
* emulator.
|
|
5
|
+
*/
|
|
6
|
+
export declare const isDevice: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The device brand. The consumer-visible brand of the product/hardware.
|
|
9
|
+
* @example Device.brand; // Android: "google", "xiaomi"; iOS: "Apple"
|
|
10
|
+
*/
|
|
11
|
+
export declare const brand: string | null;
|
|
12
|
+
/**
|
|
13
|
+
* The actual device manufacturer of the product or hardware. May be `null` if it cannot be
|
|
14
|
+
* determined.
|
|
15
|
+
*/
|
|
16
|
+
export declare const manufacturer: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* The internal model ID of the device — useful for programmatically identifying the type of
|
|
19
|
+
* device, not a human-friendly string.
|
|
20
|
+
* @platform ios
|
|
21
|
+
*/
|
|
22
|
+
export declare const modelId: string | null;
|
|
23
|
+
/**
|
|
24
|
+
* The human-friendly name of the device model. May be `null` if it cannot be determined.
|
|
25
|
+
* @example Device.modelName; // Android: "Pixel 2"; iOS: "iPhone XS Max"
|
|
26
|
+
*/
|
|
27
|
+
export declare const modelName: string | null;
|
|
28
|
+
/**
|
|
29
|
+
* The specific configuration or name of the industrial design — the device's name when it was
|
|
30
|
+
* designed during manufacturing into mass production. Corresponds to `Build.DEVICE`.
|
|
31
|
+
* @platform android
|
|
32
|
+
*/
|
|
33
|
+
export declare const designName: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* The device's overall product name chosen by the device implementer, containing the
|
|
36
|
+
* development name or code name of the device. Corresponds to `Build.PRODUCT`.
|
|
37
|
+
* @platform android
|
|
38
|
+
*/
|
|
39
|
+
export declare const productName: string | null;
|
|
40
|
+
/**
|
|
41
|
+
* The type of the device as a {@link DeviceType} enum value.
|
|
42
|
+
*/
|
|
43
|
+
export declare const deviceType: DeviceType | null;
|
|
44
|
+
/** The device year class (https://github.com/facebook/device-year-class) of this device. */
|
|
45
|
+
export declare const deviceYearClass: number | null;
|
|
46
|
+
/**
|
|
47
|
+
* The device's total memory, in bytes — the total memory accessible to the kernel, but not
|
|
48
|
+
* necessarily to a single app.
|
|
49
|
+
*/
|
|
50
|
+
export declare const totalMemory: number | null;
|
|
51
|
+
/**
|
|
52
|
+
* A list of supported processor architecture versions. `null` if the supported architectures
|
|
53
|
+
* could not be determined.
|
|
54
|
+
*/
|
|
55
|
+
export declare const supportedCpuArchitectures: string[] | null;
|
|
56
|
+
/**
|
|
57
|
+
* The name of the OS running on the device.
|
|
58
|
+
* @example Device.osName; // Android: "Android" or a build fingerprint string; iOS: "iOS"/"iPadOS"
|
|
59
|
+
*/
|
|
60
|
+
export declare const osName: string | null;
|
|
61
|
+
/**
|
|
62
|
+
* The human-readable OS version string. Note that the version string may not always contain
|
|
63
|
+
* three numbers separated by dots.
|
|
64
|
+
*/
|
|
65
|
+
export declare const osVersion: string | null;
|
|
66
|
+
/**
|
|
67
|
+
* The build ID of the OS that more precisely identifies the version of the OS. On Android this
|
|
68
|
+
* corresponds to `Build.DISPLAY` (not `Build.ID`); on iOS to `kern.osversion`.
|
|
69
|
+
*/
|
|
70
|
+
export declare const osBuildId: string | null;
|
|
71
|
+
/**
|
|
72
|
+
* The internal build ID of the OS running on the device. On Android this corresponds to
|
|
73
|
+
* `Build.ID`; on iOS it's the same value as {@link osBuildId}.
|
|
74
|
+
*/
|
|
75
|
+
export declare const osInternalBuildId: string | null;
|
|
76
|
+
/**
|
|
77
|
+
* A string that uniquely identifies the build of the currently running system OS.
|
|
78
|
+
* @platform android
|
|
79
|
+
*/
|
|
80
|
+
export declare const osBuildFingerprint: string | null;
|
|
81
|
+
/**
|
|
82
|
+
* The Android SDK version of the software currently running on this hardware device.
|
|
83
|
+
* @platform android
|
|
84
|
+
*/
|
|
85
|
+
export declare const platformApiLevel: number | null;
|
|
86
|
+
/**
|
|
87
|
+
* The human-readable name of the device, which may be set by the device's user. `null` if the
|
|
88
|
+
* device name is unavailable.
|
|
89
|
+
*/
|
|
90
|
+
export declare const deviceName: string | null;
|
|
91
|
+
/**
|
|
92
|
+
* Checks the type of the device as a {@link DeviceType} enum value.
|
|
93
|
+
*
|
|
94
|
+
* On Android, for devices other than TVs, the device type is determined by the screen
|
|
95
|
+
* resolution (screen diagonal size), so the result may not be completely accurate. If the
|
|
96
|
+
* screen diagonal length is between 3" and 6.9", the method returns `DeviceType.PHONE`. For
|
|
97
|
+
* lengths between 7" and 18", the method returns `DeviceType.TABLET`. Otherwise it returns
|
|
98
|
+
* `DeviceType.UNKNOWN`.
|
|
99
|
+
*/
|
|
100
|
+
export declare function getDeviceTypeAsync(): Promise<DeviceType>;
|
|
101
|
+
/**
|
|
102
|
+
* Gets the uptime since the last reboot of the device, in milliseconds. Android devices do not
|
|
103
|
+
* count time spent in deep sleep.
|
|
104
|
+
* @platform android
|
|
105
|
+
* @platform ios
|
|
106
|
+
*/
|
|
107
|
+
export declare function getUptimeAsync(): Promise<number>;
|
|
108
|
+
/**
|
|
109
|
+
* Returns the maximum amount of memory that the Java VM will attempt to use. If there is no
|
|
110
|
+
* inherent limit, `Number.MAX_SAFE_INTEGER` is returned instead of the native `-1` sentinel.
|
|
111
|
+
* @platform android
|
|
112
|
+
*/
|
|
113
|
+
export declare function getMaxMemoryAsync(): Promise<number>;
|
|
114
|
+
/**
|
|
115
|
+
* Checks whether the device has been rooted (Android) or jailbroken (iOS). This is a best-effort
|
|
116
|
+
* check — root/jailbreak-detection bypasses exist on both platforms, so a `false` result is not
|
|
117
|
+
* a guarantee.
|
|
118
|
+
*/
|
|
119
|
+
export declare function isRootedExperimentalAsync(): Promise<boolean>;
|
|
120
|
+
/**
|
|
121
|
+
* Returns whether applications can be installed for this user via the system's
|
|
122
|
+
* `ACTION_INSTALL_PACKAGE` mechanism, rather than through the OS's default app store. Requires
|
|
123
|
+
* the `REQUEST_INSTALL_PACKAGES` permission.
|
|
124
|
+
* @platform android
|
|
125
|
+
*/
|
|
126
|
+
export declare function isSideLoadingEnabledAsync(): Promise<boolean>;
|
|
127
|
+
/**
|
|
128
|
+
* Gets a list of platform-specific feature names available on the system. Resolves to an empty
|
|
129
|
+
* array rather than throwing when the native method is absent (e.g. on iOS), matching upstream.
|
|
130
|
+
* @platform android
|
|
131
|
+
*/
|
|
132
|
+
export declare function getPlatformFeaturesAsync(): Promise<string[]>;
|
|
133
|
+
/**
|
|
134
|
+
* Tells if the device has a specific system feature. Resolves to `false` rather than throwing
|
|
135
|
+
* when the native method is absent (e.g. on iOS), matching upstream.
|
|
136
|
+
* @platform android
|
|
137
|
+
*/
|
|
138
|
+
export declare function hasPlatformFeatureAsync(feature: string): Promise<boolean>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// Hand-ported from .vendors/expo/packages/expo-device/src/Device.ts (sdk-57). Every constant
|
|
2
|
+
// below is resolved eagerly, once, at import time — matching upstream's own top-level `export
|
|
3
|
+
// const` shape — from the native module's optional fields (native-module.ts), never imported
|
|
4
|
+
// from expo-device's own JS.
|
|
5
|
+
//
|
|
6
|
+
// Deviation from upstream: upstream guards each constant with `ExpoDevice ? field : fallback`,
|
|
7
|
+
// i.e. a truthiness check on the WHOLE module, because its own requireNativeModule call could in
|
|
8
|
+
// principle resolve to a falsy value on some legacy/web target. Every sibling package in this
|
|
9
|
+
// repo (local-auth, cellular, battery) instead resolves its native module unconditionally via
|
|
10
|
+
// expo-modules-core's requireNativeModule, which throws rather than returning null/undefined —
|
|
11
|
+
// so "the whole module is absent" already fails at import time here, same as every other
|
|
12
|
+
// package. What upstream's ternary is actually doing field-by-field IS still real and worth
|
|
13
|
+
// keeping: several constants are `undefined` on one platform by design (modelId is iOS-only;
|
|
14
|
+
// designName/productName/osBuildFingerprint/platformApiLevel are Android-only), so each constant
|
|
15
|
+
// below falls back with `??`, matching that per-field behavior without a redundant whole-module
|
|
16
|
+
// check the rest of this codebase's convention doesn't otherwise use.
|
|
17
|
+
import { UnavailabilityError } from 'expo-modules-core';
|
|
18
|
+
import { expoDevice } from './native-module';
|
|
19
|
+
import { DeviceType } from './types';
|
|
20
|
+
const NATIVE_MODULE_NAME = 'expo-device';
|
|
21
|
+
const MAX_MEMORY_UNLIMITED_SENTINEL = -1;
|
|
22
|
+
/**
|
|
23
|
+
* `true` if the app is running on a real device and `false` if running in a simulator or
|
|
24
|
+
* emulator.
|
|
25
|
+
*/
|
|
26
|
+
export const isDevice = expoDevice.isDevice ?? true;
|
|
27
|
+
/**
|
|
28
|
+
* The device brand. The consumer-visible brand of the product/hardware.
|
|
29
|
+
* @example Device.brand; // Android: "google", "xiaomi"; iOS: "Apple"
|
|
30
|
+
*/
|
|
31
|
+
export const brand = expoDevice.brand ?? null;
|
|
32
|
+
/**
|
|
33
|
+
* The actual device manufacturer of the product or hardware. May be `null` if it cannot be
|
|
34
|
+
* determined.
|
|
35
|
+
*/
|
|
36
|
+
export const manufacturer = expoDevice.manufacturer ?? null;
|
|
37
|
+
/**
|
|
38
|
+
* The internal model ID of the device — useful for programmatically identifying the type of
|
|
39
|
+
* device, not a human-friendly string.
|
|
40
|
+
* @platform ios
|
|
41
|
+
*/
|
|
42
|
+
export const modelId = expoDevice.modelId ?? null;
|
|
43
|
+
/**
|
|
44
|
+
* The human-friendly name of the device model. May be `null` if it cannot be determined.
|
|
45
|
+
* @example Device.modelName; // Android: "Pixel 2"; iOS: "iPhone XS Max"
|
|
46
|
+
*/
|
|
47
|
+
export const modelName = expoDevice.modelName ?? null;
|
|
48
|
+
/**
|
|
49
|
+
* The specific configuration or name of the industrial design — the device's name when it was
|
|
50
|
+
* designed during manufacturing into mass production. Corresponds to `Build.DEVICE`.
|
|
51
|
+
* @platform android
|
|
52
|
+
*/
|
|
53
|
+
export const designName = expoDevice.designName ?? null;
|
|
54
|
+
/**
|
|
55
|
+
* The device's overall product name chosen by the device implementer, containing the
|
|
56
|
+
* development name or code name of the device. Corresponds to `Build.PRODUCT`.
|
|
57
|
+
* @platform android
|
|
58
|
+
*/
|
|
59
|
+
export const productName = expoDevice.productName ?? null;
|
|
60
|
+
/**
|
|
61
|
+
* The type of the device as a {@link DeviceType} enum value.
|
|
62
|
+
*/
|
|
63
|
+
export const deviceType = expoDevice.deviceType ?? null;
|
|
64
|
+
/** The device year class (https://github.com/facebook/device-year-class) of this device. */
|
|
65
|
+
export const deviceYearClass = expoDevice.deviceYearClass ?? null;
|
|
66
|
+
/**
|
|
67
|
+
* The device's total memory, in bytes — the total memory accessible to the kernel, but not
|
|
68
|
+
* necessarily to a single app.
|
|
69
|
+
*/
|
|
70
|
+
export const totalMemory = expoDevice.totalMemory ?? null;
|
|
71
|
+
/**
|
|
72
|
+
* A list of supported processor architecture versions. `null` if the supported architectures
|
|
73
|
+
* could not be determined.
|
|
74
|
+
*/
|
|
75
|
+
export const supportedCpuArchitectures = expoDevice.supportedCpuArchitectures ?? null;
|
|
76
|
+
/**
|
|
77
|
+
* The name of the OS running on the device.
|
|
78
|
+
* @example Device.osName; // Android: "Android" or a build fingerprint string; iOS: "iOS"/"iPadOS"
|
|
79
|
+
*/
|
|
80
|
+
export const osName = expoDevice.osName ?? null;
|
|
81
|
+
/**
|
|
82
|
+
* The human-readable OS version string. Note that the version string may not always contain
|
|
83
|
+
* three numbers separated by dots.
|
|
84
|
+
*/
|
|
85
|
+
export const osVersion = expoDevice.osVersion ?? null;
|
|
86
|
+
/**
|
|
87
|
+
* The build ID of the OS that more precisely identifies the version of the OS. On Android this
|
|
88
|
+
* corresponds to `Build.DISPLAY` (not `Build.ID`); on iOS to `kern.osversion`.
|
|
89
|
+
*/
|
|
90
|
+
export const osBuildId = expoDevice.osBuildId ?? null;
|
|
91
|
+
/**
|
|
92
|
+
* The internal build ID of the OS running on the device. On Android this corresponds to
|
|
93
|
+
* `Build.ID`; on iOS it's the same value as {@link osBuildId}.
|
|
94
|
+
*/
|
|
95
|
+
export const osInternalBuildId = expoDevice.osInternalBuildId ?? null;
|
|
96
|
+
/**
|
|
97
|
+
* A string that uniquely identifies the build of the currently running system OS.
|
|
98
|
+
* @platform android
|
|
99
|
+
*/
|
|
100
|
+
export const osBuildFingerprint = expoDevice.osBuildFingerprint ?? null;
|
|
101
|
+
/**
|
|
102
|
+
* The Android SDK version of the software currently running on this hardware device.
|
|
103
|
+
* @platform android
|
|
104
|
+
*/
|
|
105
|
+
export const platformApiLevel = expoDevice.platformApiLevel ?? null;
|
|
106
|
+
/**
|
|
107
|
+
* The human-readable name of the device, which may be set by the device's user. `null` if the
|
|
108
|
+
* device name is unavailable.
|
|
109
|
+
*/
|
|
110
|
+
export const deviceName = expoDevice.deviceName ?? null;
|
|
111
|
+
/**
|
|
112
|
+
* Checks the type of the device as a {@link DeviceType} enum value.
|
|
113
|
+
*
|
|
114
|
+
* On Android, for devices other than TVs, the device type is determined by the screen
|
|
115
|
+
* resolution (screen diagonal size), so the result may not be completely accurate. If the
|
|
116
|
+
* screen diagonal length is between 3" and 6.9", the method returns `DeviceType.PHONE`. For
|
|
117
|
+
* lengths between 7" and 18", the method returns `DeviceType.TABLET`. Otherwise it returns
|
|
118
|
+
* `DeviceType.UNKNOWN`.
|
|
119
|
+
*/
|
|
120
|
+
export async function getDeviceTypeAsync() {
|
|
121
|
+
if (!expoDevice.getDeviceTypeAsync) {
|
|
122
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getDeviceTypeAsync');
|
|
123
|
+
}
|
|
124
|
+
return expoDevice.getDeviceTypeAsync();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Gets the uptime since the last reboot of the device, in milliseconds. Android devices do not
|
|
128
|
+
* count time spent in deep sleep.
|
|
129
|
+
* @platform android
|
|
130
|
+
* @platform ios
|
|
131
|
+
*/
|
|
132
|
+
export async function getUptimeAsync() {
|
|
133
|
+
if (!expoDevice.getUptimeAsync) {
|
|
134
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getUptimeAsync');
|
|
135
|
+
}
|
|
136
|
+
return expoDevice.getUptimeAsync();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Returns the maximum amount of memory that the Java VM will attempt to use. If there is no
|
|
140
|
+
* inherent limit, `Number.MAX_SAFE_INTEGER` is returned instead of the native `-1` sentinel.
|
|
141
|
+
* @platform android
|
|
142
|
+
*/
|
|
143
|
+
export async function getMaxMemoryAsync() {
|
|
144
|
+
if (!expoDevice.getMaxMemoryAsync) {
|
|
145
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'getMaxMemoryAsync');
|
|
146
|
+
}
|
|
147
|
+
const maxMemory = await expoDevice.getMaxMemoryAsync();
|
|
148
|
+
return maxMemory === MAX_MEMORY_UNLIMITED_SENTINEL ? Number.MAX_SAFE_INTEGER : maxMemory;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Checks whether the device has been rooted (Android) or jailbroken (iOS). This is a best-effort
|
|
152
|
+
* check — root/jailbreak-detection bypasses exist on both platforms, so a `false` result is not
|
|
153
|
+
* a guarantee.
|
|
154
|
+
*/
|
|
155
|
+
export async function isRootedExperimentalAsync() {
|
|
156
|
+
if (!expoDevice.isRootedExperimentalAsync) {
|
|
157
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isRootedExperimentalAsync');
|
|
158
|
+
}
|
|
159
|
+
return expoDevice.isRootedExperimentalAsync();
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Returns whether applications can be installed for this user via the system's
|
|
163
|
+
* `ACTION_INSTALL_PACKAGE` mechanism, rather than through the OS's default app store. Requires
|
|
164
|
+
* the `REQUEST_INSTALL_PACKAGES` permission.
|
|
165
|
+
* @platform android
|
|
166
|
+
*/
|
|
167
|
+
export async function isSideLoadingEnabledAsync() {
|
|
168
|
+
if (!expoDevice.isSideLoadingEnabledAsync) {
|
|
169
|
+
throw new UnavailabilityError(NATIVE_MODULE_NAME, 'isSideLoadingEnabledAsync');
|
|
170
|
+
}
|
|
171
|
+
return expoDevice.isSideLoadingEnabledAsync();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Gets a list of platform-specific feature names available on the system. Resolves to an empty
|
|
175
|
+
* array rather than throwing when the native method is absent (e.g. on iOS), matching upstream.
|
|
176
|
+
* @platform android
|
|
177
|
+
*/
|
|
178
|
+
export async function getPlatformFeaturesAsync() {
|
|
179
|
+
if (!expoDevice.getPlatformFeaturesAsync) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
return expoDevice.getPlatformFeaturesAsync();
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Tells if the device has a specific system feature. Resolves to `false` rather than throwing
|
|
186
|
+
* when the native method is absent (e.g. on iOS), matching upstream.
|
|
187
|
+
* @platform android
|
|
188
|
+
*/
|
|
189
|
+
export async function hasPlatformFeatureAsync(feature) {
|
|
190
|
+
if (!expoDevice.hasPlatformFeatureAsync) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return expoDevice.hasPlatformFeatureAsync(feature);
|
|
194
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { isDevice, brand, manufacturer, modelId, modelName, designName, productName, deviceType, deviceYearClass, totalMemory, supportedCpuArchitectures, osName, osVersion, osBuildId, osInternalBuildId, osBuildFingerprint, platformApiLevel, deviceName, getDeviceTypeAsync, getUptimeAsync, getMaxMemoryAsync, isRootedExperimentalAsync, isSideLoadingEnabledAsync, getPlatformFeaturesAsync, hasPlatformFeatureAsync, } from './device';
|
|
2
|
+
export { DeviceType } from './types';
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { isDevice, brand, manufacturer, modelId, modelName, designName, productName, deviceType, deviceYearClass, totalMemory, supportedCpuArchitectures, osName, osVersion, osBuildId, osInternalBuildId, osBuildFingerprint, platformApiLevel, deviceName, getDeviceTypeAsync, getUptimeAsync, getMaxMemoryAsync, isRootedExperimentalAsync, isSideLoadingEnabledAsync, getPlatformFeaturesAsync, hasPlatformFeatureAsync, } from './device';
|
|
2
|
+
export { DeviceType } from './types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DeviceType } from './types';
|
|
2
|
+
export type INativeDeviceModule = {
|
|
3
|
+
isDevice?: boolean;
|
|
4
|
+
brand?: string | null;
|
|
5
|
+
manufacturer?: string | null;
|
|
6
|
+
modelId?: string | null;
|
|
7
|
+
modelName?: string | null;
|
|
8
|
+
designName?: string | null;
|
|
9
|
+
productName?: string | null;
|
|
10
|
+
deviceType?: DeviceType | null;
|
|
11
|
+
deviceYearClass?: number | null;
|
|
12
|
+
totalMemory?: number | null;
|
|
13
|
+
supportedCpuArchitectures?: string[] | null;
|
|
14
|
+
osName?: string | null;
|
|
15
|
+
osVersion?: string | null;
|
|
16
|
+
osBuildId?: string | null;
|
|
17
|
+
osInternalBuildId?: string | null;
|
|
18
|
+
osBuildFingerprint?: string | null;
|
|
19
|
+
platformApiLevel?: number | null;
|
|
20
|
+
deviceName?: string | null;
|
|
21
|
+
getDeviceTypeAsync?(): Promise<DeviceType>;
|
|
22
|
+
getUptimeAsync?(): Promise<number>;
|
|
23
|
+
getMaxMemoryAsync?(): Promise<number>;
|
|
24
|
+
isRootedExperimentalAsync?(): Promise<boolean>;
|
|
25
|
+
isSideLoadingEnabledAsync?(): Promise<boolean>;
|
|
26
|
+
getPlatformFeaturesAsync?(): Promise<string[]>;
|
|
27
|
+
hasPlatformFeatureAsync?(feature: string): Promise<boolean>;
|
|
28
|
+
};
|
|
29
|
+
export declare const expoDevice: INativeDeviceModule;
|