1 import ABI49_0_0ExpoModulesCore
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 let uptimeMs: Double = ProcessInfo.processInfo.systemUptime * 1000
32
33 return uptimeMs
34 }
35
36 AsyncFunction("isRootedExperimentalAsync") { () -> Bool in
37 return UIDevice.current.isJailbroken
38 }
39 }
40 }
41
getDeviceTypenull42 func getDeviceType() -> Int {
43 // if it's a macOS Catalyst app
44 if ProcessInfo.processInfo.isMacCatalystApp {
45 return DeviceType.desktop.rawValue
46 }
47
48 // if it's built for iPad running on a Mac
49 if #available(iOS 14.0, *) {
50 if ProcessInfo.processInfo.isiOSAppOnMac {
51 return DeviceType.desktop.rawValue
52 }
53 }
54
55 switch UIDevice.current.userInterfaceIdiom {
56 case UIUserInterfaceIdiom.phone:
57 return DeviceType.phone.rawValue
58 case UIUserInterfaceIdiom.pad:
59 return DeviceType.tablet.rawValue
60 case UIUserInterfaceIdiom.tv:
61 return DeviceType.tv.rawValue
62 default:
63 return DeviceType.unknown.rawValue
64 }
65 }
66
isDevicenull67 func isDevice() -> Bool {
68 #if targetEnvironment(simulator)
69 return false
70 #else
71 return true
72 #endif
73 }
74
osBuildIdnull75 func osBuildId() -> String? {
76 #if os(tvOS)
77 return nil
78 #else
79 // Credit: https://stackoverflow.com/a/65858410
80 var mib: [Int32] = [CTL_KERN, KERN_OSVERSION]
81 let namelen = UInt32(MemoryLayout.size(ofValue: mib) / MemoryLayout.size(ofValue: mib[0]))
82 var bufferSize = 0
83
84 // Get the size for the buffer
85 sysctl(&mib, namelen, nil, &bufferSize, nil, 0)
86
87 var buildBuffer = [UInt8](repeating: 0, count: bufferSize)
88 let result = sysctl(&mib, namelen, &buildBuffer, &bufferSize, nil, 0)
89
90 if result >= 0 && bufferSize > 0 {
91 return String(bytesNoCopy: &buildBuffer, length: bufferSize - 1, encoding: .utf8, freeWhenDone: false)
92 }
93
94 return nil
95 #endif
96 }
97
cpuArchitecturesnull98 func cpuArchitectures() -> [String]? {
99 // Credit: https://stackoverflow.com/a/70134518
100 guard let archRaw = NXGetLocalArchInfo().pointee.name else {
101 return nil
102 }
103 return [String(cString: archRaw)]
104 }
105
106 enum DeviceType: Int {
107 case unknown = 0
108 case phone = 1
109 case tablet = 2
110 case desktop = 3
111 case tv = 4
112 }
113