// // CocosPlayerUtils.swift // flutter_cocos_widget // // Created by Rex Raphael on 30/01/2021. // import Foundation private var cocos_warmed_up = false // Hack to work around iOS SDK 4.3 linker problem // we need at least one __TEXT, __const section entry in main application .o files // to get this section emitted at right time and so avoid LC_ENCRYPTION_INFO size miscalculation private let constsection = 0 // keep arg for cocos init from non main var gArgc: Int32 = 0 var gArgv: UnsafeMutablePointer?>? = nil var appLaunchOpts: [UIApplication.LaunchOptionsKey: Any]? = [:] /***********************************PLUGIN_ENTRY STARTS**************************************/ public func InitCocosIntegration(argc: Int32, argv: UnsafeMutablePointer?>?) { gArgc = argc gArgv = argv } public func InitCocosIntegrationWithOptions( argc: Int32, argv: UnsafeMutablePointer?>?, _ launchingOptions: [UIApplication.LaunchOptionsKey: Any]?) { gArgc = argc gArgv = argv appLaunchOpts = launchingOptions } /***********************************PLUGIN_ENTRY END**************************************/ // Load cocos framework for fisrt run func CocosFrameworkLoad() -> dcocos_bridge? { return dcocos_bridge.instance() } /*********************************** GLOBAL FUNCS & VARS START**************************************/ public var globalControllers: Array = [FLTCocosWidgetController]() private var cocosPlayerUtils: CocosPlayerUtils? = nil func GetCocosPlayerUtils() -> CocosPlayerUtils { if cocosPlayerUtils == nil { cocosPlayerUtils = CocosPlayerUtils() } return cocosPlayerUtils ?? CocosPlayerUtils() } /*********************************** GLOBAL FUNCS & VARS END****************************************/ //var controller: CocosAppController? var sharedApplication: UIApplication? @objc protocol CocosEventListener: AnyObject { func onReceiveMessage(_ message: UnsafePointer?) } @objc public class CocosPlayerUtils: UIResponder, UIApplicationDelegate { var ufw: dcocos_bridge! private var _isCocosPaused = false private var _isCocosReady = false private var _isCocosLoaded = false override init() { super.init() // 监听通知 NotificationCenter.default.addObserver(self, selector: #selector(handleViewWillTransition), name: NSNotification.Name("ViewWillTransition"), object: nil) } deinit { // 移除通知监听 NotificationCenter.default.removeObserver(self) } @objc func handleViewWillTransition(notification: Notification) { guard let size = notification.userInfo?["size"] as? CGSize, let coordinator = notification.userInfo?["coordinator"] as? UIViewControllerTransitionCoordinator else { return } // 处理视图大小变化的逻辑 print("CocosPlayerUtils will transition to size: \(size)") //改正错误 let selector = NSSelectorFromString("viewWillTransitionToSize:withTransitionCoordinator:") if self.ufw.responds(to: selector) { self.ufw.perform(selector, with: size, with: coordinator) } } func initCocos() { if (self.cocosIsInitiallized()) { //todo //self.ufw?.showCocosWindow() return } // 开始生成设备旋转通知 //UIDevice.current.beginGeneratingDeviceOrientationNotifications() self.ufw = CocosFrameworkLoad() // 获取当前Pod库的Bundle let bundle = Bundle(for: dcocos_bridge.self) // 获取 `YourPodResources.bundle` 的路径 if let bundleURL = bundle.url(forResource: "cocos_main_bundle", withExtension: "bundle") { let bundlePath = bundleURL.path print("Bundle absolute path: \(bundlePath)") self.ufw.configureCocos2dSearchPaths(bundlePath) } else { print("Could not find the bundle.") } //self.ufw?.setDataBundleId("com.cocos3d.framework") self.ufw.initPlatform() let application = UIApplication.shared self.ufw.application(application, didFinishLaunchingWithOptions: appLaunchOpts ) registerCocosListener() // self.ufw?.runEmbedded(withArgc: gArgc, argv: gArgv, appLaunchOpts: appLaunchOpts) // if self.ufw?.appController() != nil { // controller = self.ufw?.appController() // controller?.cocosMessageHandler = self.cocosMessageHandlers // controller?.cocosSceneLoadedHandler = self.cocosSceneLoadedHandlers // self.ufw?.appController()?.window?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue - 1) // } _isCocosLoaded = true } // check if cocos is initiallized func cocosIsInitiallized() -> Bool { if self.ufw != nil { return true } return false } // Create new cocos player func createPlayer(completed: @escaping (_ view: UIView?) -> Void) { if self.cocosIsInitiallized() && self._isCocosReady { //todo //completed(controller?.rootView) completed(nil) return } NotificationCenter.default.addObserver(forName: NSNotification.Name("CocosReady"), object: nil, queue: OperationQueue.main, using: { note in self._isCocosReady = true //todo //completed(controller?.rootView) completed(nil) }) DispatchQueue.main.async { // if (sharedApplication == nil) { // sharedApplication = UIApplication.shared // } // Always keep Flutter window on top // let flutterUIWindow = sharedApplication?.keyWindow // flutterUIWindow?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue + 1) // Always keep Flutter window in top // sharedApplication?.keyWindow?.windowLevel = UIWindow.Level(UIWindow.Level.normal.rawValue + 1) self.initCocos() cocos_warmed_up = true self._isCocosReady = true self._isCocosLoaded = true self.listenAppState() //todo //completed(controller?.rootView) completed(nil) } } func registerCocosListener() { if self.cocosIsInitiallized() { // self.ufw?.register(self) } } func unregisterCocosListener() { if self.cocosIsInitiallized() { // self.ufw?.unregisterFrameworkListener(self) } } @objc public func cocosDidUnload(_ notification: Notification!) { unregisterCocosListener() self.ufw = nil self._isCocosReady = false self._isCocosLoaded = false } @objc func handleAppStateDidChange(notification: Notification?) { if !self._isCocosReady { return } //todo //let cocosAppController = self.ufw?.appController() as? CocosAppController // let cocosAppController = nil let application = UIApplication.shared if notification?.name == UIApplication.willResignActiveNotification { self.ufw?.applicationWillResignActive(application) } else if notification?.name == UIApplication.didEnterBackgroundNotification { // self.ufw?.applicationDidEnterBackground(application) } else if notification?.name == UIApplication.willEnterForegroundNotification { // self.ufw?.applicationWillEnterForeground(application) } else if notification?.name == UIApplication.didBecomeActiveNotification { self.ufw?.applicationDidBecomeActive(application) } else if notification?.name == UIApplication.willTerminateNotification { self.ufw?.applicationWillTerminate(application) } else if notification?.name == UIApplication.didReceiveMemoryWarningNotification { // self.ufw?.applicationDidReceiveMemoryWarning(application) } } // Listener for app lifecycle eventa func listenAppState() { for name in [ UIApplication.didBecomeActiveNotification, UIApplication.didEnterBackgroundNotification, UIApplication.willTerminateNotification, UIApplication.willResignActiveNotification, UIApplication.willEnterForegroundNotification, UIApplication.didReceiveMemoryWarningNotification ] { NotificationCenter.default.addObserver( self, selector: #selector(self.handleAppStateDidChange), name: name, object: nil) } } // Pause cocos player func pause() { //todo // self.ufw?.pause(true) self._isCocosPaused = true } // Resume cocos player func resume() { //todo //self.ufw?.pause(false) self._isCocosPaused = false } // Unoad cocos player func unload() { //todo //self.ufw?.unloadApplication() } func isCocosLoaded() -> Bool { return _isCocosLoaded } func isCocosPaused() -> Bool { return _isCocosPaused } // Quit cocos player application func quit() { //todo //self.ufw?.quitApplication(0) self._isCocosLoaded = false } // Post message to cocos func postMessageToCocos(gameObject: String?, cocosMethodName: String?, cocosMessage: String?) { if self.cocosIsInitiallized() { //todo //self.ufw?.sendMessageToGO(withName: gameObject, functionName: cocosMethodName, message: cocosMessage) } } /// Handle incoming cocos messages looping through all controllers and passing payload to /// the controller handler methods @objc func cocosMessageHandlers(_ message: UnsafePointer?) { for c in globalControllers { if let strMsg = message { c.handleMessage(message: String(utf8String: strMsg) ?? "") } else { c.handleMessage(message: "") } } } func cocosSceneLoadedHandlers(name: UnsafePointer?, buildIndex: UnsafePointer?, isLoaded: UnsafePointer?, isValid: UnsafePointer?) { if let sceneName = name, let bIndex = buildIndex, let loaded = isLoaded, let valid = isValid { let loadedVal = Bool((Int(bitPattern: loaded) != 0)) let validVal = Bool((Int(bitPattern: valid) != 0)) let addObject: Dictionary = [ "name": String(utf8String: sceneName) ?? "", "buildIndex": Int(bitPattern: bIndex), "isLoaded": loadedVal, "isValid": validVal, ] for c in globalControllers { c.handleSceneChangeEvent(info: addObject) } } } }