1 import ExpoModulesCore
2 import UIKit
3 import MachO
4
5 public class DeviceModule: Module {
definitionnull6 public func definition() -> ModuleDefinition {
7 Name("ExpoDevice")
8
9 Constants([
10 "isDevice": isDevice(),
11 "brand": "Apple",
12 "manufacturer": "Apple",
13 "modelId": UIDevice.modelIdentifier,
14 "modelName": UIDevice.DeviceMap.modelName,
15 "deviceYearClass": UIDevice.DeviceMap.deviceYearClass,
16 "totalMemory": ProcessInfo.processInfo.physicalMemory,
17 "osName": UIDevice.current.systemName,
18 "osVersion": UIDevice.current.systemVersion,
19 "osBuildId": osBuildId(),
20 "osInternalBuildId": osBuildId(),
21 "deviceName": UIDevice.current.name,
22 "deviceType": getDeviceType(),
23 "supportedCpuArchitectures": cpuArchitectures()
24 ])
25
26 AsyncFunction("getDeviceTypeAsync") { () -> Int in
27 return getDeviceType()
28 }
29
30 AsyncFunction("getUptimeAsync") { () -> Double in
31 return ProcessInfo.processInfo.systemUptime * 1000
32 }
33
34 AsyncFunction("isRootedExperimentalAsync") { () -> Bool in
35 return UIDevice.current.isJailbroken
36 }
37 }
38 }
39
getDeviceTypenull40 func getDeviceType() -> Int {
41 // if it's a macOS Catalyst app
42 if ProcessInfo.processInfo.isMacCatalystApp {
43 return DeviceType.desktop.rawValue
44 }
45
46 // if it's built for iPad running on a Mac
47 if #available(iOS 14.0, *) {
48 if ProcessInfo.processInfo.isiOSAppOnMac {
49 return DeviceType.desktop.rawValue
50 }
51 }
52
53 switch UIDevice.current.userInterfaceIdiom {
54 case UIUserInterfaceIdiom.phone:
55 return DeviceType.phone.rawValue
56 case UIUserInterfaceIdiom.pad:
57 return DeviceType.tablet.rawValue
58 case UIUserInterfaceIdiom.tv:
59 return DeviceType.tv.rawValue
60 default:
61 return DeviceType.unknown.rawValue
62 }
63 }
64
isDevicenull65 func isDevice() -> Bool {
66 #if targetEnvironment(simulator)
67 return false
68 #else
69 return true
70 #endif
71 }
72
osBuildIdnull73 func osBuildId() -> String? {
74 #if os(tvOS)
75 return nil
76 #else
77 // Credit: https://stackoverflow.com/a/65858410
78 var mib: [Int32] = [CTL_KERN, KERN_OSVERSION]
79 let namelen = UInt32(MemoryLayout.size(ofValue: mib) / MemoryLayout.size(ofValue: mib[0]))
80 var bufferSize = 0
81
82 // Get the size for the buffer
83 sysctl(&mib, namelen, nil, &bufferSize, nil, 0)
84
85 var buildBuffer = [UInt8](repeating: 0, count: bufferSize)
86 let result = sysctl(&mib, namelen, &buildBuffer, &bufferSize, nil, 0)
87
88 if result >= 0 && bufferSize > 0 {
89 return String(bytesNoCopy: &buildBuffer, length: bufferSize - 1, encoding: .utf8, freeWhenDone: false)
90 }
91
92 return nil
93 #endif
94 }
95
cpuArchitecturesnull96 func cpuArchitectures() -> [String]? {
97 // Credit: https://stackoverflow.com/a/70134518
98 guard let archRaw = NXGetLocalArchInfo().pointee.name else {
99 return nil
100 }
101 return [String(cString: archRaw)]
102 }
103
104 enum DeviceType: Int {
105 case unknown = 0
106 case phone = 1
107 case tablet = 2
108 case desktop = 3
109 case tv = 4
110 }
111