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