import UIKit import Flutter import FirebaseCore import GoogleMaps @main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { if let config = loadConfig() { if let apiKey = config["APIKey"] as? String { print("googleMapsAPIKey: \(Constants.googleMapsAPIKey)") GMSServices.provideAPIKey(apiKey) } } FirebaseApp.configure() GeneratedPluginRegistrant.register(with: self) // Perform security checks *before* showing the main UI if SecurityChecks.isDeviceCompromised() { // Call Objective-C method showSecurityAlert() return false // Prevent app from launching further } //setup method channel setupMethodChannel() return super.application(application, didFinishLaunchingWithOptions: launchOptions) } func setupMethodChannel(){ guard let controller = window?.rootViewController as? FlutterViewController else { return } let channel = FlutterMethodChannel(name: "com.mobileapp.store.ride/security", binaryMessenger: controller.binaryMessenger) channel.setMethodCallHandler { call, result in switch call.method { case "isNativeRooted": // We already check this in isDeviceCompromised, // so we can just return the result directly. result(SecurityChecks.isDeviceCompromised()) default: result(FlutterMethodNotImplemented) } } } func showSecurityAlert() { guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { // Handle the case where rootVC is nil (extremely unlikely, but good practice) exit(0) // return } let alert = UIAlertController( title: "Security Warning".localized, // Use localized strings! message: "Compromised device detected. Exiting.".localized, preferredStyle: .alert ) // Add an "OK" button with an obfuscated action alert.addAction(UIAlertAction(title: "OK".localized, style: .destructive) { _ in // More robust exit (see explanation below) self.obfuscatedExit() }) // Use a presentationDetents to prevent dismissing if #available(iOS 15.0, *) { alert.popoverPresentationController?.sourceView = rootVC.view alert.popoverPresentationController?.sourceRect = CGRect(x: rootVC.view.bounds.midX, y: rootVC.view.bounds.midY, width: 0, height: 0) alert.popoverPresentationController?.permittedArrowDirections = [] alert.presentationController?.delegate = self if let presentationController = alert.presentationController as? UISheetPresentationController { presentationController.detents = [.medium()] // Set a fixed height if desired presentationController.preferredCornerRadius = 20; presentationController.prefersEdgeAttachedInCompactHeight = true;// Set corner radius presentationController.prefersGrabberVisible = false // Optional: show a grabber } } else { // Fallback on earlier versions } rootVC.present(alert, animated: true, completion: nil) } // Obfuscated Exit (Example - you'll need a more robust solution) func obfuscatedExit() { // This is a *very* basic example. A real obfuscation would be MUCH more complex. let selector = NSSelectorFromString(String(format: "%@%@", "ex", "it:")) if responds(to: selector) { perform(selector, with: 0) // Call exit(0) indirectly } } // MARK: - Secure API Key Storage (Example) func getAPIKey() -> String { // DO NOT store API keys directly in your code! // Load it from a more secure location, such as: // 1. A configuration file that is *not* checked into source control. // 2. Keychain Services (recommended for iOS). // 3. A backend server (best option). // This is just a placeholder. Replace with your actual key loading. // In a real app, you'd fetch this from a secure source. guard let filePath = Bundle.main.path(forResource: "keys", ofType: "plist"), let plist = NSDictionary(contentsOfFile: filePath), let apiKey = plist["google_maps_api_key"] as? String else { fatalError("Couldn't find keys or API Key") // Ensure a crash if not found } return apiKey } func loadConfig() -> [String: Any]? { guard let path = Bundle.main.path(forResource: "Config", ofType: "plist"), let config = NSDictionary(contentsOfFile: path) as? [String: Any] else { return nil // Or handle the error appropriately } return config } } // Add for prevent dismissing extension AppDelegate: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { return false } func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) { } } // Add String extension extension String { var localized: String { return NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: "", comment: "") } }