| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  | // | 
					
						
							|  |  |  |  | //  Constants.swift | 
					
						
							|  |  |  |  | //  AgoraChatRoom | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | //  Created by LXH on 2019/11/27. | 
					
						
							|  |  |  |  | //  Copyright © 2019 CavanSu. All rights reserved. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import UIKit | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | internal struct Constants { | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let appVersion: String = { | 
					
						
							|  |  |  |  |         guard let infoDict = Bundle.main.infoDictionary, | 
					
						
							|  |  |  |  |               let currentVersion = infoDict["CFBundleShortVersionString"] as? String else { | 
					
						
							|  |  |  |  |             return "" | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return currentVersion | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let appBundleIdentifier: String = { | 
					
						
							|  |  |  |  |         guard let infoDictionary = Bundle.main.infoDictionary, | 
					
						
							|  |  |  |  |               let shortVersion = infoDictionary["CFBundleIdentifier"] as? String else { | 
					
						
							|  |  |  |  |             return "" | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return shortVersion | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  |     private static let guruAnalyticsSDKVersion: String = { | 
					
						
							| 
									
										
										
										
											2024-09-23 02:53:09 +00:00
										 |  |  |  |         guard let infoDict = Bundle(for: Manager.self).infoDictionary, | 
					
						
							|  |  |  |  |               let currentVersion = infoDict["CFBundleShortVersionString"] as? String else { | 
					
						
							|  |  |  |  |             return "" | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return currentVersion | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  |     /// 中台库版本,由外部更新 | 
					
						
							|  |  |  |  |     static var guruSDKVersion: String = ""; | 
					
						
							|  |  |  |  |      | 
					
						
							| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  |     private static let preferredLocale: Locale = { | 
					
						
							|  |  |  |  |         guard let preferredIdentifier = Locale.preferredLanguages.first else { | 
					
						
							|  |  |  |  |             return Locale.current | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         return Locale(identifier: preferredIdentifier) | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let countryCode: String = { | 
					
						
							|  |  |  |  |         return preferredLocale.regionCode?.uppercased() ?? "" | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let timeZone: String = { | 
					
						
							|  |  |  |  |         return TimeZone.current.identifier | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let languageCode: String = { | 
					
						
							|  |  |  |  |         return preferredLocale.languageCode ?? "" | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let localeCode: String = { | 
					
						
							|  |  |  |  |         return preferredLocale.identifier | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let modelName: String = { | 
					
						
							|  |  |  |  |         return platform().deviceType.rawValue | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let model: String = { | 
					
						
							|  |  |  |  |         return hardwareString() | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let systemVersion: String = { | 
					
						
							|  |  |  |  |         return UIDevice.current.systemVersion | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     private static let screenSize: (w: CGFloat, h: CGFloat) = { | 
					
						
							|  |  |  |  |         return (UIScreen.main.bounds.width, UIScreen.main.bounds.height) | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /// 时区偏移毫秒数 | 
					
						
							|  |  |  |  |     private static let tzOffset: Int64 = { | 
					
						
							|  |  |  |  |         return Int64(TimeZone.current.secondsFromGMT(for: Date())) * 1000 | 
					
						
							|  |  |  |  |     }() | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     static var deviceInfo: [String : Any] { | 
					
						
							|  |  |  |  |         return [ | 
					
						
							|  |  |  |  |             "country": countryCode, | 
					
						
							|  |  |  |  |             "platform": "IOS", | 
					
						
							|  |  |  |  |             "appId" : appBundleIdentifier, | 
					
						
							|  |  |  |  |             "version" : appVersion, | 
					
						
							|  |  |  |  |             "tzOffset": tzOffset, | 
					
						
							|  |  |  |  |             "deviceType" : modelName, | 
					
						
							|  |  |  |  |             "brand": "Apple", | 
					
						
							|  |  |  |  |             "model": model, | 
					
						
							|  |  |  |  |             "screenH": Int(screenSize.h), | 
					
						
							|  |  |  |  |             "screenW": Int(screenSize.w), | 
					
						
							|  |  |  |  |             "osVersion": systemVersion, | 
					
						
							| 
									
										
										
										
											2024-09-23 02:53:09 +00:00
										 |  |  |  |             "language" : languageCode, | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  |             "guruAnalyticsVersion" : guruAnalyticsSDKVersion, | 
					
						
							|  |  |  |  |             "gurusdkVersion" : guruSDKVersion, | 
					
						
							| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  |         ] | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /// This method returns the hardware type | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     /// - returns: raw `String` of device type, e.g. iPhone5,1 | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     private static func hardwareString() -> String { | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  |         var name: [Int32] = [CTL_HW, HW_MACHINE] | 
					
						
							|  |  |  |  |         var size: size_t = 0 | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // 🛡️ 安全检查1:获取缓冲区大小 | 
					
						
							|  |  |  |  |         guard sysctl(&name, 2, nil, &size, nil, 0) == 0, | 
					
						
							|  |  |  |  |               size > 0 && size < 256 else { | 
					
						
							|  |  |  |  |             return "iPhone14,1" // 安全默认值 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // 🛡️ 安全检查2:创建缓冲区 | 
					
						
							|  |  |  |  |         let bufferSize = Int(size) + 1 | 
					
						
							|  |  |  |  |         var hw_machine = [CChar](repeating: 0, count: bufferSize) | 
					
						
							|  |  |  |  |         var actualSize = size | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // 🛡️ 安全检查3:获取数据 | 
					
						
							|  |  |  |  |         guard sysctl(&name, 2, &hw_machine, &actualSize, nil, 0) == 0 else { | 
					
						
							|  |  |  |  |             return "iPhone14,1" // 安全默认值 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // 🛡️ 安全检查4:确保null终止(防止越界) | 
					
						
							|  |  |  |  |         let safeIndex = min(Int(actualSize), bufferSize - 1) | 
					
						
							|  |  |  |  |         hw_machine[safeIndex] = 0 | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         var hardware: String = String(cString: hw_machine) | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // 🛡️ 安全检查5:验证结果 | 
					
						
							|  |  |  |  |         if hardware.isEmpty { | 
					
						
							|  |  |  |  |             return "iPhone14,1" // 安全默认值 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // Check for simulator | 
					
						
							|  |  |  |  |         if hardware == "x86_64" || hardware == "i386" || hardware == "arm64" { | 
					
						
							|  |  |  |  |             if let deviceID = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] { | 
					
						
							|  |  |  |  |                 hardware = deviceID | 
					
						
							|  |  |  |  |             } else { | 
					
						
							|  |  |  |  |                 hardware = "Simulator" | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         return hardware | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     //这里不可用,有崩溃!!!用上边的方法!! | 
					
						
							|  |  |  |  |     private static func hardwareStringError() -> String { | 
					
						
							| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  |         var name: [Int32] = [CTL_HW, HW_MACHINE] | 
					
						
							|  |  |  |  |         var size: Int = 2 | 
					
						
							|  |  |  |  |         sysctl(&name, 2, nil, &size, nil, 0) | 
					
						
							|  |  |  |  |         var hw_machine = [CChar](repeating: 0, count: Int(size)) | 
					
						
							|  |  |  |  |         sysctl(&name, 2, &hw_machine, &size, nil, 0) | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         var hardware: String = String(cString: hw_machine) | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         // Check for simulator | 
					
						
							|  |  |  |  |         if hardware == "x86_64" || hardware == "i386" || hardware == "arm64" { | 
					
						
							|  |  |  |  |             if let deviceID = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] { | 
					
						
							|  |  |  |  |                 hardware = deviceID | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  |      | 
					
						
							| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  |         return hardware | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							| 
									
										
										
										
											2025-08-08 10:12:14 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |      | 
					
						
							| 
									
										
										
										
											2024-09-04 05:01:33 +00:00
										 |  |  |  |     /// This method returns the Platform enum depending upon harware string | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     /// - returns: `Platform` type of the device | 
					
						
							|  |  |  |  |     /// | 
					
						
							|  |  |  |  |     static func platform() -> Platform { | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         let hardware = hardwareString() | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         if (hardware.hasPrefix("iPhone"))    { return .iPhone } | 
					
						
							|  |  |  |  |         if (hardware.hasPrefix("iPod"))      { return .iPodTouch } | 
					
						
							|  |  |  |  |         if (hardware.hasPrefix("iPad"))      { return .iPad } | 
					
						
							|  |  |  |  |         if (hardware.hasPrefix("Watch"))     { return .appleWatch } | 
					
						
							|  |  |  |  |         if (hardware.hasPrefix("AppleTV"))   { return .appleTV } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         return .unknown | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     enum Platform { | 
					
						
							|  |  |  |  |         case iPhone | 
					
						
							|  |  |  |  |         case iPodTouch | 
					
						
							|  |  |  |  |         case iPad | 
					
						
							|  |  |  |  |         case appleWatch | 
					
						
							|  |  |  |  |         case appleTV | 
					
						
							|  |  |  |  |         case unknown | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         enum DeviceType: String { | 
					
						
							|  |  |  |  |             case mobile, tablet, desktop, smartTV, watch, other | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |         var deviceType: DeviceType { | 
					
						
							|  |  |  |  |             switch self { | 
					
						
							|  |  |  |  |             case .iPad: | 
					
						
							|  |  |  |  |                 return .tablet | 
					
						
							|  |  |  |  |             case .iPhone, .iPodTouch: | 
					
						
							|  |  |  |  |                 return .mobile | 
					
						
							|  |  |  |  |             case .appleTV: | 
					
						
							|  |  |  |  |                 return .smartTV | 
					
						
							|  |  |  |  |             case .appleWatch: | 
					
						
							|  |  |  |  |                 return .watch | 
					
						
							|  |  |  |  |             case .unknown: | 
					
						
							|  |  |  |  |                 return .other | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  | } |