176 lines
6.7 KiB
Swift
176 lines
6.7 KiB
Swift
//import UIKit
|
||
//import Flutter
|
||
//import FirebaseCore
|
||
//import GoogleMaps
|
||
//
|
||
//@main
|
||
//@objc class AppDelegate: FlutterAppDelegate {
|
||
// override func application(
|
||
// _ application: UIApplication,
|
||
// didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||
// ) -> Bool {
|
||
// GMSServices.provideAPIKey(Constants.googleMapsAPIKey)
|
||
// FirebaseApp.configure()
|
||
// GeneratedPluginRegistrant.register(with: self)
|
||
//
|
||
// if JailbreakDetection.isJailbroken() {
|
||
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||
// self.showJailbreakAlert()
|
||
// }
|
||
// }
|
||
//
|
||
// return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||
// }
|
||
//
|
||
// func showJailbreakAlert() {
|
||
// guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { return }
|
||
//
|
||
// let alert = UIAlertController(
|
||
// title: "تحذير أمني",
|
||
// message: "تم اكتشاف أن جهازك يحتوي على جيلبريك. لا يمكن تشغيل التطبيق على هذا الجهاز.",
|
||
// preferredStyle: .alert
|
||
// )
|
||
//
|
||
// alert.addAction(UIAlertAction(title: "إنهاء التطبيق", style: .destructive) { _ in
|
||
// exit(0)
|
||
// })
|
||
//
|
||
// rootVC.present(alert, animated: true, completion: nil)
|
||
// }
|
||
//}
|
||
import UIKit
|
||
import Flutter
|
||
import FirebaseCore
|
||
import GoogleMaps
|
||
|
||
@UIApplicationMain
|
||
@objc class AppDelegate: FlutterAppDelegate {
|
||
|
||
override func application(
|
||
_ application: UIApplication,
|
||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||
) -> Bool {
|
||
|
||
// Load API keys from a secure location (NOT in plain text!)
|
||
// See the "Secure API Key Storage" section below.
|
||
GMSServices.provideAPIKey(Constants.googleMapsAPIKey)
|
||
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
|
||
}
|
||
|
||
}
|
||
// 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: "")
|
||
}
|
||
}
|