1 import ABI49_0_0ExpoModulesCore 2 import UIKit 3 import MachO 4 5 public class DeviceModule: Module { 6 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 42 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 67 func isDevice() -> Bool { 68 #if targetEnvironment(simulator) 69 return false 70 #else 71 return true 72 #endif 73 } 74 75 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 98 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