import Flutter import UIKit import CommonCrypto import Security @main @objc class AppDelegate: FlutterAppDelegate { private let CHANNEL = "iq.urukprize.uruk_prize/device_fingerprint" private let KEYCHAIN_KEY = "iq.urukprize.device_persistent_id" override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let channel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in guard let self = self else { return } switch call.method { case "getHardwareFingerprint": let rawData = self.getHardwareDetails() let hashed = self.sha256(data: rawData) result(hashed) case "getDeviceModel": result(self.getDeviceModel()) case "getHardwareRawData": result(self.getHardwareDetails()) default: result(FlutterMethodNotImplemented) } }) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func getHardwareDetails() -> String { let vendorId = UIDevice.current.identifierForVendor?.uuidString ?? "UNKNOWN_IDFV" let model = getDeviceModel() let systemName = UIDevice.current.systemName let systemVersion = UIDevice.current.systemVersion let persistentKey = getOrCreatePersistentKeychainId() return "idfv=\(vendorId);keychain_id=\(persistentKey);model=\(model);sys=\(systemName)_\(systemVersion)" } private func getDeviceModel() -> String { var systemInfo = utsname() uname(&systemInfo) let machineMirror = Mirror(reflecting: systemInfo.machine) let identifier = machineMirror.children.reduce("") { identifier, element in guard let value = element.value as? Int8, value != 0 else { return identifier } return identifier + String(UnicodeScalar(UInt8(value))) } return identifier } private func getOrCreatePersistentKeychainId() -> String { let tag = KEYCHAIN_KEY.data(using: .utf8)! // Query Keychain let query: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrApplicationTag as String: tag, kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecReturnData as String: true ] var item: CFTypeRef? let status = SecItemCopyMatching(query as CFDictionary, &item) if status == errSecSuccess, let existingData = item as? Data, let string = String(data: existingData, encoding: .utf8) { return string } // Generate new persistent UUID and save to Keychain let newId = UUID().uuidString let newIdData = newId.data(using: .utf8)! let addQuery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrApplicationTag as String: tag, kSecValueData as String: newIdData, kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ] SecItemAdd(addQuery as CFDictionary, nil) return newId } private func sha256(data: String) -> String { guard let inputData = data.data(using: .utf8) else { return "" } var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) inputData.withUnsafeBytes { _ = CC_SHA256($0.baseAddress, CC_LONG(inputData.count), &digest) } return digest.map { String(format: "%02hhx", $0) }.joined() } }