import Flutter import UIKit final class PlatformInfoPlugin: NSObject, FlutterPlugin { static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel( name: "com.qxy.dronex/platform_info", binaryMessenger: registrar.messenger() ) let plugin = PlatformInfoPlugin() registrar.addMethodCallDelegate(plugin, channel: channel) } func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "packageInfo": result(packageInfoMap()) case "deviceInfo": result(deviceInfoMap()) case "deviceHealth": result(deviceHealthMap()) default: result(FlutterMethodNotImplemented) } } private func packageInfoMap() -> [String: String] { let bundle = Bundle.main return [ "appName": displayName(bundle: bundle), "packageName": bundle.bundleIdentifier ?? "", "version": bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "", "buildNumber": bundle.object(forInfoDictionaryKey: "CFBundleVersion") as? String ?? "", ] } private func deviceHealthMap() -> [String: Any?] { let device = UIDevice.current device.isBatteryMonitoringEnabled = true var batteryLevelPercent: Int? let batteryLevel = device.batteryLevel if batteryLevel >= 0 { batteryLevelPercent = Int((batteryLevel * 100).rounded()) } var storageAvailablePercent = 100.0 if let attrs = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()), let free = attrs[.systemFreeSize] as? NSNumber, let total = attrs[.systemSize] as? NSNumber, total.doubleValue > 0 { storageAvailablePercent = free.doubleValue / total.doubleValue * 100.0 } return [ "batteryLevelPercent": batteryLevelPercent, "storageAvailablePercent": storageAvailablePercent, ] } private func deviceInfoMap() -> [String: Any] { let device = UIDevice.current return [ "platform": "ios", "brand": device.systemName, "model": machineIdentifier(), "systemVersion": device.systemVersion, "isPhysicalDevice": !isSimulator(), ] } private func displayName(bundle: Bundle) -> String { if let displayName = bundle.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String { return displayName } return bundle.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "" } private func isSimulator() -> Bool { #if targetEnvironment(simulator) return true #else return false #endif } private func machineIdentifier() -> String { var systemInfo = utsname() uname(&systemInfo) let mirror = Mirror(reflecting: systemInfo.machine) let identifier = mirror.children.reduce(into: "") { value, element in guard let byte = element.value as? Int8, byte != 0 else { return } value.append(String(UnicodeScalar(UInt8(byte)))) } return identifier } }