diff --git a/GaiaXJSiOS/.gitignore b/GaiaXJSiOS/.gitignore new file mode 100644 index 000000000..d4b2b8881 --- /dev/null +++ b/GaiaXJSiOS/.gitignore @@ -0,0 +1,5 @@ +Pods +Podfile.lock +.DS_Store + +xcuserdata/ diff --git a/GaiaXJSiOS/GaiaXJS.podspec b/GaiaXJSiOS/GaiaXJS.podspec new file mode 100644 index 000000000..f9db95d62 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.podspec @@ -0,0 +1,21 @@ +Pod::Spec.new do |s| + + s.name = "GaiaXJS" + s.version = "0.1.0" + s.summary = "GaiaXJS" + s.description = "GaiaXJS" + + s.homepage = "https://github.com/alibaba/GaiaX" + + + s.author = { "ronghui1219" => "zrhzhouronghui@qq.com" } + s.platform = :ios, "9.0" + s.source = { :git => "https://github.com/alibaba/GaiaX.git", :tag => "#{s.version}" } + + s.dependency 'GaiaXSocket' + + s.source_files = 'GaiaXJS/**/*.{h,m,mm,c}' + s.resources = 'GaiaXJS/Resources/GaiaXJS.bundle' + s.xcconfig = { "ENABLE_BITCODE" => "NO" } + s.requires_arc = true +end diff --git a/GaiaXJSiOS/GaiaXJS.xcodeproj/project.pbxproj b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.pbxproj new file mode 100644 index 000000000..66f1447df --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.pbxproj @@ -0,0 +1,738 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0660CC07134E389BCFC4B266 /* libPods-GaiaXJS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E010A0793D7A14B1156FF5E9 /* libPods-GaiaXJS.a */; }; + BD036D8126733C4F00F4905B /* GaiaXJS.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BD036D8026733C4F00F4905B /* GaiaXJS.bundle */; }; + BD080D37276B35C2004DD2F9 /* GaiaXJSNativeEventManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BD080D35276B35C2004DD2F9 /* GaiaXJSNativeEventManager.h */; }; + BD080D38276B35C2004DD2F9 /* GaiaXJSNativeEventManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BD080D36276B35C2004DD2F9 /* GaiaXJSNativeEventManager.m */; }; + BD0D20CD265F447A0019D2C1 /* GaiaXJSUIViewModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0D20CB265F447A0019D2C1 /* GaiaXJSUIViewModule.h */; }; + BD0D20CE265F447A0019D2C1 /* GaiaXJSUIViewModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD0D20CC265F447A0019D2C1 /* GaiaXJSUIViewModule.m */; }; + BD0D20D1265F44900019D2C1 /* GaiaXJSUITextModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0D20CF265F44900019D2C1 /* GaiaXJSUITextModule.h */; }; + BD0D20D2265F44900019D2C1 /* GaiaXJSUITextModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD0D20D0265F44900019D2C1 /* GaiaXJSUITextModule.m */; }; + BD0D20D5265F44A40019D2C1 /* GaiaXJSUIImageModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0D20D3265F44A40019D2C1 /* GaiaXJSUIImageModule.h */; }; + BD0D20D6265F44A40019D2C1 /* GaiaXJSUIImageModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD0D20D4265F44A40019D2C1 /* GaiaXJSUIImageModule.m */; }; + BD0D20E0265F81EA0019D2C1 /* GaiaXJSUIManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0D20DE265F81EA0019D2C1 /* GaiaXJSUIManager.h */; }; + BD0D20E1265F81EA0019D2C1 /* GaiaXJSUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BD0D20DF265F81EA0019D2C1 /* GaiaXJSUIManager.m */; }; + BD0D20E5266A0A680019D2C1 /* GaiaXJSCModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0D20E3266A0A670019D2C1 /* GaiaXJSCModule.h */; }; + BD0D20E6266A0A680019D2C1 /* GaiaXJSCModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD0D20E4266A0A670019D2C1 /* GaiaXJSCModule.m */; }; + BD3EA8502923ACB200930593 /* GaiaXJSHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = BD3EA84E2923ACB200930593 /* GaiaXJSHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD3EA8512923ACB200930593 /* GaiaXJSHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = BD3EA84F2923ACB200930593 /* GaiaXJSHandler.m */; }; + BD6B494228E297D600642266 /* GaiaXJSConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = BD6B494028E297D600642266 /* GaiaXJSConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD6B494328E297D600642266 /* GaiaXJSConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = BD6B494128E297D600642266 /* GaiaXJSConfig.m */; }; + BD7FF07B2659FCF4007BEC87 /* GaiaXJSFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = BD7FF0792659FCF4007BEC87 /* GaiaXJSFactory.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BD7FF07C2659FCF4007BEC87 /* GaiaXJSFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7FF07A2659FCF4007BEC87 /* GaiaXJSFactory.m */; }; + BD7FF085265A451F007BEC87 /* GaiaXJSCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = BD7FF083265A451F007BEC87 /* GaiaXJSCRuntime.h */; }; + BD7FF086265A451F007BEC87 /* GaiaXJSCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7FF084265A451F007BEC87 /* GaiaXJSCRuntime.m */; }; + BD81B20127EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = BD81B1FF27EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.h */; }; + BD81B20227EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = BD81B20027EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.m */; }; + BD81B20727EB4190006E8C2F /* GaiaXJSDRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = BD81B20527EB4190006E8C2F /* GaiaXJSDRuntime.h */; }; + BD81B20827EB4190006E8C2F /* GaiaXJSDRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = BD81B20627EB4190006E8C2F /* GaiaXJSDRuntime.m */; }; + BD81B20B27EB42DA006E8C2F /* GaiaXJSDebuggerContext.h in Headers */ = {isa = PBXBuildFile; fileRef = BD81B20927EB42DA006E8C2F /* GaiaXJSDebuggerContext.h */; }; + BD81B20C27EB42DA006E8C2F /* GaiaXJSDebuggerContext.m in Sources */ = {isa = PBXBuildFile; fileRef = BD81B20A27EB42DA006E8C2F /* GaiaXJSDebuggerContext.m */; }; + BDB8F92C268571050086B96B /* GaiaXJSNativeTargetModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BDB8F92A268571050086B96B /* GaiaXJSNativeTargetModule.h */; }; + BDB8F92D268571060086B96B /* GaiaXJSNativeTargetModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BDB8F92B268571050086B96B /* GaiaXJSNativeTargetModule.m */; }; + BDBD016426C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.h in Headers */ = {isa = PBXBuildFile; fileRef = BDBD016226C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.h */; }; + BDBD016526C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.m in Sources */ = {isa = PBXBuildFile; fileRef = BDBD016326C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.m */; }; + BDF3E9E2291CEAB500384660 /* GaiaXJSModulesImplDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF3E9E1291CEAB500384660 /* GaiaXJSModulesImplDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF3E9E4291CEF0400384660 /* GaiaXJSExecPhaseImplDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF3E9E3291CEF0400384660 /* GaiaXJSExecPhaseImplDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF42262264AA6910090A231 /* GaiaXJS.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF42260264AA6910090A231 /* GaiaXJS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422B1264AA9470090A231 /* GaiaXJSRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422AF264AA9470090A231 /* GaiaXJSRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422B2264AA9470090A231 /* GaiaXJSRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422B0264AA9470090A231 /* GaiaXJSRuntime.m */; }; + BDF422B5264AA97F0090A231 /* GaiaXJSContext.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422B3264AA97F0090A231 /* GaiaXJSContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422B6264AA97F0090A231 /* GaiaXJSContext.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422B4264AA97F0090A231 /* GaiaXJSContext.m */; }; + BDF422B9264AA9B00090A231 /* GaiaXJSComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422B7264AA9B00090A231 /* GaiaXJSComponent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422BA264AA9B00090A231 /* GaiaXJSComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422B8264AA9B00090A231 /* GaiaXJSComponent.m */; }; + BDF422C5264AB1CB0090A231 /* GaiaXJSModuleManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422C3264AB1CB0090A231 /* GaiaXJSModuleManager.h */; }; + BDF422C6264AB1CB0090A231 /* GaiaXJSModuleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422C4264AB1CB0090A231 /* GaiaXJSModuleManager.m */; }; + BDF422C9264AB2300090A231 /* GaiaXJSHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422C7264AB2300090A231 /* GaiaXJSHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422CA264AB2300090A231 /* GaiaXJSHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422C8264AB2300090A231 /* GaiaXJSHelper.m */; }; + BDF422CD264AB2970090A231 /* GaiaXJSModuleInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422CB264AB2970090A231 /* GaiaXJSModuleInfo.h */; }; + BDF422CE264AB2970090A231 /* GaiaXJSModuleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422CC264AB2970090A231 /* GaiaXJSModuleInfo.m */; }; + BDF422D1264AB2A50090A231 /* GaiaXJSMethodInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422CF264AB2A50090A231 /* GaiaXJSMethodInfo.h */; }; + BDF422D2264AB2A50090A231 /* GaiaXJSMethodInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422D0264AB2A50090A231 /* GaiaXJSMethodInfo.m */; }; + BDF422D9264AB3200090A231 /* GaiaXJSMethodArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422D7264AB3200090A231 /* GaiaXJSMethodArgument.h */; }; + BDF422DA264AB3200090A231 /* GaiaXJSMethodArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422D8264AB3200090A231 /* GaiaXJSMethodArgument.m */; }; + BDF422E4264B7CF20090A231 /* GaiaXJSBuiltInModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422E2264B7CF20090A231 /* GaiaXJSBuiltInModule.m */; }; + BDF422E5264B7CF20090A231 /* GaiaXJSBuiltInModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422E3264B7CF20090A231 /* GaiaXJSBuiltInModule.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422E7264B7ED50090A231 /* GaiaXJSDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422E6264B7ED50090A231 /* GaiaXJSDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422EA264B851F0090A231 /* GaiaXJSNativeEventModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422E8264B851F0090A231 /* GaiaXJSNativeEventModule.m */; }; + BDF422EB264B851F0090A231 /* GaiaXJSNativeEventModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422E9264B851F0090A231 /* GaiaXJSNativeEventModule.h */; }; + BDF422EF264BC32D0090A231 /* GaiaXJSBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422ED264BC32D0090A231 /* GaiaXJSBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDF422F0264BC32D0090A231 /* GaiaXJSBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422EE264BC32D0090A231 /* GaiaXJSBridge.m */; }; + BDF422F8264BD4D90090A231 /* GaiaXJSCContext.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422F6264BD4D90090A231 /* GaiaXJSCContext.h */; }; + BDF422F9264BD4D90090A231 /* GaiaXJSCContext.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422F7264BD4D90090A231 /* GaiaXJSCContext.m */; }; + BDF422FE264CC92E0090A231 /* GaiaXJSNativeLoggerModule.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF422FC264CC92E0090A231 /* GaiaXJSNativeLoggerModule.h */; }; + BDF422FF264CC92E0090A231 /* GaiaXJSNativeLoggerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF422FD264CC92E0090A231 /* GaiaXJSNativeLoggerModule.m */; }; + BDF42302264D48080090A231 /* GaiaXJSConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF42300264D48080090A231 /* GaiaXJSConvert.h */; }; + BDF42303264D48080090A231 /* GaiaXJSConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = BDF42301264D48080090A231 /* GaiaXJSConvert.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 4847A23FC9EAFCF6E8F44B2F /* Pods-GaiaXJS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXJS.release.xcconfig"; path = "Pods/Target Support Files/Pods-GaiaXJS/Pods-GaiaXJS.release.xcconfig"; sourceTree = ""; }; + B8D605B5BC5198BF7D9CA293 /* Pods-GaiaXJS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXJS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GaiaXJS/Pods-GaiaXJS.debug.xcconfig"; sourceTree = ""; }; + BD036D8026733C4F00F4905B /* GaiaXJS.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = GaiaXJS.bundle; sourceTree = ""; }; + BD080D35276B35C2004DD2F9 /* GaiaXJSNativeEventManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSNativeEventManager.h; sourceTree = ""; }; + BD080D36276B35C2004DD2F9 /* GaiaXJSNativeEventManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSNativeEventManager.m; sourceTree = ""; }; + BD0D20CB265F447A0019D2C1 /* GaiaXJSUIViewModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSUIViewModule.h; sourceTree = ""; }; + BD0D20CC265F447A0019D2C1 /* GaiaXJSUIViewModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSUIViewModule.m; sourceTree = ""; }; + BD0D20CF265F44900019D2C1 /* GaiaXJSUITextModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSUITextModule.h; sourceTree = ""; }; + BD0D20D0265F44900019D2C1 /* GaiaXJSUITextModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSUITextModule.m; sourceTree = ""; }; + BD0D20D3265F44A40019D2C1 /* GaiaXJSUIImageModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSUIImageModule.h; sourceTree = ""; }; + BD0D20D4265F44A40019D2C1 /* GaiaXJSUIImageModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSUIImageModule.m; sourceTree = ""; }; + BD0D20DE265F81EA0019D2C1 /* GaiaXJSUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSUIManager.h; sourceTree = ""; }; + BD0D20DF265F81EA0019D2C1 /* GaiaXJSUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSUIManager.m; sourceTree = ""; }; + BD0D20E3266A0A670019D2C1 /* GaiaXJSCModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSCModule.h; sourceTree = ""; }; + BD0D20E4266A0A670019D2C1 /* GaiaXJSCModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSCModule.m; sourceTree = ""; }; + BD3EA84E2923ACB200930593 /* GaiaXJSHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSHandler.h; sourceTree = ""; }; + BD3EA84F2923ACB200930593 /* GaiaXJSHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSHandler.m; sourceTree = ""; }; + BD6B494028E297D600642266 /* GaiaXJSConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSConfig.h; sourceTree = ""; }; + BD6B494128E297D600642266 /* GaiaXJSConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSConfig.m; sourceTree = ""; }; + BD7FF0792659FCF4007BEC87 /* GaiaXJSFactory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSFactory.h; sourceTree = ""; }; + BD7FF07A2659FCF4007BEC87 /* GaiaXJSFactory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSFactory.m; sourceTree = ""; }; + BD7FF083265A451F007BEC87 /* GaiaXJSCRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSCRuntime.h; sourceTree = ""; }; + BD7FF084265A451F007BEC87 /* GaiaXJSCRuntime.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSCRuntime.m; sourceTree = ""; }; + BD81B1FF27EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSWebSocketWrapper.h; sourceTree = ""; }; + BD81B20027EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSWebSocketWrapper.m; sourceTree = ""; }; + BD81B20527EB4190006E8C2F /* GaiaXJSDRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSDRuntime.h; sourceTree = ""; }; + BD81B20627EB4190006E8C2F /* GaiaXJSDRuntime.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSDRuntime.m; sourceTree = ""; }; + BD81B20927EB42DA006E8C2F /* GaiaXJSDebuggerContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSDebuggerContext.h; sourceTree = ""; }; + BD81B20A27EB42DA006E8C2F /* GaiaXJSDebuggerContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSDebuggerContext.m; sourceTree = ""; }; + BDB8F92A268571050086B96B /* GaiaXJSNativeTargetModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSNativeTargetModule.h; sourceTree = ""; }; + BDB8F92B268571050086B96B /* GaiaXJSNativeTargetModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSNativeTargetModule.m; sourceTree = ""; }; + BDBD016226C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GaiaXJSBuiltInModule+Storage.h"; sourceTree = ""; }; + BDBD016326C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "GaiaXJSBuiltInModule+Storage.m"; sourceTree = ""; }; + BDF3E9E1291CEAB500384660 /* GaiaXJSModulesImplDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSModulesImplDelegate.h; sourceTree = ""; }; + BDF3E9E3291CEF0400384660 /* GaiaXJSExecPhaseImplDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSExecPhaseImplDelegate.h; sourceTree = ""; }; + BDF4225D264AA6910090A231 /* GaiaXJS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GaiaXJS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BDF42260264AA6910090A231 /* GaiaXJS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJS.h; sourceTree = ""; }; + BDF42261264AA6910090A231 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + BDF422AF264AA9470090A231 /* GaiaXJSRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSRuntime.h; sourceTree = ""; }; + BDF422B0264AA9470090A231 /* GaiaXJSRuntime.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSRuntime.m; sourceTree = ""; }; + BDF422B3264AA97F0090A231 /* GaiaXJSContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSContext.h; sourceTree = ""; }; + BDF422B4264AA97F0090A231 /* GaiaXJSContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSContext.m; sourceTree = ""; }; + BDF422B7264AA9B00090A231 /* GaiaXJSComponent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSComponent.h; sourceTree = ""; }; + BDF422B8264AA9B00090A231 /* GaiaXJSComponent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSComponent.m; sourceTree = ""; }; + BDF422C3264AB1CB0090A231 /* GaiaXJSModuleManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSModuleManager.h; sourceTree = ""; }; + BDF422C4264AB1CB0090A231 /* GaiaXJSModuleManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSModuleManager.m; sourceTree = ""; }; + BDF422C7264AB2300090A231 /* GaiaXJSHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSHelper.h; sourceTree = ""; }; + BDF422C8264AB2300090A231 /* GaiaXJSHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSHelper.m; sourceTree = ""; }; + BDF422CB264AB2970090A231 /* GaiaXJSModuleInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSModuleInfo.h; sourceTree = ""; }; + BDF422CC264AB2970090A231 /* GaiaXJSModuleInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSModuleInfo.m; sourceTree = ""; }; + BDF422CF264AB2A50090A231 /* GaiaXJSMethodInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSMethodInfo.h; sourceTree = ""; }; + BDF422D0264AB2A50090A231 /* GaiaXJSMethodInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSMethodInfo.m; sourceTree = ""; }; + BDF422D7264AB3200090A231 /* GaiaXJSMethodArgument.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSMethodArgument.h; sourceTree = ""; }; + BDF422D8264AB3200090A231 /* GaiaXJSMethodArgument.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSMethodArgument.m; sourceTree = ""; }; + BDF422E2264B7CF20090A231 /* GaiaXJSBuiltInModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSBuiltInModule.m; sourceTree = ""; }; + BDF422E3264B7CF20090A231 /* GaiaXJSBuiltInModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSBuiltInModule.h; sourceTree = ""; }; + BDF422E6264B7ED50090A231 /* GaiaXJSDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSDefines.h; sourceTree = ""; }; + BDF422E8264B851F0090A231 /* GaiaXJSNativeEventModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSNativeEventModule.m; sourceTree = ""; }; + BDF422E9264B851F0090A231 /* GaiaXJSNativeEventModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSNativeEventModule.h; sourceTree = ""; }; + BDF422ED264BC32D0090A231 /* GaiaXJSBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSBridge.h; sourceTree = ""; }; + BDF422EE264BC32D0090A231 /* GaiaXJSBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSBridge.m; sourceTree = ""; }; + BDF422F6264BD4D90090A231 /* GaiaXJSCContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSCContext.h; sourceTree = ""; }; + BDF422F7264BD4D90090A231 /* GaiaXJSCContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSCContext.m; sourceTree = ""; }; + BDF422FC264CC92E0090A231 /* GaiaXJSNativeLoggerModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXJSNativeLoggerModule.h; sourceTree = ""; }; + BDF422FD264CC92E0090A231 /* GaiaXJSNativeLoggerModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSNativeLoggerModule.m; sourceTree = ""; }; + BDF42300264D48080090A231 /* GaiaXJSConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSConvert.h; sourceTree = ""; }; + BDF42301264D48080090A231 /* GaiaXJSConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSConvert.m; sourceTree = ""; }; + E010A0793D7A14B1156FF5E9 /* libPods-GaiaXJS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-GaiaXJS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BDF4225A264AA6910090A231 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0660CC07134E389BCFC4B266 /* libPods-GaiaXJS.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 6983E0E9333631574902CFAE /* Pods */ = { + isa = PBXGroup; + children = ( + B8D605B5BC5198BF7D9CA293 /* Pods-GaiaXJS.debug.xcconfig */, + 4847A23FC9EAFCF6E8F44B2F /* Pods-GaiaXJS.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + BD036D7F26733C4F00F4905B /* Resources */ = { + isa = PBXGroup; + children = ( + BD036D8026733C4F00F4905B /* GaiaXJS.bundle */, + ); + path = Resources; + sourceTree = ""; + }; + BD0D20CA265F44090019D2C1 /* uis */ = { + isa = PBXGroup; + children = ( + BD0D20CB265F447A0019D2C1 /* GaiaXJSUIViewModule.h */, + BD0D20CC265F447A0019D2C1 /* GaiaXJSUIViewModule.m */, + BD0D20CF265F44900019D2C1 /* GaiaXJSUITextModule.h */, + BD0D20D0265F44900019D2C1 /* GaiaXJSUITextModule.m */, + BD0D20D3265F44A40019D2C1 /* GaiaXJSUIImageModule.h */, + BD0D20D4265F44A40019D2C1 /* GaiaXJSUIImageModule.m */, + ); + path = uis; + sourceTree = ""; + }; + BD0D20DC265F81EA0019D2C1 /* module */ = { + isa = PBXGroup; + children = ( + BDF422C3264AB1CB0090A231 /* GaiaXJSModuleManager.h */, + BDF422C4264AB1CB0090A231 /* GaiaXJSModuleManager.m */, + BDF422CB264AB2970090A231 /* GaiaXJSModuleInfo.h */, + BDF422CC264AB2970090A231 /* GaiaXJSModuleInfo.m */, + BDF422CF264AB2A50090A231 /* GaiaXJSMethodInfo.h */, + BDF422D0264AB2A50090A231 /* GaiaXJSMethodInfo.m */, + BDF422D7264AB3200090A231 /* GaiaXJSMethodArgument.h */, + BDF422D8264AB3200090A231 /* GaiaXJSMethodArgument.m */, + ); + path = module; + sourceTree = ""; + }; + BD0D20DD265F81EA0019D2C1 /* ui */ = { + isa = PBXGroup; + children = ( + BD0D20DE265F81EA0019D2C1 /* GaiaXJSUIManager.h */, + BD0D20DF265F81EA0019D2C1 /* GaiaXJSUIManager.m */, + ); + path = ui; + sourceTree = ""; + }; + BD0D20E2266A0A540019D2C1 /* jscore */ = { + isa = PBXGroup; + children = ( + BD0D20E3266A0A670019D2C1 /* GaiaXJSCModule.h */, + BD0D20E4266A0A670019D2C1 /* GaiaXJSCModule.m */, + ); + path = jscore; + sourceTree = ""; + }; + BD7FF081265A44EC007BEC87 /* context */ = { + isa = PBXGroup; + children = ( + BDF422B3264AA97F0090A231 /* GaiaXJSContext.h */, + BDF422B4264AA97F0090A231 /* GaiaXJSContext.m */, + BDF422F6264BD4D90090A231 /* GaiaXJSCContext.h */, + BDF422F7264BD4D90090A231 /* GaiaXJSCContext.m */, + BD81B20927EB42DA006E8C2F /* GaiaXJSDebuggerContext.h */, + BD81B20A27EB42DA006E8C2F /* GaiaXJSDebuggerContext.m */, + ); + path = context; + sourceTree = ""; + }; + BD7FF082265A44EC007BEC87 /* runtime */ = { + isa = PBXGroup; + children = ( + BDF422AF264AA9470090A231 /* GaiaXJSRuntime.h */, + BDF422B0264AA9470090A231 /* GaiaXJSRuntime.m */, + BD7FF083265A451F007BEC87 /* GaiaXJSCRuntime.h */, + BD7FF084265A451F007BEC87 /* GaiaXJSCRuntime.m */, + BD81B20527EB4190006E8C2F /* GaiaXJSDRuntime.h */, + BD81B20627EB4190006E8C2F /* GaiaXJSDRuntime.m */, + ); + path = runtime; + sourceTree = ""; + }; + BD7FF087265A5D52007BEC87 /* component */ = { + isa = PBXGroup; + children = ( + BDF422B7264AA9B00090A231 /* GaiaXJSComponent.h */, + BDF422B8264AA9B00090A231 /* GaiaXJSComponent.m */, + ); + path = component; + sourceTree = ""; + }; + BD81B1FE27EAB88F006E8C2F /* debugger */ = { + isa = PBXGroup; + children = ( + BD81B1FF27EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.h */, + BD81B20027EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.m */, + ); + path = debugger; + sourceTree = ""; + }; + BDF42253264AA6900090A231 = { + isa = PBXGroup; + children = ( + BDF4225F264AA6910090A231 /* GaiaXJS */, + BDF4225E264AA6910090A231 /* Products */, + BDF422DF264B7B970090A231 /* Frameworks */, + 6983E0E9333631574902CFAE /* Pods */, + ); + sourceTree = ""; + }; + BDF4225E264AA6910090A231 /* Products */ = { + isa = PBXGroup; + children = ( + BDF4225D264AA6910090A231 /* GaiaXJS.framework */, + ); + name = Products; + sourceTree = ""; + }; + BDF4225F264AA6910090A231 /* GaiaXJS */ = { + isa = PBXGroup; + children = ( + BD036D7F26733C4F00F4905B /* Resources */, + BDF42289264AA7A40090A231 /* src */, + BDF42260264AA6910090A231 /* GaiaXJS.h */, + BDF42261264AA6910090A231 /* Info.plist */, + ); + path = GaiaXJS; + sourceTree = ""; + }; + BDF42289264AA7A40090A231 /* src */ = { + isa = PBXGroup; + children = ( + BDF422E6264B7ED50090A231 /* GaiaXJSDefines.h */, + BDF422C7264AB2300090A231 /* GaiaXJSHelper.h */, + BDF422C8264AB2300090A231 /* GaiaXJSHelper.m */, + BD7FF0792659FCF4007BEC87 /* GaiaXJSFactory.h */, + BD7FF07A2659FCF4007BEC87 /* GaiaXJSFactory.m */, + BD6B494028E297D600642266 /* GaiaXJSConfig.h */, + BD6B494128E297D600642266 /* GaiaXJSConfig.m */, + BD3EA84E2923ACB200930593 /* GaiaXJSHandler.h */, + BD3EA84F2923ACB200930593 /* GaiaXJSHandler.m */, + BD81B1FE27EAB88F006E8C2F /* debugger */, + BD7FF087265A5D52007BEC87 /* component */, + BD7FF081265A44EC007BEC87 /* context */, + BD7FF082265A44EC007BEC87 /* runtime */, + BDF422EC264BC2620090A231 /* bridge */, + BDF422C2264AB1A70090A231 /* wrapper */, + BDF3E9E1291CEAB500384660 /* GaiaXJSModulesImplDelegate.h */, + BDF3E9E3291CEF0400384660 /* GaiaXJSExecPhaseImplDelegate.h */, + ); + path = src; + sourceTree = ""; + }; + BDF422C2264AB1A70090A231 /* wrapper */ = { + isa = PBXGroup; + children = ( + BD0D20DC265F81EA0019D2C1 /* module */, + BD0D20DD265F81EA0019D2C1 /* ui */, + ); + path = wrapper; + sourceTree = ""; + }; + BDF422DF264B7B970090A231 /* Frameworks */ = { + isa = PBXGroup; + children = ( + E010A0793D7A14B1156FF5E9 /* libPods-GaiaXJS.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + BDF422E1264B7C930090A231 /* modules */ = { + isa = PBXGroup; + children = ( + BD080D35276B35C2004DD2F9 /* GaiaXJSNativeEventManager.h */, + BD080D36276B35C2004DD2F9 /* GaiaXJSNativeEventManager.m */, + BDF422E9264B851F0090A231 /* GaiaXJSNativeEventModule.h */, + BDF422E8264B851F0090A231 /* GaiaXJSNativeEventModule.m */, + BDF422FC264CC92E0090A231 /* GaiaXJSNativeLoggerModule.h */, + BDF422FD264CC92E0090A231 /* GaiaXJSNativeLoggerModule.m */, + BDB8F92A268571050086B96B /* GaiaXJSNativeTargetModule.h */, + BDB8F92B268571050086B96B /* GaiaXJSNativeTargetModule.m */, + BDF422E3264B7CF20090A231 /* GaiaXJSBuiltInModule.h */, + BDF422E2264B7CF20090A231 /* GaiaXJSBuiltInModule.m */, + BDBD016226C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.h */, + BDBD016326C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.m */, + ); + path = modules; + sourceTree = ""; + }; + BDF422EC264BC2620090A231 /* bridge */ = { + isa = PBXGroup; + children = ( + BDF42300264D48080090A231 /* GaiaXJSConvert.h */, + BDF42301264D48080090A231 /* GaiaXJSConvert.m */, + BDF422ED264BC32D0090A231 /* GaiaXJSBridge.h */, + BDF422EE264BC32D0090A231 /* GaiaXJSBridge.m */, + BD0D20E2266A0A540019D2C1 /* jscore */, + BD0D20CA265F44090019D2C1 /* uis */, + BDF422E1264B7C930090A231 /* modules */, + ); + path = bridge; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + BDF42258264AA6910090A231 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BD3EA8502923ACB200930593 /* GaiaXJSHandler.h in Headers */, + BDF3E9E2291CEAB500384660 /* GaiaXJSModulesImplDelegate.h in Headers */, + BDF3E9E4291CEF0400384660 /* GaiaXJSExecPhaseImplDelegate.h in Headers */, + BD81B20727EB4190006E8C2F /* GaiaXJSDRuntime.h in Headers */, + BDF422C9264AB2300090A231 /* GaiaXJSHelper.h in Headers */, + BD6B494228E297D600642266 /* GaiaXJSConfig.h in Headers */, + BDF422EF264BC32D0090A231 /* GaiaXJSBridge.h in Headers */, + BD81B20127EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.h in Headers */, + BDF422E7264B7ED50090A231 /* GaiaXJSDefines.h in Headers */, + BDF422E5264B7CF20090A231 /* GaiaXJSBuiltInModule.h in Headers */, + BD080D37276B35C2004DD2F9 /* GaiaXJSNativeEventManager.h in Headers */, + BD7FF07B2659FCF4007BEC87 /* GaiaXJSFactory.h in Headers */, + BDF422B9264AA9B00090A231 /* GaiaXJSComponent.h in Headers */, + BD0D20D1265F44900019D2C1 /* GaiaXJSUITextModule.h in Headers */, + BDBD016426C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.h in Headers */, + BD7FF085265A451F007BEC87 /* GaiaXJSCRuntime.h in Headers */, + BDF422EB264B851F0090A231 /* GaiaXJSNativeEventModule.h in Headers */, + BDF422B5264AA97F0090A231 /* GaiaXJSContext.h in Headers */, + BDF422B1264AA9470090A231 /* GaiaXJSRuntime.h in Headers */, + BD0D20CD265F447A0019D2C1 /* GaiaXJSUIViewModule.h in Headers */, + BDF422D9264AB3200090A231 /* GaiaXJSMethodArgument.h in Headers */, + BDF42302264D48080090A231 /* GaiaXJSConvert.h in Headers */, + BD0D20E0265F81EA0019D2C1 /* GaiaXJSUIManager.h in Headers */, + BD0D20E5266A0A680019D2C1 /* GaiaXJSCModule.h in Headers */, + BD81B20B27EB42DA006E8C2F /* GaiaXJSDebuggerContext.h in Headers */, + BDF422FE264CC92E0090A231 /* GaiaXJSNativeLoggerModule.h in Headers */, + BD0D20D5265F44A40019D2C1 /* GaiaXJSUIImageModule.h in Headers */, + BDB8F92C268571050086B96B /* GaiaXJSNativeTargetModule.h in Headers */, + BDF422C5264AB1CB0090A231 /* GaiaXJSModuleManager.h in Headers */, + BDF42262264AA6910090A231 /* GaiaXJS.h in Headers */, + BDF422D1264AB2A50090A231 /* GaiaXJSMethodInfo.h in Headers */, + BDF422F8264BD4D90090A231 /* GaiaXJSCContext.h in Headers */, + BDF422CD264AB2970090A231 /* GaiaXJSModuleInfo.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + BDF4225C264AA6910090A231 /* GaiaXJS */ = { + isa = PBXNativeTarget; + buildConfigurationList = BDF42265264AA6910090A231 /* Build configuration list for PBXNativeTarget "GaiaXJS" */; + buildPhases = ( + B905D0FE0092B8A2A5EAF670 /* [CP] Check Pods Manifest.lock */, + BDF42258264AA6910090A231 /* Headers */, + BDF42259264AA6910090A231 /* Sources */, + BDF4225A264AA6910090A231 /* Frameworks */, + BDF4225B264AA6910090A231 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GaiaXJS; + productName = GaiaXJS; + productReference = BDF4225D264AA6910090A231 /* GaiaXJS.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BDF42254264AA6910090A231 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1250; + TargetAttributes = { + BDF4225C264AA6910090A231 = { + CreatedOnToolsVersion = 12.5; + }; + }; + }; + buildConfigurationList = BDF42257264AA6910090A231 /* Build configuration list for PBXProject "GaiaXJS" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BDF42253264AA6900090A231; + productRefGroup = BDF4225E264AA6910090A231 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BDF4225C264AA6910090A231 /* GaiaXJS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BDF4225B264AA6910090A231 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BD036D8126733C4F00F4905B /* GaiaXJS.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + B905D0FE0092B8A2A5EAF670 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-GaiaXJS-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BDF42259264AA6910090A231 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BDF422D2264AB2A50090A231 /* GaiaXJSMethodInfo.m in Sources */, + BD7FF07C2659FCF4007BEC87 /* GaiaXJSFactory.m in Sources */, + BDF42303264D48080090A231 /* GaiaXJSConvert.m in Sources */, + BD6B494328E297D600642266 /* GaiaXJSConfig.m in Sources */, + BD3EA8512923ACB200930593 /* GaiaXJSHandler.m in Sources */, + BDF422CA264AB2300090A231 /* GaiaXJSHelper.m in Sources */, + BD81B20227EAB8D1006E8C2F /* GaiaXJSWebSocketWrapper.m in Sources */, + BDF422EA264B851F0090A231 /* GaiaXJSNativeEventModule.m in Sources */, + BD0D20E1265F81EA0019D2C1 /* GaiaXJSUIManager.m in Sources */, + BDF422F0264BC32D0090A231 /* GaiaXJSBridge.m in Sources */, + BD81B20C27EB42DA006E8C2F /* GaiaXJSDebuggerContext.m in Sources */, + BDF422E4264B7CF20090A231 /* GaiaXJSBuiltInModule.m in Sources */, + BDF422BA264AA9B00090A231 /* GaiaXJSComponent.m in Sources */, + BD0D20CE265F447A0019D2C1 /* GaiaXJSUIViewModule.m in Sources */, + BDF422B2264AA9470090A231 /* GaiaXJSRuntime.m in Sources */, + BDF422C6264AB1CB0090A231 /* GaiaXJSModuleManager.m in Sources */, + BDF422FF264CC92E0090A231 /* GaiaXJSNativeLoggerModule.m in Sources */, + BD0D20D2265F44900019D2C1 /* GaiaXJSUITextModule.m in Sources */, + BDF422B6264AA97F0090A231 /* GaiaXJSContext.m in Sources */, + BDB8F92D268571060086B96B /* GaiaXJSNativeTargetModule.m in Sources */, + BD7FF086265A451F007BEC87 /* GaiaXJSCRuntime.m in Sources */, + BD81B20827EB4190006E8C2F /* GaiaXJSDRuntime.m in Sources */, + BD0D20E6266A0A680019D2C1 /* GaiaXJSCModule.m in Sources */, + BDF422CE264AB2970090A231 /* GaiaXJSModuleInfo.m in Sources */, + BDF422DA264AB3200090A231 /* GaiaXJSMethodArgument.m in Sources */, + BD080D38276B35C2004DD2F9 /* GaiaXJSNativeEventManager.m in Sources */, + BD0D20D6265F44A40019D2C1 /* GaiaXJSUIImageModule.m in Sources */, + BDBD016526C3EC2700D468FC /* GaiaXJSBuiltInModule+Storage.m in Sources */, + BDF422F9264BD4D90090A231 /* GaiaXJSCContext.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + BDF42263264AA6910090A231 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + BDF42264264AA6910090A231 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + BDF42266264AA6910090A231 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B8D605B5BC5198BF7D9CA293 /* Pods-GaiaXJS.debug.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = W4ZRQF48G9; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = GaiaXJS/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = com.youku.gaiaxjs; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + BDF42267264AA6910090A231 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4847A23FC9EAFCF6E8F44B2F /* Pods-GaiaXJS.release.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = W4ZRQF48G9; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = z; + INFOPLIST_FILE = GaiaXJS/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + PRODUCT_BUNDLE_IDENTIFIER = com.youku.gaiaxjs; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BDF42257264AA6910090A231 /* Build configuration list for PBXProject "GaiaXJS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BDF42263264AA6910090A231 /* Debug */, + BDF42264264AA6910090A231 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BDF42265264AA6910090A231 /* Build configuration list for PBXNativeTarget "GaiaXJS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BDF42266264AA6910090A231 /* Debug */, + BDF42267264AA6910090A231 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BDF42254264AA6910090A231 /* Project object */; +} diff --git a/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GaiaXJSiOS/GaiaXJS.xcodeproj/xcshareddata/xcschemes/GaiaXJS.xcscheme b/GaiaXJSiOS/GaiaXJS.xcodeproj/xcshareddata/xcschemes/GaiaXJS.xcscheme new file mode 100644 index 000000000..b57980306 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.xcodeproj/xcshareddata/xcschemes/GaiaXJS.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GaiaXJSiOS/GaiaXJS.xcworkspace/contents.xcworkspacedata b/GaiaXJSiOS/GaiaXJS.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..bf4da9afd --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/GaiaXJSiOS/GaiaXJS/GaiaXJS.h b/GaiaXJSiOS/GaiaXJS/GaiaXJS.h new file mode 100644 index 000000000..3fed90c2b --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/GaiaXJS.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +//! Project version number for GaiaXJS. +FOUNDATION_EXPORT double GaiaXJSVersionNumber; + +//! Project version string for GaiaXJS. +FOUNDATION_EXPORT const unsigned char GaiaXJSVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/GaiaXJSiOS/GaiaXJS/Info.plist b/GaiaXJSiOS/GaiaXJS/Info.plist new file mode 100644 index 000000000..aa7f2b80a --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/GaiaXJSiOS/GaiaXJS/Resources/GaiaXJS.bundle/bootstrap.min.js b/GaiaXJSiOS/GaiaXJS/Resources/GaiaXJS.bundle/bootstrap.min.js new file mode 100644 index 000000000..73d214df3 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/Resources/GaiaXJS.bundle/bootstrap.min.js @@ -0,0 +1 @@ +Object.entries||(Object.entries=function(e){for(var t=Object.keys(e),n=t.length,a=new Array(n);n--;)a[n]=[t[n],e[t[n]]];return a}),Object.values||(Object.values=function(e){if(e!==Object(e))throw new TypeError("Object.values called on a non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(e[t]);return n});var pEventData=new WeakMap;function ped(e){var t=pEventData.get(e);if(null==t)throw new Error("'this' is expected an Event object, but got "+e);return t}var GaiaXJSEvent=function(){function e(e){pEventData.set(this,e)}return Object.defineProperty(e.prototype,"templateId",{get:function(){return ped(this).templateId},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"instanceId",{get:function(){return ped(this).instanceId},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"type",{get:function(){return ped(this).type},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"timeStamp",{get:function(){return ped(this).timeStamp},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetId",{get:function(){return ped(this).targetId},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetType",{get:function(){return ped(this).targetType},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetSubType",{get:function(){return ped(this).targetSubType},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"offsetX",{get:function(){return ped(this).offsetX},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"offsetY",{get:function(){return ped(this).offsetY},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"data",{get:function(){return ped(this).userData},enumerable:!1,configurable:!0}),e}(),listenersMap=new WeakMap;function getListeners(e){var t=listenersMap.get(e);if(null==t)throw new TypeError("'this' is expected an EventTarget object, but got another value.");return t}var GaiaXJSEventTarget=function(){function e(e){for(var t in e)if(Object.hasOwnProperty.call(e,t)){var n=e[t];this["__".concat(t,"__")]=n}this.__style__=new Style(e),listenersMap.set(this,new Map)}return Object.defineProperty(e.prototype,"style",{get:function(){return this.__style__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetId",{get:function(){return this.__targetId__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetType",{get:function(){return this.__targetType__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"targetSubType",{get:function(){return this.__targetSubType__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"templateId",{get:function(){return this.__templateId__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"instanceId",{get:function(){return this.__instanceId__},enumerable:!1,configurable:!0}),e.prototype.addEventListener=function(e,t,n){var a=getListeners(this);null!=a.get(e)&&a.delete(e),NativeEvent.addEventListener({templateId:this.templateId,targetId:this.targetId,instanceId:this.instanceId,eventType:e,option:n}).then((function(){var n={listener:t,next:null};a.set(e,n)}))},e.prototype.removeEventListener=function(e,t){var n=this;NativeEvent.removeEventListener({templateId:this.templateId,targetId:this.targetId,instanceId:this.instanceId,eventType:e}).then((function(){getListeners(n).delete(e)}))},e.prototype.dispatchEvent=function(e){var t=getListeners(this),n=e.type,a=t.get(n);if(null==a)return!0;"function"==typeof a.listener&&a.listener.call(this,e)},e}(),cListenersMap=new WeakMap;function getCListeners(e){var t=cListenersMap.get(e);if(null==t)throw new TypeError("'this' is expected an EventTarget object, but got another value.");return t}var nativeListenersMap=new WeakMap;function getNativeListeners(e){var t=nativeListenersMap.get(e);if(null==t)throw new TypeError("'this' is expected an EventTarget object, but got another value.");return t}var __Component__=function(){function e(e,t){if(this.__state__=e.state||{},this.__onReady__=e.onReady,this.__onShow__=e.onShow,this.__onHide__=e.onHide,this.__onDestroy__=e.onDestroy,this.__onReuse__=e.onReuse,this.__onLoadMore__=e.onLoadMore,this.__onScroll__=e.onScroll,this.__onScrollStart__=e.onScrollStart,this.__onScrollEnd__=e.onScrollEnd,this.__bizId__=t&&t.bizId,this.__templateId__=t&&t.templateId,this.__templateVersion__=t&&t.templateVersion||"-1",this.__instanceId__=t&&t.instanceId||0,e)for(var n in e){var a=e[n];"state"!=n&&"onReady"!=n&&"onShow"!=n&&"onHide"!=n&&"onDestroy"!=n&&"onReuse"!=n&&"onLoadMore"!=n&&"onScroll"!=n&&"onScrollStart"!=n&&"onScrollEnd"!=n&&(this[n]=a)}this.targets={},cListenersMap.set(this,new Map),nativeListenersMap.set(this,new Map)}return Object.defineProperty(e.prototype,"templateId",{get:function(){return this.__templateId__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"templateVersion",{get:function(){return this.__templateVersion__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"index",{get:function(){return gaiax.getComponentIndex({templateId:this.templateId,instanceId:this.instanceId})},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"instanceId",{get:function(){return this.__instanceId__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"bizId",{get:function(){return this.__bizId__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"state",{get:function(){return this.__state__},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"data",{get:function(){return gaiax.getData({templateId:this.templateId,instanceId:this.instanceId})},enumerable:!1,configurable:!0}),e.prototype.setData=function(e,t){gaiax.setData(e,{templateId:this.templateId,instanceId:this.instanceId},(function(){t&&t()}))},e.prototype.setState=function(e,t){if("object"==typeof e){var n=Object.assign(this.__state__,e||{})||{};this.__state__=n,setTimeout((function(){t&&t()}),0)}},e.prototype.onReuse=function(){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onReuse")),this.__onReuse__&&this.__onReuse__.call(this)}catch(e){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:e.message,stack:e.stack})}},e.prototype.onReady=function(){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onReady")),this.__onReady__&&this.__onReady__.call(this)}catch(e){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:e.message,stack:e.stack})}},e.prototype.onShow=function(){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onShow")),this.__onShow__&&this.__onShow__.call(this)}catch(e){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:e.message,stack:e.stack})}},e.prototype.onHide=function(){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onHide")),this.__onHide__&&this.__onHide__.call(this)}catch(e){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:e.message,stack:e.stack})}},e.prototype.onDestroy=function(){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onDestroy")),this.__onDestroy__&&this.__onDestroy__.call(this)}catch(e){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:e.message,stack:e.stack})}},e.prototype.onLoadMore=function(e){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onLoadMore")),this.__onLoadMore__&&this.__onLoadMore__.call(this,e)}catch(t){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:t.message,stack:t.stack})}},e.prototype.onScroll=function(e){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onScroll")),this.__onScroll__&&this.__onScroll__.call(this,e)}catch(t){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:t.message,stack:t.stack})}},e.prototype.onScrollStart=function(e){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onScrollStart")),this.__onScrollStart__&&this.__onScrollStart__.call(this,e)}catch(t){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:t.message,stack:t.stack})}},e.prototype.onScrollEnd=function(e){try{__globalThis&&__globalThis.__DEV__&&console.log("instanceId=".concat(this.instanceId,", bizId=").concat(this.bizId,", templateId=").concat(this.templateId,", templateVersion=").concat(this.templateVersion," onScrollEnd")),this.__onScrollEnd__&&this.__onScrollEnd__.call(this,e)}catch(t){console.error({templateId:this.templateId,templateVersion:this.templateVersion,bizId:this.bizId,message:t.message,stack:t.stack})}},e.prototype.getElementById=function(e){var t,n=NativeTarget.getElementByData({templateId:this.templateId,instanceId:this.instanceId,targetId:e});return null!=n&&(null==this.targets["".concat(this.instanceId,"_").concat(e)]?(t=new GaiaXJSEventTarget({templateId:this.templateId,instanceId:this.instanceId,targetId:e,targetType:n.targetType,targetSubType:n.targetSubType}),this.targets["".concat(this.instanceId,"_").concat(e)]=t):t=this.targets["".concat(this.instanceId,"_").concat(e)]),t},e.prototype.dispatchEvent=function(e){if(null!=e)if(e.targetId){var t=e.targetId;e.targetId&&this.targets["".concat(this.instanceId,"_").concat(t)]instanceof GaiaXJSEventTarget&&this.targets["".concat(this.instanceId,"_").concat(t)].dispatchEvent(e)}else{var n=getCListeners(this),a=e.type,i=n.get(a);if(null==i)return!0;"function"==typeof i.listener&&i.listener.call(this,e)}},e.prototype.addEventListener=function(e,t,n){var a=getCListeners(this);null!=a.get(e)&&a.delete(e);var i={listener:t,next:null};a.set(e,i)},e.prototype.removeEventListener=function(e,t){getCListeners(this).delete(e)},e.prototype.refreshPage=function(e){OneArch.refresh({templateId:this.templateId,instanceId:this.instanceId,type:"page",params:e})},e.prototype.refreshCard=function(e){OneArch.refresh({templateId:this.templateId,instanceId:this.instanceId,type:"card",params:e})},e.prototype.refreshComponent=function(e){OneArch.refresh({templateId:this.templateId,instanceId:this.instanceId,type:"component",params:e})},e.prototype.scrollTo=function(e){OneArch.scrollTo({templateId:this.templateId,instanceId:this.instanceId,params:e})},e.prototype.dispatchNativeEvent=function(e){if(null!=e){var t=getNativeListeners(this),n=e.type,a=t.get(n);if(null==a)return!0;"function"==typeof a.listener&&a.listener.call(this,e)}},e.prototype.addNativeEventListener=function(e,t){if(NativeEvent.addNativeEventListener({templateId:this.templateId,instanceId:this.instanceId,contextId:__globalThis.__CONTEXT_ID__,type:e})){var n=getNativeListeners(this);null!=n.get(e)&&n.delete(e);var a={listener:t,next:null};n.set(e,a)}},e.prototype.removeNativeEventListener=function(e){NativeEvent.removeNativeEventListener({templateId:this.templateId,instanceId:this.instanceId,contextId:__globalThis.__CONTEXT_ID__,type:e})&&getNativeListeners(this).delete(e)},e}();function Component(e,t){e&&t&&"object"==typeof e&&"object"==typeof t&&IMs.insertComponent(new __Component__(e,t))}var GaiaXJSWindow=function(){function e(){}return e.prototype.dispatchEventInternal=function(e){var t=new GaiaXJSEvent(e);IMs.dispatchEvent(t)},e.prototype.postMessage=function(e,t){"string"==typeof e?this.dispatchEventInternal(Object.assign({type:e||""},{userData:t})):this.dispatchEventInternal(e)},e.prototype.postNativeMessage=function(e){var t=new GaiaXJSEvent(e);IMs.dispatchNativeEvent(t)},e}();1!=__globalThis.__ENGINE_TYPE__&&10!=__globalThis.__ENGINE_TYPE__||(__globalThis.__successCallbacks=new Map,__globalThis.__failureCallbacks=new Map,__globalThis.__callbackId=0,__globalThis.__processCallbacks=function(e,t){return __globalThis.__successCallbacks.set(__globalThis.__callbackId,e),__globalThis.__failureCallbacks.set(__globalThis.__callbackId,t),__globalThis.__callbackId++});var Bridge=function(){function e(){}return e.callSync=function(e){if(null!=e&&e instanceof Object)return 1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__?GaiaXJSBridge.callSync(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__})):GaiaXJSBridge.callSync(JSON.stringify(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__})))},e.callAsync=function(e,t){if(null!=e&&e instanceof Object)if(1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__){var n=__globalThis.__processCallbacks&&__globalThis.__processCallbacks(t);GaiaXJSBridge.callAsync(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__,callbackId:n}))}else GaiaXJSBridge.callAsync(JSON.stringify(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__})),(function(e){t&&t(e)}))},e.callPromise=function(e){return new Promise((function(t,n){if(null!=e&&e instanceof Object)if(1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__){var a=__globalThis.__processCallbacks&&__globalThis.__processCallbacks(t,n);GaiaXJSBridge.callPromise(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__,callbackId:a}))}else GaiaXJSBridge.callPromise(JSON.stringify(Object.assign({},e,{contextId:__globalThis.__CONTEXT_ID__}))).then((function(e){t(e)})).catch((function(e){n(e)}));else n(new Error("arguments is not valid"))}))},e.invokeCallback=function(e,t){if((1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__)&&null!=e){var n=__globalThis.__successCallbacks.get(e);n&&(n(t),__globalThis.__successCallbacks.delete(e),__globalThis.__failureCallbacks.delete(e))}},e.invokePromiseSuccess=function(e,t){if((1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__)&&null!=e){var n=__globalThis.__successCallbacks.get(e);n&&(n(t),__globalThis.__successCallbacks.delete(e),__globalThis.__failureCallbacks.delete(e))}},e.invokePromiseFailure=function(e,t){if((1==__globalThis.__ENGINE_TYPE__||10==__globalThis.__ENGINE_TYPE__)&&null!=e){var n=__globalThis.__failureCallbacks.get(e);n&&(n(t),__globalThis.__successCallbacks.delete(e),__globalThis.__failureCallbacks.delete(e))}},e}(),InstancesManager=function(){function e(){this.instanceMaps={}}return e.prototype.getAllComponents=function(){return Object.values(this.instanceMaps)},e.prototype.insertComponent=function(e){this.instanceMaps[e.instanceId]=e},e.prototype.getComponent=function(e){return this.instanceMaps[e]},e.prototype.removeComponent=function(e){delete this.instanceMaps[e]},e.prototype.dispatchNativeEvent=function(e){var t=IMs.getComponent(e.instanceId);try{t&&t.dispatchNativeEvent(e)}catch(n){console.error({templateId:t.templateId,templateVersion:t.templateVersion,bizId:t.bizId,message:n.message,stack:n.stack})}},e.prototype.dispatchEvent=function(e){if(e&&e instanceof GaiaXJSEvent)if(null!=e.instanceId&&null!=e.templateId){var t=IMs.getComponent(e.instanceId);try{t&&t.dispatchEvent(e)}catch(i){console.error({templateId:t.templateId,templateVersion:t.templateVersion,bizId:t.bizId,message:i.message,stack:i.stack})}}else{var n=IMs.getAllComponents();if(n)for(var a=0;a + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSConfig : NSObject + + ++ (BOOL)isBreakPointDebugging; + ++ (void)setBreakPointDebuggingEnabled:(BOOL)enabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.m b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.m new file mode 100644 index 000000000..8aba69325 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSConfig.h" +#import "GaiaXJSFactory.h" + +@implementation GaiaXJSConfig + + ++ (BOOL)isBreakPointDebugging { + BOOL enabled = NO; + if ([[NSUserDefaults standardUserDefaults] objectForKey:@"GAIAX_JS_DEBUGGER_ENABLED"] != nil) { + enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"GAIAX_JS_DEBUGGER_ENABLED"]; + } + return enabled; +} + ++ (void)setBreakPointDebuggingEnabled:(BOOL)enabled { + if (enabled) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"GAIAX_JS_DEBUGGER_ENABLED"]; + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"GAIAX_JS_DEBUGGER_ENABLED"]; + } + NSDictionary *userInfo = nil; + if (enabled) { + userInfo = @{@"engineType": @"breakpoint"}; + } + if (enabled) { + [GaiaXJSFactory newContextByBizIdIfNeeded:@"common"]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_JS_ENGINE_TYPE_CHANGED" object:nil userInfo:userInfo]; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSDefines.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSDefines.h new file mode 100644 index 000000000..57f70c64f --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSDefines.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GaiaXJSDefines_h +#define GaiaXJSDefines_h + +typedef struct GaiaXJSExportedMethod { + const char *const objcName; + const BOOL isSync; +} GaiaXJSExportedMethod; + +typedef NS_ENUM(NSUInteger, GaiaXJSEngineType) { + GaiaXJSEngineTypeJSC, + GaiaXJSEngineTypeQuickJS, + GaiaXJSEngineTypeDebugger +}; + + +typedef NS_ENUM(NSUInteger, GaiaXJSMethodType) { + GaiaXJSMethodTypeSync, + GaiaXJSMethodTypeAsync, + GaiaXJSMethodTypePromise, +}; + +typedef NS_ENUM(NSUInteger, GaiaXJSEventType) { + GaiaXJSEventTypeClick, + GaiaXJSEventTypeLongPress, + GaiaXJSEventTypeDoubleClick, + GaiaXJSEventTypeSwipe, + GaiaXJSEventTypePinch +}; + + +typedef NS_ENUM(NSInteger, GaiaXJSExecPhase) { + //JS NativeModules + GaiaXJSExecPhaseWillStartLoadNativeModules, + GaiaXJSExecPhaseDidEndLoadNativeModules, + + //JS Context + GaiaXJSExecPhaseWillStartCreateContext, + GaiaXJSExecPhaseDidEndCreateContext, + + //JS Library + GaiaXJSExecPhaseWillStartLoadJSLibrary, + GaiaXJSExecPhaseDidEndLoadJSLibrary, + + //IndexJS + GaiaXJSExecPhaseWillStartLoadIndexJS, + GaiaXJSExecPhaseDidEndLoadIndexJS, + + //JSAPI + GaiaXJSExecPhaseWillStartInvokeSyncMethod, + GaiaXJSExecPhaseDidEndInvokeSyncMethod, + GaiaXJSExecPhaseWillStartInvokeAsyncMethod, + GaiaXJSExecPhaseDidEndInvokeAsyncMethod, + GaiaXJSExecPhaseWillStartInvokePromiseMethod, + GaiaXJSExecPhaseDidEndInvokePromiseMethod, +}; + +typedef NS_ENUM(NSInteger, GaiaXJSInvokeMethodSubPhase) { + GaiaXJSInvokeMethodSubPhaseJSToContext, + GaiaXJSInvokeMethodSubPhaseContextToReturn, + GaiaXJSInvokeMethodSubPhaseReturnToContext +}; + + +#define GaiaXJSQueuePrefix @"com.gaiaxjs.queue" +#define GaiaXJSDebugQueuePrefix @"com.gaiaxjs.debugger.queue" + +#define GAIAXJS_DEBUGGER_BIZ_ID @"GAIAXJS_DEBUGGER" + +typedef void (^GaiaXJSCallbackBlock)(id result); + +typedef void (^GaiaXJSPromiseResolveBlock)(id result); + +typedef void (^GaiaXJSPromiseRejectBlock)(NSString *code, NSString *message); + +typedef void (^GaiaXJSPropBlock)(id view, id json); + +typedef void (^GaiaXJSStyleBlock)(id view, id json); + +#define GaiaXJSSafeString(value) ([value length] == 0 ? @"" : value) + +#define GaiaXJSNullIfNil(value) ((value) ?: (id)kCFNull) +#define GaiaXJSNilIfNull(value) \ + ({ \ + __typeof__(value) t = (value); \ + (id) t == (id)kCFNull ? (__typeof(value))nil : t; \ + }) + + +#if !defined GAIAXJS_DYNAMIC +#if __has_attribute(objc_dynamic) +#define GAIAXJS_DYNAMIC __attribute__((objc_dynamic)) +#else +#define GAIAXJS_DYNAMIC +#endif +#endif + +#define GAIAXJS_CONCAT2(A, B) A##B +#define GAIAXJS_CONCAT(A, B) GAIAXJS_CONCAT2(A, B) + +#define GAIAXJS_EXPORT_MODULE(name) \ +char * gaiaxjs_##name##_module __attribute((used, section("__DATA, __gaiaxjs"))) = ""#name""; + +#define GAIAXJS_EXPORT_UI_MODULE(name) \ +char * gaiaxjs_##name##_ui_module __attribute((used, section("__DATA, __gaiaxjs"))) = ""#name""; + +#define GAIAXJS_EXPORT_UI_PROPERTY(name, type) \ + +(NSArray *)gaiaxjs_propConfig_##name GAIAXJS_DYNAMIC \ + { \ + return @[ @ #type ]; \ + } + +#define GAIAXJS_EXPORT_UI_STYLE(name, type) \ + +(NSArray *)gaiaxjs_styleConfig_##name GAIAXJS_DYNAMIC \ + { \ + return @[ @ #type ]; \ + } + + +#define _GAIAXJS_EXTERN_REMAP_METHOD(method, is_synchronous_method) \ ++(const GaiaXJSExportedMethod *)GAIAXJS_CONCAT(__gaiaxjs_export__,GAIAXJS_CONCAT(__LINE__,__COUNTER__)) \ +{ \ + static GaiaXJSExportedMethod config = {#method, is_synchronous_method}; \ + return &config; \ +} + +#define GAIAXJS_EXPORT_SYNC_METHOD(returnType, method) \ + _GAIAXJS_EXTERN_REMAP_METHOD(method, YES) \ + -(returnType)method GAIAXJS_DYNAMIC + +#define GAIAXJS_EXPORT_ASYNC_METHOD(method) \ + _GAIAXJS_EXTERN_REMAP_METHOD(method, NO) \ + -(void)method GAIAXJS_DYNAMIC + +#define GAIAXJS_EXPORT_EXTERN_MODULE(name, objc_name, objc_supername) \ +objc_name: \ +objc_supername @ \ +end @interface objc_name(GaiaXJSExternModule) \ +@end \ +@implementation objc_name (GaiaXJSExternModule) \ +char * gaiaxjs_##name##_module __attribute((used, section("__DATA, __gaiaxjs"))) = ""#name""; \ + +#define GAIAXJS_EXPORT_EXTERN_SYNC_METHOD(returnType, method) \ + _GAIAXJS_EXTERN_REMAP_METHOD(method, YES) \ + +#define GAIAXJS_EXPORT_EXTERN_ASYNC_METHOD(method) \ + _GAIAXJS_EXTERN_REMAP_METHOD(method, NO) \ + + +#define GAIAXJS_CONVERTER(type, name, getter) GAIAXJS_CUSTOM_CONVERTER(type, name, [json getter]) + +#define GAIAXJS_CUSTOM_CONVERTER(type, name, code) \ + +(type)name : (id)json GAIAXJS_DYNAMIC \ + { \ + return code; \ + } \ + +#define GAIAXJS_NUMBER_CONVERTER(type, getter) \ + GAIAXJS_CUSTOM_CONVERTER(type, type, [json getter]) + +typedef NS_ENUM(NSUInteger, GaiaXJSNullability) { + GaiaXJSNullabilityUnspecified, + GaiaXJSNullable, + GaiaXJSNonnullable, +}; + + +#define __GAIAXJS_PRIMITIVE_CASE(_type, _nullable) \ + { \ + isNullableType = _nullable; \ + _type (*convert)(id, SEL, id) = (__typeof__(convert))objc_msgSend; \ + [argumentBlocks addObject:^(NSUInteger index, id json) { \ + _type value = convert([GaiaXJSConvert class], selector, json); \ + [invocation setArgument:&value atIndex:(index) + 2]; \ + return YES; \ + }]; \ + break; \ + } + +#define GAIAXJS_PRIMITIVE_CASE(_type) __GAIAXJS_PRIMITIVE_CASE(_type, NO) + + +// Convert nil values to NSNull, and vice-versa +#define GAIAXJSNullIfNil(value) ((value) ?: (id)kCFNull) +#define GAIAXJSNilIfNull(value) \ + ({ \ + __typeof__(value) t = (value); \ + (id) t == (id)kCFNull ? (__typeof(value))nil : t; \ + }) + + + +// Explicitly copy the block +#define __COPY_BLOCK(block...) \ + id value = [block copy]; \ + if (value) { \ + [self.retainedObjects addObject:value]; \ + } + +#define GAIAXJS_RETAINED_ARG_BLOCK(_logic) \ + [argumentBlocks addObject:^( NSUInteger index, id json) { \ + _logic [invocation setArgument:&value atIndex:(index) + 2]; \ + if (value) { \ + [self.retainedObjects addObject:value]; \ + } \ + return YES; \ + }] + +#define GAIAXJS_BLOCK_CASE(_block_args, _block) \ + GAIAXJS_RETAINED_ARG_BLOCK(__COPY_BLOCK(^_block_args{ \ + _block});) + +#endif /* GaiaXJSDefines_h */ diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSExecPhaseImplDelegate.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSExecPhaseImplDelegate.h new file mode 100644 index 000000000..8d1842a76 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSExecPhaseImplDelegate.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol GaiaXJSExecPhaseImplDelegate + +@optional +- (void)gaiaxjsEnterExecutePhase:(GaiaXJSExecPhase)execPhase extendInfo:(NSDictionary *)extendInfo; + +- (void)gaiaxjsCatchJSError:(NSDictionary *)extendInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.h new file mode 100644 index 000000000..8f49321d2 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" +#import "GaiaXJSModulesImplDelegate.h" +#import "GaiaXJSExecPhaseImplDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSContext; + + +@interface GaiaXJSFactory : NSObject + +@property(nonatomic, weak) id modulesImplDelegate; + ++ (instancetype)defaultFactory; + ++ (GaiaXJSContext *)newContextByBizIdIfNeeded:(NSString *)bizId; + ++ (GaiaXJSContext *)getContextByContextId:(NSInteger)contextId; + +@end + + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.m b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.m new file mode 100644 index 000000000..ad879b70d --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.m @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSFactory.h" +#import "GaiaXJSModuleManager.h" +#import "GaiaXJSContext.h" +#import "GaiaXJSCContext.h" +#import "GaiaXJSDebuggerContext.h" +#import "GaiaXJSCRuntime.h" +#import "GaiaXJSUIManager.h" +#import "GaiaXJSConfig.h" +#import +#import "GaiaXJSDRuntime.h" + +@interface GaiaXJSFactory () + +@property(nonatomic, assign) GaiaXJSEngineType engineType; +@property(nonatomic, strong) NSMapTable *quickJSVMSMap; +@property(nonatomic, strong) NSMapTable *jscVMSMap; +@property(nonatomic, strong) NSMapTable *debuggerVMSMap; +@property(nonatomic, assign) NSInteger runtimeCount; + + +@end + +@implementation GaiaXJSFactory + ++ (instancetype)defaultFactory { + static dispatch_once_t onceToken; + static GaiaXJSFactory *jsFactory; + dispatch_once(&onceToken, ^{ + jsFactory = [[GaiaXJSFactory alloc] init]; + jsFactory.runtimeCount = 0; + [jsFactory initMaps]; + [[NSNotificationCenter defaultCenter] addObserver:jsFactory selector:@selector(jsEngineTypeChanged:) name:@"GAIAX_JS_ENGINE_TYPE_CHANGED" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:jsFactory selector:@selector(devToolsDidClosed:) name:@"GAIAX_DEVTOOLS_DID_CLOSED" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:jsFactory selector:@selector(devToolsDidOpened:) name:@"GAIAX_DEVTOOLS_DID_OPENED" object:nil]; + }); + return jsFactory; +} + +- (void)initMaps { + GaiaXJSEngineType type = GaiaXJSEngineTypeJSC; + if ([GaiaXJSConfig isBreakPointDebugging]) { + type = GaiaXJSEngineTypeDebugger; + } + [self initMapsWithEngineType:type]; +} + +- (void)initMapsWithEngineType:(GaiaXJSEngineType)engineType { + self.engineType = engineType; + if (self.engineType == GaiaXJSEngineTypeJSC && self.jscVMSMap == nil) { + self.jscVMSMap = [NSMapTable strongToStrongObjectsMapTable]; + } else if (self.engineType == GaiaXJSEngineTypeQuickJS && self.quickJSVMSMap == nil) { + self.quickJSVMSMap = [NSMapTable strongToStrongObjectsMapTable]; + } else if (self.engineType == GaiaXJSEngineTypeDebugger && self.debuggerVMSMap == nil) { + self.debuggerVMSMap = [NSMapTable strongToStrongObjectsMapTable]; + } +} + +- (void)devToolsDidClosed:(NSNotification *)notify { + if ([GaiaXJSConfig isBreakPointDebugging]) { + [GaiaXJSConfig setBreakPointDebuggingEnabled:NO]; + [self initMapsWithEngineType:GaiaXJSEngineTypeJSC]; + } +} + +- (void)devToolsDidOpened:(NSNotification *)notify { + GaiaXJSEngineType type = GaiaXJSEngineTypeJSC; + if ([GaiaXJSConfig isBreakPointDebugging]) { + type = GaiaXJSEngineTypeDebugger; + } + [self initMapsWithEngineType:type]; +} + +- (void)jsEngineTypeChanged:(NSNotification *)notify { + NSDictionary *userInfo = notify.userInfo; + GaiaXJSEngineType type = GaiaXJSEngineTypeJSC; + if ([userInfo[@"engineType"] isEqualToString:@"breakpoint"]) { + type = GaiaXJSEngineTypeDebugger; + } else if ([userInfo[@"engineType"] isEqualToString:@"quickjs"]) { + type = GaiaXJSEngineTypeQuickJS; + } + [self initMapsWithEngineType:type]; +} + ++ (GaiaXJSContext *)getContextByContextId:(NSInteger)contextId { + GaiaXJSFactory *factory = [GaiaXJSFactory defaultFactory]; + NSMapTable *map = nil; + if (factory.engineType == GaiaXJSEngineTypeJSC) { + map = factory.jscVMSMap; + } else if (factory.engineType == GaiaXJSEngineTypeQuickJS) { + map = factory.quickJSVMSMap; + } else if (factory.engineType == GaiaXJSEngineTypeDebugger) { + map = factory.debuggerVMSMap; + } + return [[map objectForKey:@(contextId)] context]; +} + ++ (GaiaXJSContext *)newContextByBizIdIfNeeded:(NSString *)bizId { + GaiaXJSFactory *factory = [GaiaXJSFactory defaultFactory]; + if (factory == nil) { + return nil; + } + return [GaiaXJSFactory newContextByTypeIfNeeded:factory.engineType bizId:bizId]; +} + ++ (GaiaXJSContext *)newContextByTypeIfNeeded:(GaiaXJSEngineType)type bizId:(NSString *)bizId { + GaiaXJSContext *context = nil; + GaiaXJSRuntime *runtime = nil; + GaiaXJSFactory *factory = [GaiaXJSFactory defaultFactory]; + [self getCurrentModuleManagerByEngineType:type]; + [self getCurrentUIManagerByEngineType:type]; + if (type == GaiaXJSEngineTypeJSC) { + GaiaXJSRuntime *runtimeInPool = [factory getRuntimeFromPoolByType:type bizId:bizId]; + if (runtimeInPool != nil) { + context = runtimeInPool.context; + } else { + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartCreateContext extendInfo:@{@"timestamp": @(startTime)}]; + runtime = [[GaiaXJSCRuntime alloc] init]; + factory.runtimeCount++; + [factory.jscVMSMap setObject:runtime forKey:@(factory.runtimeCount)]; + context = [[GaiaXJSCContext alloc] initWithRuntime:runtime]; + context.contextId = factory.runtimeCount; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndCreateContext extendInfo:@{@"timestamp": @(endTime), + @"cost": @(endTime - startTime)}]; + } + } else if (type == GaiaXJSEngineTypeDebugger) { + GaiaXJSRuntime *runtimeInPool = [factory getRuntimeFromPoolByType:type bizId:bizId]; + if (runtimeInPool != nil) { + context = runtimeInPool.context; + } else { + runtime = [[GaiaXJSDRuntime alloc] init]; + factory.runtimeCount++; + [factory.debuggerVMSMap setObject:runtime forKey:@(factory.runtimeCount)]; + context = [[GaiaXJSDebuggerContext alloc] initWithRuntime:runtime]; + context.contextId = factory.runtimeCount; + } + } + return context; +} + + +- (GaiaXJSRuntime *)getRuntimeFromPoolByType:(GaiaXJSEngineType)type bizId:(NSString *)bizId { + GaiaXJSRuntime *runtime = nil; + if (type == GaiaXJSEngineTypeJSC) { + NSEnumerator *enumerator = [self.jscVMSMap objectEnumerator]; + while (runtime = [enumerator nextObject]) { + if ([runtime isKindOfClass:[GaiaXJSCRuntime class]]) { + GaiaXJSCRuntime *jsc = (GaiaXJSCRuntime *) runtime; + if ([jsc.context getComponentsCountByBizId:bizId] > 0) { + runtime = jsc; + break; + } else { + if ([jsc.context getAllComponentsCount] <= [self maxComponent]) { + runtime = jsc; + break; + } + } + } + } + } else if (type == GaiaXJSEngineTypeDebugger) { + NSEnumerator *enumerator = [self.debuggerVMSMap objectEnumerator]; + while (runtime = [enumerator nextObject]) { + if ([runtime isKindOfClass:[GaiaXJSDRuntime class]]) { + GaiaXJSDRuntime *jsc = (GaiaXJSDRuntime *) runtime; + runtime = jsc; + break; + } + } + } + return runtime; +} + + ++ (GaiaXJSModuleManager *)getCurrentModuleManagerByEngineType:(GaiaXJSEngineType)engineType { + GaiaXJSModuleManager *manager = nil; + if (engineType == GaiaXJSEngineTypeDebugger) { + manager = [GaiaXJSModuleManager debuggerManager]; + } else { + manager = [GaiaXJSModuleManager defaultManager]; + } + return manager; +} + ++ (GaiaXJSUIManager *)getCurrentUIManagerByEngineType:(GaiaXJSEngineType)engineType { + GaiaXJSUIManager *manager = nil; + if (engineType == GaiaXJSEngineTypeDebugger) { + manager = [GaiaXJSUIManager debuggerManager]; + } else { + manager = [GaiaXJSUIManager defaultManager]; + } + return manager; +} + +- (NSInteger)maxComponent { + return 1000000; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.h new file mode 100644 index 000000000..d1013fc94 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import "GaiaXJSDefines.h" +#import "GaiaXJSExecPhaseImplDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSHandler : NSObject + ++ (instancetype)defaultHandler; + ++ (void)dispatchExecPhase:(GaiaXJSExecPhase)execPhase extendInfo:(nullable NSDictionary *)extendInfo; + ++ (void)throwJSError:(NSDictionary *)errorInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.m b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.m new file mode 100644 index 000000000..f860fc32e --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.m @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSHandler.h" + +@implementation GaiaXJSHandler + ++ (instancetype)defaultHandler { + static dispatch_once_t onceToken; + static GaiaXJSHandler *handler = nil; + dispatch_once(&onceToken, ^{ + handler = [[GaiaXJSHandler alloc] init]; + }); + return handler; +} + ++ (void)dispatchExecPhase:(GaiaXJSExecPhase)execPhase extendInfo:(nullable NSDictionary *)extendInfo { + GaiaXJSHandler *handler = [GaiaXJSHandler defaultHandler]; + if ([handler respondsToSelector:@selector(gaiaxjsEnterExecutePhase:extendInfo:)]) { + [handler gaiaxjsEnterExecutePhase:execPhase extendInfo:extendInfo]; + } +}; + ++ (void)throwJSError:(NSDictionary *)errorInfo { + GaiaXJSHandler *handler = [GaiaXJSHandler defaultHandler]; + if ([handler respondsToSelector:@selector(gaiaxjsCatchJSError:)]) { + [handler gaiaxjsCatchJSError:errorInfo]; + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.h new file mode 100644 index 000000000..dbdbd6d83 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSMethodInfo; +@class GaiaXJSModuleInfo; +@class GaiaXJSMethodArgument; + +@interface GaiaXJSHelper : NSObject + ++ (NSString *)toJSName:(NSString *)input; + ++ (NSString *)generateJSMethodString:(GaiaXJSMethodInfo *)moduleMethod + moduleIndex:(NSInteger)moduleIndex + methodIndex:(NSInteger)methodIndex; + ++ (NSString *)getHelperJSMethods; + ++ (NSString *)generateJSPropsStringWithClass:(NSString *)className key:(NSString *)keyString; + ++ (NSString *)generateJSStyleStringWithClass:(NSString *)className key:(NSString *)keyString; + ++ (NSString *)removeGaiaXPrefix:(NSString *)moduleName; + +NSString *GaiaXJSParseType(const char **input); + +NSString *GaiaXJSParseMethodSignature(const char *input, NSArray **arguments); + + ++ (NSUserDefaults *)getUserDefaults; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.m b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.m new file mode 100644 index 000000000..0fb28997e --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.m @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSHelper.h" +#import "GaiaXJSMethodInfo.h" +#import "GaiaXJSModuleInfo.h" +#import "GaiaXJSMethodArgument.h" + +@implementation GaiaXJSHelper + ++ (NSUserDefaults *)getUserDefaults { + static NSUserDefaults *defaults = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaults = [[NSUserDefaults alloc] initWithSuiteName:@"GAIAXJS"]; + }); + return defaults; +} + ++ (NSString *)toJSName:(NSString *)input { + NSRange range = [input rangeOfString:@":"]; + NSString *jsName; + if (range.location != NSNotFound) { + jsName = [input substringToIndex:range.location]; + } + if (jsName != NULL) { + jsName = [jsName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } else { + jsName = input; + } + return jsName; +} + ++ (NSString *)getHelperJSMethods { + return [NSString stringWithFormat:@"var __extends = (this && this.__extends) || (function () { \r\n \ + var extendStatics = function (d, b) { \r\n \ + extendStatics = Object.setPrototypeOf || \ + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || \ + function (d, b) { \r\n for (var p in b) if (b.hasOwnProperty(p)) \r\n d[p] = b[p]; }; \ + return extendStatics(d, b); \r\n \ + } \r\n \ + return function (d, b) { \r\n \ + extendStatics(d, b); \ + function __() { \r\n this.constructor = d; } \ + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); \ + }; \ + })(); \ + var __assign = (this && this.__assign) || function () { \r\n \ + __assign = Object.assign || function(t) { \r\n \ + for (var s, i = 1, n = arguments.length; i < n; i++) { \r\n \ + s = arguments[i]; \r\n \ + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) \ + t[p] = s[p]; \ + } \r\n \ + return t; \r\n \ + }; \r\n \ + return __assign.apply(this, arguments); \r\n \ + }; \r\n"]; +} + ++ (NSString *)generateJSPropsStringWithClass:(NSString *)className key:(NSString *)keyString { + return [NSString stringWithFormat:@"Object.defineProperty(%@Props.prototype, \"%@\", {\ + get: function () {\ + return this.__%@__;\ + },\ + set: function (value) {\ + this.__%@__ = value;\ + gaiax.setProps(\"%@\", value, this.targetData);\ + },\ + });", className, keyString, keyString, keyString, keyString]; +} + ++ (NSString *)generateJSStyleStringWithClass:(NSString *)className key:(NSString *)keyString { + return [NSString stringWithFormat:@"Object.defineProperty(%@Style.prototype, \"%@\", {\ + get: function () {\ + return this.__%@__;\ + },\ + set: function (value) {\ + this.__%@__ = value;\ + gaiax.setStyle(\"%@\", value, this.targetData);\ + },\ + });", className, keyString, keyString, keyString, keyString]; +} + + ++ (NSString *)generateJSMethodString:(GaiaXJSMethodInfo *)methodInfo + moduleIndex:(NSInteger)moduleIndex + methodIndex:(NSInteger)methodIndex { + NSMutableString *result = [NSMutableString string]; + NSString *objcMethodString = methodInfo.methodName; + NSString *jsName = [GaiaXJSHelper toJSName:objcMethodString]; + NSString *className = methodInfo.moduleInfo.moduleName; + NSString *jsClassName = className; + [result appendFormat:@"%@.prototype.%@ = function() {", jsClassName, jsName]; + [result appendFormat:@"var args = [];\ + for (var _i = 0; _i < arguments.length; _i++) {\ + args[_i] = arguments[_i];\ + }"]; + if (methodInfo.isSync) { + [result appendFormat:@"return %@.callSync({moduleId:%ld, methodId:%ld, timestamp:Date.now(), args});", jsClassName, (long) moduleIndex, (long) methodIndex]; + } else { + if (methodInfo.methodType == GaiaXJSMethodTypePromise) { + [result appendFormat:@"return new Promise(function (resolve, reject) {\ + %@.callPromise({moduleId:%ld, methodId:%ld, timestamp:Date.now(), args}).then(function(result) {\ + resolve(result)\ + }).catch(function(error) {\ + reject(error);}) }) ", jsClassName, (long) moduleIndex, (long) methodIndex]; + } else if (methodInfo.methodType == GaiaXJSMethodTypeAsync) { + [result appendFormat:@"%@.callAsync({moduleId:%ld, methodId:%ld, timestamp:Date.now(), args: (typeof args[args.length-1] == 'function') ? args.slice(0, args.length-1) : args}, function(result) {\ + let callback = args[args.length-1];\ + callback && (typeof callback == 'function') && callback(result); });", + jsClassName, (long) moduleIndex, (long) methodIndex]; + } + } + [result appendString:@"}"]; + return result; +} + ++ (NSString *)removeGaiaXPrefix:(NSString *)moduleName { + NSString *result = moduleName; + if ([result hasPrefix:@"GaiaX"]) { + result = [result substringFromIndex:5]; + } else if ([result hasPrefix:@"GaiaXJS"]) { + result = [result substringFromIndex:7]; + } + if ([result hasSuffix:@"Module"]) { + result = [result substringToIndex:result.length - 6]; + } + return result; +} + +NSString *GaiaXJSParseMethodSignature(const char *input, NSArray **arguments) { + GaiaXJSSkipWhitespace(&input); + NSMutableArray *args; + NSMutableString *selector = [NSMutableString new]; + while (GaiaXJSParseSelectorPart(&input, selector)) { + if (!args) { + args = [NSMutableArray new]; + } + if (GaiaXJSReadChar(&input, '(')) { + GaiaXJSSkipWhitespace(&input); + GaiaXJSNullability nullability = GaiaXJSParseNullability(&input); + GaiaXJSSkipWhitespace(&input); + BOOL unused = GaiaXJSParseUnused(&input); + GaiaXJSSkipWhitespace(&input); + NSString *type = GaiaXJSParseType(&input); + GaiaXJSSkipWhitespace(&input); + if (nullability == GaiaXJSNullabilityUnspecified) { + nullability = GaiaXJSParseNullabilityPostfix(&input); + GaiaXJSSkipWhitespace(&input); + if (!unused) { + unused = GaiaXJSParseUnused(&input); + GaiaXJSSkipWhitespace(&input); + if (unused && nullability == GaiaXJSNullabilityUnspecified) { + nullability = GaiaXJSParseNullabilityPostfix(&input); + GaiaXJSSkipWhitespace(&input); + } + } + } else if (!unused) { + unused = GaiaXJSParseUnused(&input); + GaiaXJSSkipWhitespace(&input); + } + [args addObject:[[GaiaXJSMethodArgument alloc] initWithType:type nullability:nullability unused:unused]]; + GaiaXJSSkipWhitespace(&input); + GaiaXJSReadChar(&input, ')'); + GaiaXJSSkipWhitespace(&input); + } else { + [args addObject:[[GaiaXJSMethodArgument alloc] initWithType:@"id" nullability:GaiaXJSNullable unused:NO]]; + } + GaiaXJSParseArgumentIdentifier(&input, NULL); + GaiaXJSSkipWhitespace(&input); + } + *arguments = [args copy]; + return selector; +} + + +void GaiaXJSSkipWhitespace(const char **input) { + while (isspace(**input)) { + (*input)++; + } +} + +BOOL GaiaXJSReadChar(const char **input, char c) { + if (**input == c) { + (*input)++; + return YES; + } + return NO; +} + +static BOOL GaiaXJSParseUnused(const char **input) { + return GaiaXJSReadString(input, "__attribute__((unused))") || GaiaXJSReadString(input, "__attribute__((__unused__))") || + GaiaXJSReadString(input, "__unused"); +} + +BOOL GaiaXJSReadString(const char **input, const char *string) { + int i; + for (i = 0; string[i] != 0; i++) { + if (string[i] != (*input)[i]) { + return NO; + } + } + *input += i; + return YES; +} + +static BOOL GaiaXJSParseSelectorPart(const char **input, NSMutableString *selector) { + NSString *selectorPart; + if (GaiaXJSParseSelectorIdentifier(input, &selectorPart)) { + [selector appendString:selectorPart]; + } + GaiaXJSSkipWhitespace(input); + if (GaiaXJSReadChar(input, ':')) { + [selector appendString:@":"]; + GaiaXJSSkipWhitespace(input); + return YES; + } + return NO; +} + + +BOOL GaiaXJSParseSelectorIdentifier(const char **input, NSString **string) { + const char *start = *input; + if (!GaiaXJSIsIdentifierHead(**input)) { + return NO; + } + (*input)++; + while (GaiaXJSIsIdentifierTail(**input)) { + (*input)++; + } + if (string) { + *string = [[NSString alloc] initWithBytes:start length:(NSInteger) (*input - start) encoding:NSASCIIStringEncoding]; + } + return YES; +} + +static BOOL GaiaXJSIsIdentifierHead(const char c) { + return isalpha(c) || c == '_'; +} + +static BOOL GaiaXJSIsIdentifierTail(const char c) { + return isalnum(c) || c == '_'; +} + + +NSString *GaiaXJSParseType(const char **input) { + NSString *type; + GaiaXJSParseArgumentIdentifier(input, &type); + GaiaXJSSkipWhitespace(input); + if (GaiaXJSReadChar(input, '<')) { + GaiaXJSSkipWhitespace(input); + NSString *subtype = GaiaXJSParseType(input); + if (GaiaXJSIsCollectionType(type)) { + if ([type isEqualToString:@"NSDictionary"]) { + GaiaXJSSkipWhitespace(input); + GaiaXJSReadChar(input, ','); + GaiaXJSSkipWhitespace(input); + subtype = GaiaXJSParseType(input); + } + if (![subtype isEqualToString:@"id"]) { + type = [type stringByReplacingCharactersInRange:(NSRange) {0, 2} withString:subtype]; + } + } + GaiaXJSSkipWhitespace(input); + GaiaXJSReadChar(input, '>'); + } + GaiaXJSSkipWhitespace(input); + if (!GaiaXJSReadChar(input, '*')) { + GaiaXJSReadChar(input, '&'); + } + return type; +} + +BOOL GaiaXJSParseArgumentIdentifier(const char **input, NSString **string) { + const char *start = *input; + do { + if (!GaiaXJSIsIdentifierHead(**input)) { + return NO; + } + (*input)++; + while (GaiaXJSIsIdentifierTail(**input)) { + (*input)++; + } + } while (GaiaXJSReadString(input, "::")); + if (string) { + *string = [[NSString alloc] initWithBytes:start length:(NSInteger) (*input - start) encoding:NSASCIIStringEncoding]; + } + return YES; +} + +static BOOL GaiaXJSIsCollectionType(NSString *type) { + static NSSet *collectionTypes; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + collectionTypes = [[NSSet alloc] initWithObjects:@"NSArray", @"NSSet", @"NSDictionary", nil]; + }); + return [collectionTypes containsObject:type]; +} + +static GaiaXJSNullability GaiaXJSParseNullability(const char **input) { + if (GaiaXJSReadString(input, "nullable")) { + return GaiaXJSNullable; + } else if (GaiaXJSReadString(input, "nonnull")) { + return GaiaXJSNonnullable; + } + return GaiaXJSNullabilityUnspecified; +} + +static GaiaXJSNullability GaiaXJSParseNullabilityPostfix(const char **input) { + if (GaiaXJSReadString(input, "_Nullable") || GaiaXJSReadString(input, "__nullable")) { + return GaiaXJSNullable; + } else if (GaiaXJSReadString(input, "_Nonnull") || GaiaXJSReadString(input, "__nonnull")) { + return GaiaXJSNonnullable; + } + return GaiaXJSNullabilityUnspecified; +} + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/GaiaXJSModulesImplDelegate.h b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSModulesImplDelegate.h new file mode 100644 index 000000000..1565935e9 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/GaiaXJSModulesImplDelegate.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol GaiaXJSModulesImplDelegate + +/** + * get element by extendInfo + * @param extendInfo + * example: + * { + instanceId = 1; + targetId = "label-a"; + templateId = "template-demo"; + * } + * @return + * example + * { + targetId = "label-a"; + targetType = "view"; + * } or else nil + */ +- (NSDictionary *)getElement:(NSDictionary *)extendInfo; + +/** + * + * @param extendInfo + * @return + */ +- (BOOL)addEventListener:(NSDictionary *)extendInfo; + +/** + */ +- (BOOL)removeEventListener:(NSDictionary *)extendInfo; + +/** + + */ +- (NSDictionary *)getBindingData:(NSDictionary *)extendInfo; + +/** + + */ + +- (void)setBindingData:(NSDictionary *)data extendInfo:(NSDictionary *)extendInfo; + +/** + if not found, return -1; else return index + */ +- (NSNumber *)getIndex:(NSDictionary *)extendInfo; + +/** + refresh component ui + */ +- (void)refresh:(NSDictionary *)extendInfo; + +- (void)scrollTo:(NSDictionary *)extendInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.h b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.h new file mode 100644 index 000000000..d356e1f29 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSContext; + +typedef void(^GaiaXJSSetupContextBlock)(void); + +typedef void(^GaiaXJSExecutedBlock)(void); + +@interface GaiaXJSBridge : NSObject + +@property(nonatomic, weak) GaiaXJSContext *jsContext; + +@property(nonatomic, strong) dispatch_queue_t gaiaxJSQueue; + +- (instancetype)initWidthJSContext:(GaiaXJSContext *)jsContext; + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName; + +- (void)executeIndexJS:(NSString *)jsString + fileName:(NSString *)fileName + args:(NSDictionary *)args + callback:(GaiaXJSExecutedBlock)callback; + +- (void)executeJSLibrary:(NSString *)jsString fileName:(NSString *)fileName; + +- (void)setupContext:(GaiaXJSSetupContextBlock)block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.m b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.m new file mode 100644 index 000000000..ed89b7e6c --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.m @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSBridge.h" +#import "GaiaXJSModuleManager.h" +#import "GaiaXJSRuntime.h" + +static NSInteger queueIndex = 0; + +@implementation GaiaXJSBridge + +- (instancetype)initWidthJSContext:(GaiaXJSContext *)jsContext { + if (self = [super init]) { + NSString *labelString = [NSString stringWithFormat:@"%@.%ld", GaiaXJSQueuePrefix, (long) queueIndex++]; + self.gaiaxJSQueue = dispatch_queue_create(labelString.UTF8String, NULL); + self.jsContext = jsContext; + } + return self; +} + +- (void)setupContext:(GaiaXJSSetupContextBlock)block { + dispatch_async(self.gaiaxJSQueue, ^{ + if (block) { + block(); + } + }); +} + +- (void)executeJSLibrary:(NSString *)jsString fileName:(NSString *)fileName { + [self.jsContext evalScript:jsString fileName:fileName]; +} + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName { + [self evalScript:jsString fileName:fileName callback:nil]; +} + +- (void)evalScript:(NSString *)jsString + fileName:(NSString *)fileName + callback:(GaiaXJSExecutedBlock)callback { + dispatch_async(self.gaiaxJSQueue, ^{ + [self.jsContext evalScript:jsString fileName:fileName]; + if (callback != nil) { + callback(); + } + }); +} + +- (void)executeIndexJS:(NSString *)jsString + fileName:(NSString *)fileName + args:(NSDictionary *)args + callback:(GaiaXJSExecutedBlock)callback { + dispatch_async(self.gaiaxJSQueue, ^{ + [self.jsContext executeIndexJS:jsString fileName:fileName args:args]; + if (callback != nil) { + callback(); + } + }); +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.h b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.h new file mode 100644 index 000000000..592ccd4c3 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSConvert : NSObject + ++ (id)id:(id)json; + ++ (double)double:(id)json; + ++ (float)float:(id)json; + ++ (int)int:(id)json; + ++ (NSArray *)NSArray:(id)json; + ++ (NSDictionary *)NSDictionary:(id)json; + ++ (NSString *)NSString:(id)json; + ++ (NSNumber *)NSNumber:(id)json; + ++ (UIColor *)UIColor:(id)json; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.m b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.m new file mode 100644 index 000000000..bb5cbeb16 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.m @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSConvert.h" +#import "GaiaXJSDefines.h" + + +@implementation GaiaXJSConvert + +#define GAIAXJS_JSON_ARRAY_CONVERTER(name) \ ++(NSArray *)name##Array : (id)json \ +{ \ + return json; \ +} + +GAIAXJS_CONVERTER(id, id, self) + +GAIAXJS_NUMBER_CONVERTER(double, doubleValue) + +GAIAXJS_NUMBER_CONVERTER(float, floatValue) + +GAIAXJS_NUMBER_CONVERTER(int, intValue) + +GAIAXJS_CUSTOM_CONVERTER(CGFloat, CGFloat, [self double:json]) + +#define GAIAXJS_JSON_CONVERTER(type) \ + +(type *)type : (id)json \ + { \ + return json; \ + } + +GAIAXJS_JSON_CONVERTER(NSArray) + +GAIAXJS_JSON_CONVERTER(NSDictionary) + +GAIAXJS_JSON_CONVERTER(NSString) + +GAIAXJS_JSON_CONVERTER(NSNumber) + +GAIAXJS_NUMBER_CONVERTER(NSInteger, integerValue) + +GAIAXJS_NUMBER_CONVERTER(NSUInteger, unsignedIntegerValue) + +GAIAXJS_JSON_ARRAY_CONVERTER(NSNumber) + ++ (UIColor *)UIColor:(id)json { + if (!json) { + return nil; + } + if ([json isKindOfClass:[NSArray class]]) { + NSArray *components = [self NSNumberArray:json]; + CGFloat alpha = components.count > 3 ? [self CGFloat:components[3]] : 1.0; + return [UIColor colorWithRed:[self CGFloat:components[0]] + green:[self CGFloat:components[1]] + blue:[self CGFloat:components[2]] + alpha:alpha]; + } else if ([json isKindOfClass:[NSNumber class]]) { + NSUInteger argb = [self NSUInteger:json]; + CGFloat a = ((argb >> 24) & 0xFF) / 255.0; + CGFloat r = ((argb >> 16) & 0xFF) / 255.0; + CGFloat g = ((argb >> 8) & 0xFF) / 255.0; + CGFloat b = (argb & 0xFF) / 255.0; + return [UIColor colorWithRed:r green:g blue:b alpha:a]; + } else { + return nil; + } +} + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.h new file mode 100644 index 000000000..8507e54f2 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" +#import + + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSCContext; + +@protocol GaiaXJSCProtocol + +JSExportAs(callSync, +(JSValue *) callSync:(NSDictionary *)dictionary); + +JSExportAs(callAsync, +(void) callAsync:(NSDictionary *)dictionary); + +JSExportAs(callPromise, +(void) callPromise:(NSDictionary *)dictionary); + +@end + +@interface GaiaXJSCModule : NSObject + +void init_jsc_module(GaiaXJSCContext *context); + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.m new file mode 100644 index 000000000..84187b37b --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.m @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSCModule.h" +#import "GaiaXJSCContext.h" +#import "GaiaXJSModuleManager.h" + +@implementation GaiaXJSCModule + +static NSMutableDictionary *timerMaps = nil; +static int timerId = 1; + +void init_jsc_module(GaiaXJSCContext *context) { + timerMaps = [NSMutableDictionary dictionary]; + __weak GaiaXJSCContext *weakContext = context; + context.ctx[@"GaiaXJSBridge"] = [GaiaXJSCModule class]; + context.ctx[@"setTimeout"] = ^(JSValue *callback, JSValue *timeoutValue) { + int timeout = -1; + if (timeoutValue != nil) { + timeout = [[timeoutValue toNumber] intValue]; + } + if (timeout >= 0) { + int tempTimerId = timerId; + dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{ + [callback callWithArguments:@[]]; + @synchronized (timerMaps) { + [timerMaps removeObjectForKey:@(tempTimerId)]; + } + }); + @synchronized (timerMaps) { + timerMaps[@(timerId)] = block; + } + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (timeout * NSEC_PER_MSEC)), weakContext.bridge.gaiaxJSQueue, block); + return [JSValue valueWithInt32:timerId++ inContext:weakContext.ctx]; + } + return [JSValue valueWithUndefinedInContext:weakContext.ctx]; + }; + context.ctx[@"clearTimeout"] = ^(JSValue *uuid) { + if (uuid == nil) { + return; + } + dispatch_block_t block = timerMaps[@([uuid toInt32])]; + if (block != NULL) { + dispatch_block_cancel(block); + } + @synchronized (timerMaps) { + [timerMaps removeObjectForKey:@([uuid toInt32])]; + } + }; + + + context.ctx[@"setInterval"] = ^(JSValue *callback, JSValue *intervalValue) { + int interval = -1; + if (intervalValue != nil) { + interval = [[intervalValue toNumber] intValue]; + } + if (interval >= 0) { + dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, weakContext.bridge.gaiaxJSQueue); + dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t) (interval * NSEC_PER_MSEC)), interval * NSEC_PER_MSEC, 0); + dispatch_source_set_event_handler(_timer, ^{ + [callback callWithArguments:@[]]; + }); + @synchronized (timerMaps) { + timerMaps[@(timerId)] = _timer; + } + dispatch_resume(_timer); + return [JSValue valueWithInt32:timerId++ inContext:weakContext.ctx]; + } + return [JSValue valueWithUndefinedInContext:weakContext.ctx]; + }; + + context.ctx[@"clearInterval"] = ^(JSValue *uuid) { + if (uuid == nil) { + return; + } + dispatch_source_t _timer = timerMaps[@([uuid toInt32])]; + if (_timer != NULL) { + dispatch_source_cancel(_timer); + } + @synchronized (timerMaps) { + [timerMaps removeObjectForKey:@([uuid toInt32])]; + } + }; +} + ++ (JSValue *)callSync:(NSDictionary *)dictionary { + JSContext *context = [JSContext currentContext]; + if (dictionary == nil) { + return [JSValue valueWithUndefinedInContext:context]; + } + + id retValue = [[GaiaXJSModuleManager defaultManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + timestamp:[dictionary[@"timestamp"] doubleValue] + args:dictionary[@"args"]]; + if (retValue != nil) { + return [GaiaXJSCModule valueFromObject:retValue context:context]; + } + + return [JSValue valueWithUndefinedInContext:context]; +} + ++ (void)callAsync:(NSDictionary *)dictionary { + if (dictionary == nil) { + return; + } + JSContext *context = [JSContext currentContext]; + [[GaiaXJSModuleManager defaultManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + timestamp:[dictionary[@"timestamp"] doubleValue] + args:dictionary[@"args"] + callback:^(id result) { + [[[context globalObject] valueForProperty:@"Bridge"] + invokeMethod:@"invokeCallback" + withArguments:@[ + dictionary[@"callbackId"], result == nil ? [JSValue valueWithUndefinedInContext:context] : result + ]]; + }]; +} + ++ (void)callPromise:(NSDictionary *)dictionary { + if (dictionary == nil) { + return; + } + JSContext *context = [JSContext currentContext]; + [[GaiaXJSModuleManager defaultManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + timestamp:[dictionary[@"timestamp"] doubleValue] + args:dictionary[@"args"] + resolver:^(id result) { + [[[context globalObject] valueForProperty:@"Bridge"] + invokeMethod:@"invokePromiseSuccess" + withArguments:@[dictionary[@"callbackId"], result == nil ? [JSValue valueWithUndefinedInContext:context] : result]]; + } + rejecter:^(NSString *code, NSString *message) { + [[[context globalObject] valueForProperty:@"Bridge"] + invokeMethod:@"invokePromiseFailure" + withArguments:@[ + dictionary[@"callbackId"], @{@"code": code, @"message": message} + ]]; + }]; +} + ++ (JSValue *)valueFromObject:(id)object context:(JSContext *)ctx { + JSValue *objectVal = nil; + if ([object isKindOfClass:[NSNumber class]]) { + NSNumber *numberObject = (NSNumber *) object; + if (numberObject.class == [@YES class]) { + objectVal = [JSValue valueWithBool:[numberObject boolValue] + inContext:ctx]; + } else { + CFNumberType numberType = CFNumberGetType((CFNumberRef) numberObject); + switch (numberType) { + case kCFNumberFloatType: + case kCFNumberFloat64Type: + case kCFNumberCGFloatType: + case kCFNumberDoubleType: + objectVal = [JSValue valueWithDouble:[numberObject doubleValue] + inContext:ctx]; + break; + default: + objectVal = [JSValue valueWithInt32:[numberObject intValue] + inContext:ctx]; + break; + } + } + } else { + objectVal = [JSValue valueWithObject:object inContext:ctx]; + } + + return objectVal; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.h new file mode 100644 index 000000000..9fb49101f --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSBuiltInModule (Storage) + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.m new file mode 100644 index 000000000..614e68cda --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.m @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSBuiltInModule+Storage.h" + +@implementation GaiaXJSBuiltInModule (Storage) + + +GAIAXJS_EXPORT_ASYNC_METHOD(getStorage:(NSString *) key resolver:(GaiaXJSPromiseResolveBlock) resolve rejecter:(GaiaXJSPromiseRejectBlock) reject) { + NSUserDefaults *defaults = [GaiaXJSHelper getUserDefaults]; + id result = nil; + if (key != nil) { + result = [defaults objectForKey:key]; + resolve(result); + return; + } + reject(@"-1", @"获取失败"); +} + +GAIAXJS_EXPORT_ASYNC_METHOD(setStorage:(NSString *) key value:(id) value resolver:(GaiaXJSPromiseResolveBlock) resolve rejecter:(GaiaXJSPromiseRejectBlock) reject) { + NSUserDefaults *defaults = [GaiaXJSHelper getUserDefaults]; + if (key != nil && value != nil) { + [defaults setObject:value forKey:key]; + resolve(nil); + return; + } + reject(@"-1", @"存储失败"); +} + +GAIAXJS_EXPORT_ASYNC_METHOD(removeStorage:(NSString *) key resolver:(GaiaXJSPromiseResolveBlock) resolve rejecter:(GaiaXJSPromiseRejectBlock) reject) { + NSUserDefaults *defaults = [GaiaXJSHelper getUserDefaults]; + if (key != nil) { + [defaults removeObjectForKey:key]; + resolve(nil); + return; + } + reject(@"-1", @"删除失败"); +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.h new file mode 100644 index 000000000..e31d1a474 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSBuiltInModule : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.m new file mode 100644 index 000000000..35d46215f --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.m @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSBuiltInModule.h" +#import "GaiaXJSDefines.h" +#import +#import "GaiaXJSFactory.h" + +@implementation GaiaXJSBuiltInModule + +GAIAXJS_EXPORT_MODULE(BuiltIn) + +GAIAXJS_EXPORT_SYNC_METHOD(void, setStyle:(NSString *) key value:(id) value extendInfo:(NSDictionary *) extendInfo) { + NSLog(@"setStyle"); +} + +GAIAXJS_EXPORT_SYNC_METHOD(void, setProps:(NSString *) key value:(id) value extendInfo:(NSDictionary *) extendInfo) { + NSLog(@"setProps"); +} + +GAIAXJS_EXPORT_SYNC_METHOD(NSDictionary *, getData:(NSDictionary *) extendInfo) { + NSLog(@"getData extendInfo = %@", extendInfo); + NSDictionary *data = nil; + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(getBindingData:)]) { + data = [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(getBindingData:) withObject:extendInfo]; + } + return data; +} + +GAIAXJS_EXPORT_ASYNC_METHOD(setData:(NSDictionary *) data extendInfo:(NSDictionary *) extendInfo callback:(GaiaXJSCallbackBlock) callback) { + NSLog(@"setData %@, extendInfo = %@", data, extendInfo); + dispatch_async(dispatch_get_main_queue(), ^{ + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(setBindingData:extendInfo:)]) { + [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(setBindingData:extendInfo:) withObject:data withObject:extendInfo]; + } + if (callback != nil) { + callback(nil); + } + }); +} + +GAIAXJS_EXPORT_SYNC_METHOD(NSNumber *, getComponentIndex:(NSDictionary *) extendInfo) { + NSNumber *index = nil; + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(getIndex:)]) { + index = [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(getIndex:) withObject:extendInfo]; + } else { + index = @(-1); + } + return index; +} + +GAIAXJS_EXPORT_ASYNC_METHOD(showAlert:(NSDictionary *) data callback:(GaiaXJSCallbackBlock) callback) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:data[@"title"] != nil ? data[@"title"] : @"" + message:data[@"message"] != nil ? data[@"message"] : @"" + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) { + if (callback != nil) { + callback(@{@"canceled": @(YES)}); + } + }]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) { + if (callback != nil) { + callback(@{@"canceled": @(NO)}); + } + }]; + [alertController addAction:cancelAction]; + [alertController addAction:okAction]; + [[[UIApplication sharedApplication] windows][0].rootViewController presentViewController:alertController animated:YES completion:^{ + + }]; + }); +} + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.h new file mode 100644 index 000000000..e7aaced64 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSNativeEventManager : NSObject + ++ (instancetype)defaultManager; + ++ (BOOL)registerMessage:(NSDictionary *)data; + ++ (BOOL)unRegisterMessage:(NSDictionary *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.m new file mode 100644 index 000000000..c562fcb6d --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.m @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSNativeEventManager.h" +#import "GaiaXJSDefines.h" +#import "GaiaXJSFactory.h" +#import "GaiaxJSContext.h" + +@interface GaiaXJSNativeEventManager () + +@property(nonatomic, strong) NSMutableArray *callbacks; + +@end + +@implementation GaiaXJSNativeEventManager + ++ (instancetype)defaultManager { + static dispatch_once_t onceToken; + static GaiaXJSNativeEventManager *manager; + dispatch_once(&onceToken, ^{ + manager = [[GaiaXJSNativeEventManager alloc] init]; + manager.callbacks = [[NSMutableArray alloc] init]; + }); + return manager; +} + + ++ (BOOL)registerMessage:(NSDictionary *)data { + if (data && data[@"type"] != nil && data[@"contextId"] != nil && data[@"instanceId"] != nil) { + GaiaXJSNativeEventManager *manager = [GaiaXJSNativeEventManager defaultManager]; + @synchronized (manager) { + BOOL alreadyRegisterMessage = NO; + for (NSUInteger i = 0; i < [manager.callbacks count]; i++) { + NSDictionary *callback = manager.callbacks[i]; + if ([callback[@"type"] isEqualToString:data[@"type"]] && + [data[@"contextId"] integerValue] == [callback[@"contextId"] integerValue] && + [data[@"instanceId"] integerValue] == [callback[@"instanceId"] integerValue]) { + alreadyRegisterMessage = YES; + break;; + } + } + if (!alreadyRegisterMessage) { + [manager.callbacks addObject:data]; + + } + [[NSNotificationCenter defaultCenter] removeObserver:manager name:data[@"type"] object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:manager selector:@selector(receivedMessage:) name:data[@"type"] object:nil]; + } + return YES; + } + return NO; +} + +- (void)receivedMessage:(NSNotification *)notify { + @synchronized (self) { + for (NSUInteger i = 0; i < [self.callbacks count]; i++) { + NSDictionary *callback = self.callbacks[i]; + if ([callback[@"type"] isEqualToString:notify.name]) { + NSMutableDictionary *injectEventData = [NSMutableDictionary dictionaryWithDictionary:callback]; + if (notify.userInfo != nil) { + [injectEventData setObject:notify.userInfo forKey:@"userData"]; + } + [injectEventData setObject:GaiaXJSSafeString(notify.name) forKey:@"type"]; + [injectEventData setObject:@([@([[NSDate date] timeIntervalSince1970] * 1000) integerValue]) forKey:@"timestamp"]; + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:[callback[@"contextId"] integerValue]]; + NSData *jsonData = nil; + @try { + jsonData = [NSJSONSerialization dataWithJSONObject:injectEventData + options:0 + error:NULL]; + } @catch (NSException *exception) { + + } @finally { + NSString *jsonString = nil; + if (jsonData != nil) { + jsonString = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + } + NSString *injectString = + [NSString stringWithFormat:@"window.postNativeMessage(%@)", jsonString]; + [context.bridge evalScript:injectString fileName:@"index.js"]; + } + } + } + } +} + ++ (BOOL)unRegisterMessage:(NSDictionary *)data { + if (data && data[@"type"] != nil && data[@"contextId"] != nil && data[@"instanceId"] != nil) { + GaiaXJSNativeEventManager *manager = [GaiaXJSNativeEventManager defaultManager]; + NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init]; + @synchronized (manager) { + for (NSUInteger i = 0; i < [manager.callbacks count]; i++) { + NSDictionary *callback = manager.callbacks[i]; + if ([callback[@"type"] isEqualToString:data[@"type"]] && + [data[@"contextId"] integerValue] == [callback[@"contextId"] integerValue] && + [data[@"instanceId"] integerValue] == [callback[@"instanceId"] integerValue]) { + [idxSet addIndex:i]; + } + } + [manager.callbacks removeObjectsAtIndexes:idxSet]; + } + return YES; + } + return NO; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.h new file mode 100644 index 000000000..d08da06ac --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSNativeEventModule : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.m new file mode 100644 index 000000000..1a4d2ca11 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.m @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSNativeEventModule.h" +#import "GaiaXJSDefines.h" +#import "GaiaXJSNativeEventManager.h" +#import "GaiaXJSFactory.h" + +@implementation GaiaXJSNativeEventModule + +GAIAXJS_EXPORT_MODULE(NativeEvent) + +/* + data 内容 @{} + templateId, + targetId, + instanceId, + eventType, + option + */ + +//添加监听 +GAIAXJS_EXPORT_ASYNC_METHOD(addEventListener:(NSDictionary *) extendInfo resolver:(GaiaXJSPromiseResolveBlock) resolve rejecter:(GaiaXJSPromiseRejectBlock) reject) { + NSLog(@"native extendInfo = %@", extendInfo); + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(addEventListener:)]) { + BOOL success = [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(addEventListener:) withObject:extendInfo]; + if (success) { + if (resolve != nil) { + resolve(nil); + } + } else { + if (reject != nil) { + reject(@"-1", @"无法添加事件"); + } + } + } else { + if (reject != nil) { + reject(@"-1", @"无法添加事件"); + } + } +} + +//移除监听 +GAIAXJS_EXPORT_ASYNC_METHOD(removeEventListener:(NSDictionary *) extendInfo resolver:(GaiaXJSPromiseResolveBlock) resolve rejecter:(GaiaXJSPromiseRejectBlock) reject) { + NSLog(@"native extendInfo = %@", extendInfo); + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(removeEventListener:)]) { + BOOL success = [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(removeEventListener:) withObject:extendInfo]; + if (success) { + if (resolve != nil) { + resolve(nil); + } + } else { + if (reject != nil) { + reject(@"-1", @"无法移除事件"); + } + } + } else { + if (reject != nil) { + reject(@"-1", @"无法移除事件"); + } + } +} + +GAIAXJS_EXPORT_SYNC_METHOD(NSNumber *, addNativeEventListener:(NSDictionary *) extendInfo) { + NSLog(@"native extendInfo = %@", extendInfo); + BOOL success = [GaiaXJSNativeEventManager registerMessage:extendInfo]; + return @(success); +} + +GAIAXJS_EXPORT_SYNC_METHOD(NSNumber *, removeNativeEventListener:(NSDictionary *) extendInfo) { + NSLog(@"native extendInfo = %@", extendInfo); + BOOL success = [GaiaXJSNativeEventManager unRegisterMessage:extendInfo]; + return @(success); +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.h new file mode 100644 index 000000000..46a5df051 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import "GaiaXJSDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSNativeLoggerModule : NSObject + + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.m new file mode 100644 index 000000000..01f426555 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.m @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSNativeLoggerModule.h" +#import +#import "GaiaXJSHandler.h" + +@implementation GaiaXJSNativeLoggerModule + +GAIAXJS_EXPORT_MODULE(NativeLogger) + +GAIAXJS_EXPORT_SYNC_METHOD(void, log:(NSDictionary *) data) { + GaiaXSocketModel *model = [GaiaXSocketModel notificationWithMethod:@"js/console" params:@{@"level": @"log", @"data": data != nil && data[@"data"] != nil ? data[@"data"] : @""}]; + [[[GaiaXSocketManager sharedInstance] socketClient] sendeNotification:model]; +} + +GAIAXJS_EXPORT_SYNC_METHOD(void, info:(NSDictionary *) data) { + GaiaXSocketModel *model = [GaiaXSocketModel notificationWithMethod:@"js/console" params:@{@"level": @"info", @"data": data != nil && data[@"data"] != nil ? data[@"data"] : @""}]; + [[[GaiaXSocketManager sharedInstance] socketClient] sendeNotification:model]; +} + +GAIAXJS_EXPORT_SYNC_METHOD(void, warn:(NSDictionary *) data) { + GaiaXSocketModel *model = [GaiaXSocketModel notificationWithMethod:@"js/console" params:@{@"level": @"warn", @"data": data != nil && data[@"data"] != nil ? data[@"data"] : @""}]; + [[[GaiaXSocketManager sharedInstance] socketClient] sendeNotification:model]; +} + +GAIAXJS_EXPORT_SYNC_METHOD(void, error:(NSDictionary *) data) { + GaiaXSocketModel *model = [GaiaXSocketModel notificationWithMethod:@"js/console" params:@{@"level": @"error", @"data": data != nil && data[@"data"] != nil ? data[@"data"] : @""}]; + [[[GaiaXSocketManager sharedInstance] socketClient] sendeNotification:model]; + if (data && data[@"data"] != nil) { + NSDictionary *errorDictionary = data[@"data"]; + if ([errorDictionary isKindOfClass:[NSDictionary class]]) { + NSDictionary *errorInfo = @{@"errorCode": [NSString stringWithFormat:@"%@##%@@%@##%@", GaiaXJSSafeString(errorDictionary[@"bizId"]), GaiaXJSSafeString(errorDictionary[@"templateId"]), GaiaXJSSafeString(errorDictionary[@"templateVersion"]), GaiaXJSSafeString(errorDictionary[@"message"])], @"errorMessage": GaiaXJSSafeString(errorDictionary[@"message"]), @"errorStack": GaiaXJSSafeString(errorDictionary[@"stack"])}; + [GaiaXJSHandler throwJSError:errorInfo]; + } else { + NSDictionary *errorInfo = @{@"errorCode": GaiaXJSSafeString(data[@"data"]), @"errorMessage": GaiaXJSSafeString(data[@"data"])}; + [GaiaXJSHandler throwJSError:errorInfo]; + } + + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.h new file mode 100644 index 000000000..9945eea0c --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSNativeTargetModule : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.m new file mode 100644 index 000000000..99e664ab9 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSNativeTargetModule.h" +#import "GaiaXJSDefines.h" +#import "GaiaXJSFactory.h" + +@implementation GaiaXJSNativeTargetModule + +GAIAXJS_EXPORT_MODULE(NativeTarget) + +GAIAXJS_EXPORT_SYNC_METHOD(NSDictionary *, getElementByData:(NSDictionary *) extendInfo) { + NSDictionary *result = nil; + if ([[GaiaXJSFactory defaultFactory].modulesImplDelegate respondsToSelector:@selector(getElement:)]) { + result = [[GaiaXJSFactory defaultFactory].modulesImplDelegate performSelector:@selector(getElement:) withObject:extendInfo]; + } + return result; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXImageUIModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXImageUIModule.h new file mode 100644 index 000000000..81c0880be --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXImageUIModule.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// +// GaiaXImageUIModule.h +// GaiaXJS +// +// Created by ronghui on 2021/5/27. +// + +#import "GaiaXViewStyleModule.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXImageStyleModule : GaiaXViewStyleModule + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.h new file mode 100644 index 000000000..df80d7292 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import +#import "GaiaXJSDefines.h" +#import "GaiaXJSUIViewModule.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSUIImageModule : GaiaXJSUIViewModule + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.m new file mode 100644 index 000000000..b97b0d145 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.m @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSUIImageModule.h" + +@implementation GaiaXJSUIImageModule + +//GAIAXJS_EXPORT_UI_MODULE(Image) + +GAIAXJS_EXPORT_UI_PROPERTY(url, NSString*) + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.h new file mode 100644 index 000000000..410404d28 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import +#import "GaiaXJSDefines.h" +#import "GaiaXJSUIViewModule.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSUITextModule : GaiaXJSUIViewModule + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.m new file mode 100644 index 000000000..ab14d9cbc --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSUITextModule.h" + +@implementation GaiaXJSUITextModule + +//GAIAXJS_EXPORT_UI_MODULE(Text) + +GAIAXJS_EXPORT_UI_STYLE(lines, NSInteger) + +GAIAXJS_EXPORT_UI_STYLE(color, UIColor) + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.h b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.h new file mode 100644 index 000000000..61822bbcd --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import +#import "GaiaXJSDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSUIViewModule : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.m b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.m new file mode 100644 index 000000000..809febdcf --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.m @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSUIViewModule.h" + +@implementation GaiaXJSUIViewModule + +GAIAXJS_EXPORT_UI_MODULE(View) + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.h b/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.h new file mode 100644 index 000000000..dd7204ad4 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" + + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSContext; +@protocol GaiaXJSContextProtocol; + +@interface GaiaXJSComponent : NSObject + +@property(nonatomic, strong) NSString *bizId; +@property(nonatomic, strong) NSString *templateId; +@property(nonatomic, strong) NSString *templateVersion; +@property(nonatomic, assign) NSInteger instanceId; +@property(nonatomic, strong) NSString *jsString; + +@property(nonatomic, weak) id delegate; + +- (instancetype)initWithContext:(GaiaXJSContext *)context + bizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId; + +- (instancetype)initWithContext:(GaiaXJSContext *)context + bizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId + jsString:(nullable NSString *)jsString; + +/** + 整个生命周期内只会回调一次 + */ +- (void)onReady; + +/** + 组件复用时回调 + */ +- (void)onReuse; + +/** + 每次当组件显示时调用一次 + */ +- (void)onShow; + +/** + 每次当组件消失时调用一次 + */ +- (void)onHide; + +/** + 组件触发加载更多时调用 + */ +- (void)onLoadMore:(NSDictionary *)params; + +/** + 组件要销毁时调用 + */ +- (void)onDestroy; + +/** + 传递事件 + */ +- (void)emmitEvent:(GaiaXJSEventType)eventType data:(NSDictionary *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.m b/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.m new file mode 100644 index 000000000..d43a8e876 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.m @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSComponent.h" +#import "GaiaXJSContext.h" +#import +#import "GaiaXJSHandler.h" + +@interface GaiaXJSComponent () + +@property(nonatomic, weak) GaiaXJSContext *context; + +@end + +@implementation GaiaXJSComponent + +- (instancetype)initWithContext:(GaiaXJSContext *)context + bizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId { + return [self initWithContext:context + bizId:bizId + templateId:templateId + templateVersion:templateVersion + instanceId:instanceId + jsString:nil]; +} + +- (instancetype)initWithContext:(GaiaXJSContext *)context + bizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId + jsString:(nullable NSString *)jsString { + if (self = [super init]) { + self.context = context; + if (bizId == nil || bizId.length <= 0) { + self.bizId = @"common"; + } else { + self.bizId = bizId; + } + self.templateId = templateId; + self.templateVersion = (templateVersion.length <= 0 ? @"-1" : templateVersion); + self.instanceId = instanceId; + self.jsString = jsString; + } + return self; +} + +- (void)emmitEvent:(GaiaXJSEventType)eventType data:(NSDictionary *)data { + NSMutableDictionary *injectEventData = [[NSMutableDictionary alloc] init]; + if (data == nil || self.templateId == nil) { + return; + } + [injectEventData addEntriesFromDictionary:data]; + [injectEventData setObject:GaiaXJSSafeString(self.bizId) forKey:@"bizId"]; + [injectEventData setObject:GaiaXJSSafeString(self.templateId) forKey:@"templateId"]; + [injectEventData setObject:GaiaXJSSafeString(self.templateVersion) forKey:@"templateVersion"]; + [injectEventData setObject:@(self.instanceId) forKey:@"instanceId"]; + if (eventType == GaiaXJSEventTypeClick) { + [injectEventData setObject:@"click" forKey:@"type"]; + } else if (eventType == GaiaXJSEventTypeDoubleClick) { + [injectEventData setObject:@"dblclick" forKey:@"type"]; + } else if (eventType == GaiaXJSEventTypeSwipe) { + [injectEventData setObject:@"swipe" forKey:@"type"]; + } else if (eventType == GaiaXJSEventTypeLongPress) { + [injectEventData setObject:@"longpress" forKey:@"type"]; + } else if (eventType == GaiaXJSEventTypePinch) { + [injectEventData setObject:@"pinch" forKey:@"type"]; + } + NSData *jsonData = nil; + @try { + jsonData = [NSJSONSerialization dataWithJSONObject:injectEventData + options:0 + error:NULL]; + } @catch (NSException *exception) { + + } @finally { + NSString *jsonString = nil; + if (jsonData != nil) { + jsonString = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + } + NSString *injectString = + [NSString stringWithFormat:@"window.postMessage(%@)", jsonString]; + [self.context.bridge evalScript:injectString fileName:@"index.js"]; + } +} + +- (void)onReady { + if (self.jsString.length > 0) { + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartLoadIndexJS extendInfo:@{@"timestamp": @(startTime), + @"templateId": GaiaXJSSafeString(self.templateId), + @"templateVersion": GaiaXJSSafeString(self.templateVersion), + @"templateBiz": GaiaXJSSafeString(self.bizId) + }]; + [self.context.bridge executeIndexJS:self.jsString + fileName:@"index.js" + args:@{@"bizId": self.bizId, + @"templateId": self.templateId, + @"instanceId": @(self.instanceId), + @"templateVersion": self.templateVersion} + callback:^{ + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndLoadIndexJS extendInfo:@{@"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"templateId": GaiaXJSSafeString(self.templateId), + @"templateVersion": GaiaXJSSafeString(self.templateVersion), + @"templateBiz": GaiaXJSSafeString(self.bizId) + }]; + }]; + + NSString *readyStr = [NSString + stringWithFormat:@"(function () {var instance = IMs.getComponent(%ld); " + @"if (instance) { instance.onShow && instance.onShow(); " + @"instance.onReady && instance.onReady(); }})()", + (long) self.instanceId]; + [self.context.bridge evalScript:readyStr fileName:@"index.js"]; + } +} + +- (void)onShow { + NSString *showStr = + [NSString stringWithFormat: + @"(function () {var instance = IMs.getComponent(%ld); if " + @"(instance) { instance.onShow && instance.onShow(); }})()", + (long) self.instanceId]; + [self.context.bridge evalScript:showStr fileName:@"index.js"]; +} + +- (void)onReuse { + NSString *reuseStr = [NSString + stringWithFormat: + @"(function () {var instance = IMs.getComponent(%ld); if " + @"(instance) { instance.onReuse && instance.onReuse(); }})()", + (long) self.instanceId]; + [self.context.bridge evalScript:reuseStr fileName:@"index.js"]; +} + +- (void)onLoadMore:(NSDictionary *)params { + NSData *jsonData = nil; + @try { + jsonData = [NSJSONSerialization dataWithJSONObject:params + options:0 + error:NULL]; + } @catch (NSException *exception) { + + } @finally { + NSString *jsonString = nil; + if (jsonData != nil) { + jsonString = [[NSString alloc] initWithData:jsonData + encoding:NSUTF8StringEncoding]; + NSString *reuseStr = [NSString + stringWithFormat: + @"(function () {var instance = IMs.getComponent(%ld); if " + @"(instance) { instance.onLoadMore && instance.onLoadMore(%@); }})()", + (long) self.instanceId, jsonString]; + [self.context.bridge evalScript:reuseStr fileName:@"index.js"]; + } + } +} + +- (void)onHide { + NSString *hideStr = + [NSString stringWithFormat: + @"(function () {var instance = IMs.getComponent(%ld); if " + @"(instance) { instance.onHide && instance.onHide(); }})()", + (long) self.instanceId]; + [self.context.bridge evalScript:hideStr fileName:@"index.js"]; +} + +- (void)onDestroy { + NSString *destroyStr = + [NSString stringWithFormat: + @"(function () {var instance = IMs.getComponent(%ld); if " + @"(instance) { instance.onDestroy && instance.onDestroy(); " + @"} IMs.removeComponent(%ld); })()", + (long) self.instanceId, (long) self.instanceId]; + [self.context.bridge evalScript:destroyStr fileName:@"index.js"]; + + if (_delegate != nil && + [_delegate respondsToSelector:@selector(componentDidRemoved:)]) { + [_delegate componentDidRemoved:self]; + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.h b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.h new file mode 100644 index 000000000..3ec3b301c --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSContext.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSCContext : GaiaXJSContext + +@property(nonatomic, strong) JSContext *ctx; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.m b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.m new file mode 100644 index 000000000..214c97ef0 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.m @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSCContext.h" +#import "GaiaXJSCRuntime.h" +#import "GaiaXJSModuleManager.h" +#import "GaiaXJSUIManager.h" +#import "GaiaXJSCModule.h" +#import "GaiaXJSHelper.h" +#import "GaiaXJSHandler.h" + +@interface GaiaXJSCContext () + +@property(nonatomic, weak) GaiaXJSCRuntime *runtime; + + +@end + +@implementation GaiaXJSCContext + +- (instancetype)initWithRuntime:(GaiaXJSRuntime *)runtime { + if (self = [super initWithRuntime:runtime]) { + self.runtime = (GaiaXJSCRuntime *) runtime; + self.ctx = [[JSContext alloc] initWithVirtualMachine:self.runtime.vm]; + [self setUpContext:self.ctx]; + } + return self; +} + +- (void)dealloc { + NSLog(@"GaiaXJSCContext dealloc"); +} + +- (void)setUpContext:(JSContext *)ctx { + [self.bridge setupContext:^{ + init_jsc_module(self); + + [ctx setExceptionHandler:^(JSContext *context, JSValue *exception) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GaiaXJSDidChangedNotification" object:nil userInfo:@{@"level": @"error", @"data": GaiaXJSSafeString([exception toString])}]; + + NSDictionary *errorInfo = @{@"errorCode": GaiaXJSSafeString([exception toString]), @"errorMessage": GaiaXJSSafeString([exception toString]), @"errorStack": GaiaXJSSafeString([[exception objectForKeyedSubscript:@"stack"] toString])}; + [GaiaXJSHandler throwJSError:errorInfo]; + + }]; + + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartLoadJSLibrary extendInfo:@{@"timestamp": @(startTime)}]; + + NSString *bootstrapPath = [[NSBundle mainBundle] pathForResource:@"GaiaXJS.bundle/bootstrap.min" ofType:@"js"]; + NSMutableString *bootstrapString = [NSMutableString string]; + [bootstrapString appendFormat:@"\r\nvar __globalThis = this; \r\n__globalThis.__CONTEXT_ID__ = %ld;\r\n __globalThis.__ENGINE_TYPE__ = 1;\r\n", (long) self.contextId]; + NSDictionary *env = [[NSProcessInfo processInfo] environment]; + if ([env[@"GAIAX_JS_DEV"] boolValue]) { + [bootstrapString appendFormat:@"__globalThis.__DEV__ = true; \r\n"]; + } + [bootstrapString appendString:[GaiaXJSHelper getHelperJSMethods]]; + NSString *fileString = [[NSString alloc] initWithContentsOfFile:bootstrapPath encoding:NSUTF8StringEncoding error:NULL]; + [bootstrapString appendString:fileString]; + [bootstrapString appendFormat:@"%@", [[GaiaXJSModuleManager defaultManager] injectConfigs]]; + [bootstrapString appendFormat:@"%@", [[GaiaXJSUIManager defaultManager] injectProps]]; + + [self.bridge executeJSLibrary:bootstrapString fileName:@"bootstrap.min.js"]; + + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndLoadJSLibrary extendInfo:@{@"timestamp": @(endTime), + @"cost": @(endTime-startTime) + }]; + }]; + +} + +- (void)executeIndexJS:(NSString *)jsString fileName:(NSString *)fileName args:(NSDictionary *)args { + NSString *str = jsString; + if (args != nil) { + NSArray *jsArray = [str componentsSeparatedByString:@"\r\n"]; + NSMutableArray *newContentArray = [[NSMutableArray alloc] init]; + for (NSInteger i = 0; i < jsArray.count; i++) { + if ([jsArray[i] hasPrefix:@"//"]) { + continue; + } + [newContentArray addObject:jsArray[i]]; + } + if (newContentArray.count > 0) { + str = [newContentArray componentsJoinedByString:@"\r\n"]; + } + str = [str + stringByTrimmingCharactersInSet:[NSCharacterSet + whitespaceAndNewlineCharacterSet]]; + NSRange range = [str rangeOfString:@"})" options:NSBackwardsSearch]; + str = [str + stringByReplacingCharactersInRange:range + withString: + [NSString + stringWithFormat: + @"},{ 'bizId':'%@', 'templateId': " + @"'%@', 'instanceId': %@, 'templateVersion': '%@' } )", + args[@"bizId"], args[@"templateId"], + args[@"instanceId"], args[@"templateVersion"]]]; + } + + if (str.length > 0) { + if (fileName != nil && fileName.length > 0) { + [self.ctx evaluateScript:str withSourceURL:[NSURL URLWithString:fileName]]; + + } else { + [self.ctx evaluateScript:str]; + } + } +} + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName { + if (jsString.length > 0) { + if (fileName != nil && fileName.length > 0) { + [self.ctx evaluateScript:jsString withSourceURL:[NSURL URLWithString:fileName]]; + + } else { + [self.ctx evaluateScript:jsString]; + } + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.h b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.h new file mode 100644 index 000000000..709b52be7 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSRuntime; +@class GaiaXJSComponent; + +@protocol GaiaXJSContextProtocol + +- (void)componentDidRemoved:(GaiaXJSComponent *)component; + +@end + +@interface GaiaXJSContext : NSObject + +@property(nonatomic, strong) GaiaXJSBridge *bridge; +@property(nonatomic, assign) NSInteger contextId; + +- (instancetype)initWithRuntime:(GaiaXJSRuntime *)runtime; + +- (GaiaXJSComponent *)newComponentWithBizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId; + + +- (GaiaXJSComponent *)newComponentWithBizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId + jsString:(nullable NSString *)jsString; + +- (NSUInteger)getComponentsCountByBizId:(NSString *)bizId; + +- (NSUInteger)getAllComponentsCount; + +- (void)executeIndexJS:(NSString *)jsString fileName:(NSString *)fileName args:(NSDictionary *)args; + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName; + + +/** + 销毁 + */ +- (void)onDestroy; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.m b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.m new file mode 100644 index 000000000..277548855 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.m @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSContext.h" +#import "GaiaXJSComponent.h" +#import "GaiaXJSRuntime.h" + +@interface GaiaXJSContext () + +@property(nonatomic, strong) NSMapTable *> *componentsMap; + +@end + +@implementation GaiaXJSContext + + +- (instancetype)initWithRuntime:(GaiaXJSRuntime *)runtime { + if (self = [super init]) { + runtime.context = self; + self.componentsMap = [NSMapTable strongToStrongObjectsMapTable]; + self.bridge = [[GaiaXJSBridge alloc] initWidthJSContext:self]; + } + return self; +} + +- (GaiaXJSComponent *)newComponentWithBizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId + jsString:(nullable NSString *)jsString { + GaiaXJSComponent *jsComponent = [[GaiaXJSComponent alloc] initWithContext:self + bizId:bizId + templateId:templateId + templateVersion:templateVersion + instanceId:instanceId + jsString:jsString]; + jsComponent.delegate = self; + NSMapTable *mapTable = nil; + if ([self.componentsMap objectForKey:bizId] == nil) { + mapTable = [NSMapTable strongToStrongObjectsMapTable]; + [self.componentsMap setObject:mapTable forKey:bizId]; + } else { + mapTable = [self.componentsMap objectForKey:bizId]; + } + [mapTable setObject:jsComponent forKey:@(instanceId)]; + return jsComponent; +} + +- (GaiaXJSComponent *)newComponentWithBizId:(NSString *)bizId + templateId:(NSString *)templateId + templateVersion:(NSString *)templateVersion + instanceId:(NSInteger)instanceId { + return [self newComponentWithBizId:bizId + templateId:templateId + templateVersion:templateVersion + instanceId:instanceId + jsString:nil]; +} + +- (NSUInteger)getComponentsCountByBizId:(NSString *)bizId { + NSUInteger count = 0; + NSMapTable *mapTable = [self.componentsMap objectForKey:bizId]; + if (mapTable != nil) { + count = [mapTable count]; + } + return count; +} + +- (NSUInteger)getAllComponentsCount { + NSEnumerator *itemEnumerator = [self.componentsMap objectEnumerator]; + NSMapTable *mapTable = nil; + NSUInteger count = 0; + while (mapTable = [itemEnumerator nextObject]) { + if (mapTable != nil) { + count += [mapTable count]; + } + } + return count; +} + +- (void)executeIndexJS:(NSString *)jsString fileName:(NSString *)fileName args:(NSDictionary *)args { +} + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName { +} + +- (void)onDestroy { + [self removeAllComponnets]; +} + +- (void)removeAllComponnets { + NSEnumerator *itemEnumerator = [self.componentsMap objectEnumerator]; + NSMapTable *mapTable = nil; + while (mapTable = [itemEnumerator nextObject]) { + if (mapTable != nil) { + GaiaXJSComponent *component = nil; + NSEnumerator *componentEnumerator = [mapTable objectEnumerator]; + while (component = [componentEnumerator nextObject]) { + [component onDestroy]; + } + } + } +} + +- (void)componentDidRemoved:(GaiaXJSComponent *)component { + [self removeComponentByBizId:component.bizId instanceId:component.instanceId]; +} + +- (void)removeComponentByBizId:(NSString *)bizId instanceId:(NSInteger)instanceId { + NSMapTable *mapTable = [self.componentsMap objectForKey:bizId]; + if (mapTable != nil) { + [mapTable removeObjectForKey:@(instanceId)]; + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.h b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.h new file mode 100644 index 000000000..e358e5d41 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSContext.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSDebuggerContext : GaiaXJSContext + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.m b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.m new file mode 100644 index 000000000..42ba44dc4 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.m @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSDebuggerContext.h" +#import "GaiaXJSDRuntime.h" +#import "GaiaXJSModuleManager.h" +#import "GaiaXJSUIManager.h" + +@interface GaiaXJSDebuggerContext () + +@property(nonatomic, weak) GaiaXJSDRuntime *runtime; +@property(nonatomic, strong) NSString *boostraptring; + +@end + +@implementation GaiaXJSDebuggerContext + +- (instancetype)initWithRuntime:(GaiaXJSRuntime *)runtime { + if (self = [super initWithRuntime:runtime]) { + self.runtime = (GaiaXJSDRuntime *) runtime; + self.runtime.wsWrapper.jsBridge = self.bridge; + [self setUpContext]; + } + return self; +} + +- (void)setUpContext { + [self.bridge setupContext:^{ + NSMutableString *bootstrapString = [NSMutableString string]; + [bootstrapString appendFormat:@"\r\nvar __globalThis = this; \r\n__globalThis.__CONTEXT_ID__ = %ld;\r\n __globalThis.__ENGINE_TYPE__ = 10;\r\n", (long) self.contextId]; + NSDictionary *env = [[NSProcessInfo processInfo] environment]; + if ([env[@"GAIAX_JS_DEV"] boolValue]) { + [bootstrapString appendFormat:@"__globalThis.__DEV__ = true; \r\n"]; + } + [bootstrapString appendString:@"/**bridge.ts**/\r\n"]; + [bootstrapString appendString:@"/**bootstrap.ts**/\r\n"]; + [bootstrapString appendFormat:@"%@", [[GaiaXJSModuleManager debuggerManager] rdInjectConfigs]]; + [bootstrapString appendFormat:@"%@", [[GaiaXJSUIManager debuggerManager] rdInjectProps]]; + self.boostraptring = bootstrapString; + [self.bridge executeJSLibrary:bootstrapString fileName:@"debugger.js"]; + }]; +} + + +- (void)evalScript:(NSString *)jsString fileName:(NSString *)fileName { + if (jsString != nil && jsString.length > 0) { + if ([fileName isEqualToString:@"debugger.js"]) { + [self.runtime.wsWrapper evalInitEnvJSScript:jsString]; + } else { + [self.runtime.wsWrapper sendJSScript:jsString]; + } + } +} + +- (void)executeIndexJS:(NSString *)jsString fileName:(NSString *)fileName args:(NSDictionary *)args { + if (jsString != nil && jsString.length > 0) { + [self.runtime.wsWrapper createJSComponent:args]; + } +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.h b/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.h new file mode 100644 index 000000000..7b77c3a77 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSBridge.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void(^WSWBlock)(void); + +@interface GaiaXJSWebSocketWrapper : NSObject + +@property(nonatomic, weak) GaiaXJSBridge *jsBridge; + + +- (void)createJSComponent:(NSDictionary *)params; + +- (void)evalInitEnvJSScript:(NSString *)jsScript; + +- (void)sendJSScript:(NSString *)script; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.m b/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.m new file mode 100644 index 000000000..7dcea6173 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.m @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSWebSocketWrapper.h" +#import "GaiaXJSDefines.h" +#import "GaiaXJSModuleManager.h" +#import + +@interface GaiaXJSWebSocketWrapper () + +@property(nonatomic, strong) dispatch_queue_t gaiaxJSDebugQueue; +@property(nonatomic, strong) dispatch_semaphore_t semaphore; +@property(nonatomic, strong) NSString *bootstrapJS; + +@end + +@implementation GaiaXJSWebSocketWrapper + +- (instancetype)init { + if (self = [super init]) { + NSString *labelString = [NSString stringWithFormat:@"%@", GaiaXJSDebugQueuePrefix]; + self.gaiaxJSDebugQueue = dispatch_queue_create(labelString.UTF8String, NULL); + self.semaphore = dispatch_semaphore_create(0); + [[GaiaXSocketManager sharedInstance] registerListener:self]; + } + return self; +} + +- (GaiaXSocketClient *)socketClient { + return [[GaiaXSocketManager sharedInstance] socketClient]; +} + +- (NSString *)gxMessageId { + return @"GAIAX_JS_DEBUGGER"; +} + +- (void)gxSocketClient:(GaiaXSocketClient *)client didReceiveMessage:(GaiaXSocketModel *)model { + if (model.messageId == nil) { + return; + } + if ([model.method isEqualToString:@"js/callSync"]) { + dispatch_async(self.jsBridge.gaiaxJSQueue, ^{ + NSDictionary *dictionary = model.params; + id retValue = [[GaiaXJSModuleManager debuggerManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + args:dictionary[@"args"]]; + dispatch_async(self.gaiaxJSDebugQueue, ^{ + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + if (retValue != nil) { + result[@"value"] = retValue; + } + GaiaXSocketModel *response = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] + result:result]; + [client sendResponse:response]; + }); + + }); + } else if ([model.method isEqualToString:@"js/callAsync"]) { + dispatch_async(self.jsBridge.gaiaxJSQueue, ^{ + NSDictionary *dictionary = model.params; + [[GaiaXJSModuleManager debuggerManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + args:dictionary[@"args"] + callback:^(id result) { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + NSString *script = nil; + if (result != nil) { + script = [NSString stringWithFormat:@"Bridge.invokeCallback(%@, %@)", dictionary[@"callbackId"], [self stringifyGaiaXJSValue:result]]; + } else { + script = [NSString stringWithFormat:@"Bridge.invokeCallback(%@)", dictionary[@"callbackId"]]; + } + GaiaXSocketModel *response = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] + result:@{@"script": script}]; + [client sendResponse:response]; + }); + + }]; + + }); + } else if ([model.method isEqualToString:@"js/callPromise"]) { + dispatch_async(self.jsBridge.gaiaxJSQueue, ^{ + NSDictionary *dictionary = model.params; + [[GaiaXJSModuleManager debuggerManager] + invokeMethodWithContextId:[dictionary[@"contextId"] integerValue] + moduleId:[dictionary[@"moduleId"] integerValue] + methodId:[dictionary[@"methodId"] integerValue] + args:dictionary[@"args"] + resolver:^(id result) { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + NSString *script = nil; + if (result != nil) { + script = [NSString stringWithFormat:@"Bridge.invokePromiseSuccess(%@, %@)", dictionary[@"callbackId"], [self stringifyGaiaXJSValue:result]]; + } else { + script = [NSString stringWithFormat:@"Bridge.invokePromiseSuccess(%@)", dictionary[@"callbackId"]]; + } + GaiaXSocketModel *response = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] + result:@{@"script": script}]; + [client sendResponse:response]; + }); + + } + rejecter:^(NSString *code, NSString *message) { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + NSString *script = nil; + if (code != nil && message != nil) { + script = [NSString stringWithFormat:@"Bridge.invokePromiseFailure(%@, %@)", dictionary[@"callbackId"], @{@"code": code, @"message": message}]; + } else { + script = [NSString stringWithFormat:@"Bridge.invokePromiseFailure(%@)", dictionary[@"callbackId"]]; + } + GaiaXSocketModel *response = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] result:@{@"script": script}]; + [client sendResponse:response]; + }); + + }]; + }); + } else if ([model.method isEqualToString:@"js/getLibrary"]) { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + GaiaXSocketModel *response = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] result:@{@"script": self.bootstrapJS}]; + [client sendResponse:response]; + }); + } +} + +- (void)createJSComponent:(NSDictionary *)params { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + GaiaXSocketModel *request = [GaiaXSocketModel requestWithMethod:@"js/createComponent" + params:params]; + [self.socketClient sendRequest:request callback:^(GaiaXSocketModel *_Nonnull model) { + + }]; + }); +} + +- (void)evalInitEnvJSScript:(NSString *)jsScript { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + self.bootstrapJS = jsScript; + GaiaXSocketModel *request = [GaiaXSocketModel requestWithMethod:@"js/initJSEnv" + params:@{@"script": jsScript}]; + [self.socketClient sendRequest:request callback:^(GaiaXSocketModel *_Nonnull model) { + + }]; + }); +} + +- (void)sendJSScript:(NSString *)script { + dispatch_async(self.gaiaxJSDebugQueue, ^{ + GaiaXSocketModel *request = [GaiaXSocketModel requestWithMethod:@"js/eval" + params:@{@"script": script}]; + [self.socketClient sendRequest:request callback:^(GaiaXSocketModel *_Nonnull model) { + + }]; + }); + +} + + +- (id)stringifyGaiaXJSValue:(id)value { + id result = value; + if ([value isKindOfClass:[NSDictionary class]]) { + @try { + NSData *data = [NSJSONSerialization dataWithJSONObject:value options:0 error:NULL]; + result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } @catch (NSException *exception) { + + } @finally { + } + } + return result; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.h b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.h new file mode 100644 index 000000000..8689f6195 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import +#import "GaiaXJSRuntime.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSCRuntime : GaiaXJSRuntime + +@property(nonatomic, strong) JSVirtualMachine *vm; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.m b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.m new file mode 100644 index 000000000..14fb8d11b --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSCRuntime.h" + +@implementation GaiaXJSCRuntime + +- (instancetype)init { + if (self = [super init]) { + self.vm = [[JSVirtualMachine alloc] init]; + } + return self; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.h b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.h new file mode 100644 index 000000000..0eba8029f --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSWebSocketWrapper.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSDRuntime : GaiaXJSRuntime + +@property(nonatomic, strong) GaiaXJSWebSocketWrapper *wsWrapper; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.m b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.m new file mode 100644 index 000000000..63d3167e4 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.m @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSDRuntime.h" + +@implementation GaiaXJSDRuntime + + +- (instancetype)init { + if (self = [super init]) { + // 连接 + self.wsWrapper = [[GaiaXJSWebSocketWrapper alloc] init]; + } + return self; +} + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.h b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.h new file mode 100644 index 000000000..193a53a78 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import "GaiaXJSContext.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSRuntime : NSObject + +@property(nonatomic, strong) GaiaXJSContext *context; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.m b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.m new file mode 100644 index 000000000..ba435458a --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.m @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSRuntime.h" + +@implementation GaiaXJSRuntime + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.h b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.h new file mode 100644 index 000000000..922d10c37 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSMethodArgument : NSObject + +@property(nonatomic, copy, readonly) NSString *type; +@property(nonatomic, readonly) GaiaXJSNullability nullability; +@property(nonatomic, readonly) BOOL unused; + +- (instancetype)initWithType:(NSString *)type nullability:(GaiaXJSNullability)nullability unused:(BOOL)unused; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.m b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.m new file mode 100644 index 000000000..69aa7c575 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.m @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSMethodArgument.h" + +@implementation GaiaXJSMethodArgument + +- (instancetype)initWithType:(NSString *)type nullability:(GaiaXJSNullability)nullability unused:(BOOL)unused { + if (self = [super init]) { + _type = [type copy]; + _nullability = nullability; + _unused = unused; + } + return self; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.h b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.h new file mode 100644 index 000000000..288dcc58f --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSDefines.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSModuleInfo; + +@interface GaiaXJSMethodInfo : NSObject + +@property(nonatomic, weak) GaiaXJSModuleInfo *moduleInfo; +@property(nonatomic, strong) NSString *methodName; +@property(nonatomic, assign) BOOL isSync; +@property(nonatomic, assign) GaiaXJSMethodType methodType; + +- (instancetype)initWithExportedMethod:(GaiaXJSExportedMethod *)exportMethod + moduleInfo:(GaiaXJSModuleInfo *)moduleInfo NS_DESIGNATED_INITIALIZER; + + +- (id)invokeWithArguments:(NSArray *)args; + +- (void)invokeWithArguments:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback; + +- (void)invokeWithArguments:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.m b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.m new file mode 100644 index 000000000..68075a7aa --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.m @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSMethodInfo.h" +#import "GaiaXJSMethodArgument.h" +#import "GaiaXJSHelper.h" +#import "GaiaXJSModuleInfo.h" +#import "GaiaXJSConvert.h" +#import +#import + +typedef BOOL (^GAIAXJSArgumentBlock)(NSUInteger, id); + +@interface GaiaXJSMethodInfo () + +@property(nonatomic, strong) NSMutableArray *retainedObjects; + +@end + +@implementation GaiaXJSMethodInfo + + +static SEL selectorForType(NSString *type) { + const char *input = type.UTF8String; + return NSSelectorFromString([GaiaXJSParseType(&input) stringByAppendingString:@":"]); +} + +- (instancetype)initWithExportedMethod:(GaiaXJSExportedMethod *)exportMethod + moduleInfo:(GaiaXJSModuleInfo *)moduleInfo { + if (self = [super init]) { + self.moduleInfo = moduleInfo; + self.isSync = exportMethod->isSync; + self.methodName = [NSString stringWithFormat:@"%s", exportMethod->objcName]; + if (self.isSync) { + self.methodType = GaiaXJSMethodTypeSync; + } else { + if ([self.methodName rangeOfString:@"GaiaXJSPromiseResolveBlock"].location != NSNotFound || + [self.methodName rangeOfString:@"GaiaXPromiseResolveBlock"].location != NSNotFound || + [self.methodName rangeOfString:@"GaiaXJSPromiseRejectBlock"].location != NSNotFound || + [self.methodName rangeOfString:@"GaiaXPromiseRejectBlock"].location != NSNotFound) { + self.methodType = GaiaXJSMethodTypePromise; + } else { + self.methodType = GaiaXJSMethodTypeAsync; + } + } + self.retainedObjects = [NSMutableArray array]; + } + return self; +} + +- (id)invokeWithArguments:(NSArray *)args { + NSObject *object = [[NSClassFromString(self.moduleInfo.moduleName) alloc] init]; + + if (object == nil) { + return nil; + } + + NSArray *arguments; + SEL selector = NSSelectorFromString(GaiaXJSParseMethodSignature([self.methodName UTF8String], &arguments)); + NSMethodSignature *signature = [object methodSignatureForSelector:selector]; + if (!signature) { + return nil; + } + + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:selector]; + [invocation setTarget:object]; + + NSUInteger numberOfArguments = signature.numberOfArguments; + NSMutableArray *argumentBlocks = [[NSMutableArray alloc] init]; + for (NSUInteger i = 2; i < numberOfArguments; i++) { + const char *objcType = [signature getArgumentTypeAtIndex:i]; + BOOL isNullableType = NO; + GaiaXJSMethodArgument *argument = arguments[i - 2]; + NSString *typeName = argument.type; + SEL selector = selectorForType(typeName); + if ([GaiaXJSConvert respondsToSelector:selector]) { + switch (objcType[0]) { + case _C_CHR: GAIAXJS_PRIMITIVE_CASE(char) + case _C_UCHR: GAIAXJS_PRIMITIVE_CASE(unsigned char) + case _C_SHT: GAIAXJS_PRIMITIVE_CASE(short) + case _C_USHT: GAIAXJS_PRIMITIVE_CASE(unsigned short) + case _C_INT: GAIAXJS_PRIMITIVE_CASE(int) + case _C_UINT: GAIAXJS_PRIMITIVE_CASE(unsigned int) + case _C_LNG: GAIAXJS_PRIMITIVE_CASE(long) + case _C_ULNG: GAIAXJS_PRIMITIVE_CASE(unsigned long) + case _C_LNG_LNG: GAIAXJS_PRIMITIVE_CASE(long long) + case _C_ULNG_LNG: GAIAXJS_PRIMITIVE_CASE(unsigned long long) + case _C_FLT: GAIAXJS_PRIMITIVE_CASE(float) + case _C_DBL: GAIAXJS_PRIMITIVE_CASE(double) + case _C_BOOL: GAIAXJS_PRIMITIVE_CASE(BOOL) + case _C_SEL: GAIAXJS_PRIMITIVE_CASE(SEL) + case _C_CHARPTR: GAIAXJS_PRIMITIVE_CASE(const char *) + case _C_PTR: GAIAXJS_PRIMITIVE_CASE(void *) + case _C_ID: { + isNullableType = YES; + id (*convert)(id, SEL, id) = (__typeof__(convert)) objc_msgSend; + GAIAXJS_RETAINED_ARG_BLOCK(id value = convert([GaiaXJSConvert class], selector, json);); + break; + } + } + } + } + + NSUInteger index = 0; + for (id json in args) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, GAIAXJSNilIfNull(json))) { + return nil; + } + index++; + } + + for (; index < [argumentBlocks count]; index++) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, NULL)) { + return nil; + } + } + + + [invocation invoke]; + + if (*[signature methodReturnType] == '@') { + void *retValue = nil; + [invocation getReturnValue:&retValue]; + if (retValue) { + return (__bridge id) retValue; + } + } + + + return nil; +} + + +- (void)invokeWithArguments:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback { + NSObject *object = [[NSClassFromString(self.moduleInfo.moduleName) alloc] init]; + + if (object == nil) { + callback(nil); + return; + } + + NSArray *arguments; + SEL selector = NSSelectorFromString(GaiaXJSParseMethodSignature([self.methodName UTF8String], &arguments)); + NSMethodSignature *signature = [object methodSignatureForSelector:selector]; + if (!signature) { + callback(nil); + return; + } + + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:selector]; + [invocation setTarget:object]; + + NSUInteger numberOfArguments = signature.numberOfArguments; + NSMutableArray *argumentBlocks = [[NSMutableArray alloc] init]; + + for (NSUInteger i = 2; i < numberOfArguments; i++) { + const char *objcType = [signature getArgumentTypeAtIndex:i]; + BOOL isNullableType = NO; + GaiaXJSMethodArgument *argument = arguments[i - 2]; + NSString *typeName = argument.type; + SEL selector = selectorForType(typeName); + if ([GaiaXJSConvert respondsToSelector:selector]) { + switch (objcType[0]) { + case _C_CHR: GAIAXJS_PRIMITIVE_CASE(char) + case _C_UCHR: GAIAXJS_PRIMITIVE_CASE(unsigned char) + case _C_SHT: GAIAXJS_PRIMITIVE_CASE(short) + case _C_USHT: GAIAXJS_PRIMITIVE_CASE(unsigned short) + case _C_INT: GAIAXJS_PRIMITIVE_CASE(int) + case _C_UINT: GAIAXJS_PRIMITIVE_CASE(unsigned int) + case _C_LNG: GAIAXJS_PRIMITIVE_CASE(long) + case _C_ULNG: GAIAXJS_PRIMITIVE_CASE(unsigned long) + case _C_LNG_LNG: GAIAXJS_PRIMITIVE_CASE(long long) + case _C_ULNG_LNG: GAIAXJS_PRIMITIVE_CASE(unsigned long long) + case _C_FLT: GAIAXJS_PRIMITIVE_CASE(float) + case _C_DBL: GAIAXJS_PRIMITIVE_CASE(double) + case _C_BOOL: GAIAXJS_PRIMITIVE_CASE(BOOL) + case _C_SEL: GAIAXJS_PRIMITIVE_CASE(SEL) + case _C_CHARPTR: GAIAXJS_PRIMITIVE_CASE(const char *) + case _C_PTR: GAIAXJS_PRIMITIVE_CASE(void *) + case _C_ID: { + isNullableType = YES; + id (*convert)(id, SEL, id) = (__typeof__(convert)) objc_msgSend; + GAIAXJS_RETAINED_ARG_BLOCK(id value = convert([GaiaXJSConvert class], selector, json);); + break; + } + } + } else if ([typeName isEqualToString:@"GaiaXJSCallbackBlock"] || [typeName isEqualToString:@"GaiaXCallbackBlock"]) { + GAIAXJS_BLOCK_CASE((id result), { + callback(result); + }); + } + } + + NSUInteger index = 0; + for (id json in args) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, GAIAXJSNilIfNull(json))) { + callback(nil); + return; + } + index++; + } + + for (; index < [argumentBlocks count]; index++) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, NULL)) { + callback(nil); + return; + } + } + + + [invocation invoke]; + + [self.retainedObjects removeAllObjects]; + +} + +- (void)invokeWithArguments:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject { + NSObject *object = [[NSClassFromString(self.moduleInfo.moduleName) alloc] init]; + + if (object == nil) { + reject(@"-1", [NSString stringWithFormat:@"无法实例化模块 %@", self.moduleInfo.moduleName]); + return; + } + + NSArray *arguments; + SEL selector = NSSelectorFromString(GaiaXJSParseMethodSignature([self.methodName UTF8String], &arguments)); + NSMethodSignature *signature = [object methodSignatureForSelector:selector]; + if (!signature) { + reject(@"-2", [NSString stringWithFormat:@"无法实例化方法 %@", self.methodName]); + return; + } + + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setSelector:selector]; + [invocation setTarget:object]; + + NSUInteger numberOfArguments = signature.numberOfArguments; + NSMutableArray *argumentBlocks = [[NSMutableArray alloc] init]; + + for (NSUInteger i = 2; i < numberOfArguments; i++) { + const char *objcType = [signature getArgumentTypeAtIndex:i]; + BOOL isNullableType = NO; + GaiaXJSMethodArgument *argument = arguments[i - 2]; + NSString *typeName = argument.type; + SEL selector = selectorForType(typeName); + if ([GaiaXJSConvert respondsToSelector:selector]) { + switch (objcType[0]) { + case _C_CHR: GAIAXJS_PRIMITIVE_CASE(char) + case _C_UCHR: GAIAXJS_PRIMITIVE_CASE(unsigned char) + case _C_SHT: GAIAXJS_PRIMITIVE_CASE(short) + case _C_USHT: GAIAXJS_PRIMITIVE_CASE(unsigned short) + case _C_INT: GAIAXJS_PRIMITIVE_CASE(int) + case _C_UINT: GAIAXJS_PRIMITIVE_CASE(unsigned int) + case _C_LNG: GAIAXJS_PRIMITIVE_CASE(long) + case _C_ULNG: GAIAXJS_PRIMITIVE_CASE(unsigned long) + case _C_LNG_LNG: GAIAXJS_PRIMITIVE_CASE(long long) + case _C_ULNG_LNG: GAIAXJS_PRIMITIVE_CASE(unsigned long long) + case _C_FLT: GAIAXJS_PRIMITIVE_CASE(float) + case _C_DBL: GAIAXJS_PRIMITIVE_CASE(double) + case _C_BOOL: GAIAXJS_PRIMITIVE_CASE(BOOL) + case _C_SEL: GAIAXJS_PRIMITIVE_CASE(SEL) + case _C_CHARPTR: GAIAXJS_PRIMITIVE_CASE(const char *) + case _C_PTR: GAIAXJS_PRIMITIVE_CASE(void *) + case _C_ID: { + isNullableType = YES; + id (*convert)(id, SEL, id) = (__typeof__(convert)) objc_msgSend; + GAIAXJS_RETAINED_ARG_BLOCK(id value = convert([GaiaXJSConvert class], selector, json);); + break; + } + } + } else if ([typeName isEqualToString:@"GaiaXJSPromiseResolveBlock"] || [typeName isEqualToString:@"GaiaXPromiseResolveBlock"]) { + GAIAXJS_BLOCK_CASE((id result), { + resolve(result); + }); + } else if ([typeName isEqualToString:@"GaiaXJSPromiseRejectBlock"] || [typeName isEqualToString:@"GaiaXPromiseRejectBlock"]) { + GAIAXJS_BLOCK_CASE((NSString * code, NSString * message), { + reject(code, message); + }); + } + } + + NSUInteger index = 0; + for (id json in args) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, GAIAXJSNilIfNull(json))) { + reject(@"-1", @"参数错误"); + return; + } + index++; + } + + for (; index < [argumentBlocks count]; index++) { + GAIAXJSArgumentBlock block = argumentBlocks[index]; + if (!block(index, NULL)) { + reject(@"-1", @"参数错误"); + return; + } + } + + + [invocation invoke]; + + [self.retainedObjects removeAllObjects]; +} + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.h b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.h new file mode 100644 index 000000000..5964787a8 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import +#import "GaiaXJSMethodInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSModuleInfo : NSObject + +@property(nonatomic, strong) NSString *moduleName; +@property(nonatomic, strong) NSMapTable *methodsMap; +@property(nonatomic, strong) NSMapTable *idsMap; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.m b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.m new file mode 100644 index 000000000..7535e8ddc --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.m @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import "GaiaXJSModuleInfo.h" + +@implementation GaiaXJSModuleInfo + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.h b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.h new file mode 100644 index 000000000..87f20aad5 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +#import +#import "GaiaXJSModuleInfo.h" +#import "GaiaXJSMethodInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSModuleManager : NSObject + ++ (instancetype)defaultManager; ++ (instancetype)debuggerManager; + +@property(nonatomic, strong) NSMapTable *modulesMap; +@property(nonatomic, strong) NSMapTable *idsMap; +@property(nonatomic, strong) NSMutableString *injectConfigs; +@property(nonatomic, strong) NSMutableString *rdInjectConfigs; + +/** + 同步方法 + */ +- (id)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args; + +- (id)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args; + +/** + 异步方法,callback + */ +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback; + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback; + +/* + 异步方法,Promise + */ +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject; + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.m b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.m new file mode 100644 index 000000000..655f01659 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.m @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSModuleManager.h" +#import +#import +#import +#import "GaiaXJSHelper.h" +#import "GaiaXJSFactory.h" +#import "GaiaXJSContext.h" +#import "GaiaXJSHandler.h" + +static NSUInteger moduleIndex = 0; + + +@interface GaiaXJSModuleManager () +@property (nonatomic, assign)GaiaXJSEngineType engineType; +@end + + +@implementation GaiaXJSModuleManager + ++ (instancetype)defaultManager { + static dispatch_once_t onceToken; + static GaiaXJSModuleManager *defaultM; + dispatch_once(&onceToken, ^{ + defaultM = [[GaiaXJSModuleManager alloc] init]; + defaultM.engineType = GaiaXJSEngineTypeJSC; + [defaultM initMaps]; + [defaultM registerModules]; + }); + return defaultM; +} + ++ (instancetype)debuggerManager { + static dispatch_once_t onceDebuggerToken; + static GaiaXJSModuleManager *debuggerM; + dispatch_once(&onceDebuggerToken, ^{ + debuggerM = [[GaiaXJSModuleManager alloc] init]; + debuggerM.engineType = GaiaXJSEngineTypeDebugger; + [debuggerM initMaps]; + [debuggerM registerModulesWithEngineType:GaiaXJSEngineTypeDebugger]; + }); + return debuggerM; +} + +- (void)initMaps { + self.modulesMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + self.idsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + self.injectConfigs = [NSMutableString string]; + self.rdInjectConfigs = [NSMutableString string]; +} + +- (void)registerModules { + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartLoadNativeModules extendInfo:@{@"timestamp": @(startTime)}]; + [self registerModulesWithEngineType:GaiaXJSEngineTypeJSC]; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndLoadNativeModules extendInfo:@{@"timestamp": @(endTime), @"cost": @(endTime - startTime)}]; +} + +- (void)registerModulesWithEngineType:(GaiaXJSEngineType)engineType { + static NSString *configuration = @""; + Dl_info info; + dladdr((__bridge const void *) (configuration), &info); +#ifndef __LP64__ + const struct mach_header *mhp = (struct mach_header*)info.dli_fbase; + unsigned long size = 0; + uint32_t *data = (uint32_t*)getsectiondata(mhp, "__DATA", "__gaiaxjs", &size); +#else + const struct mach_header_64 *mhp = (struct mach_header_64 *) info.dli_fbase; + unsigned long size = 0; + uint64_t *data = (uint64_t *) getsectiondata(mhp, "__DATA", "__gaiaxjs", &size); +#endif + NSUInteger counter = size / sizeof(void *); + for (NSUInteger idx = 0; idx < counter; ++idx) { + char *string = (char *) data[idx]; + NSString *str = [NSString stringWithFormat:@"%s", string]; + [self buildMapsWithJSName:str index:moduleIndex++ engineType:engineType]; + } +} + +- (void)buildMapsWithJSName:(NSString *)jsName index:(NSUInteger)index engineType:(GaiaXJSEngineType)engineType { + BOOL isDebugging = engineType == GaiaXJSEngineTypeDebugger; + NSString *className = [NSString stringWithFormat:@"GaiaXJS%@Module", jsName]; + Class cls = NSClassFromString(className); + if (cls == nil) { + className = [NSString stringWithFormat:@"GaiaX%@Module", jsName]; + cls = NSClassFromString(className); + } + if (cls != nil) { + GaiaXJSModuleInfo *moduleInfo = [[GaiaXJSModuleInfo alloc] init]; + moduleInfo.moduleName = className; + [self.modulesMap setObject:moduleInfo forKey:@(index)]; + [self.idsMap setObject:@(index) forKey:moduleInfo.moduleName]; + [self.injectConfigs appendFormat:@"var %@ = /** @class */ (function (_super) {\ + __extends(%@, _super);\ + function %@() {\ + return _super.call(this) || this;\ + }\ + return %@;\ + }(Bridge));", className, className, className, className]; + if (isDebugging) { + [self.rdInjectConfigs appendFormat:@"class %@ extends Bridge {}; ", className]; + } + if (![jsName isEqualToString:@"BuiltIn"]) { + [self.injectConfigs appendFormat:@"__globalThis.%@ = new %@(); ", jsName, className]; + if (isDebugging) { + [self.rdInjectConfigs appendFormat:@"__globalThis.%@ = new %@(); ", jsName, className]; + } + } else { + [self.injectConfigs appendFormat:@"__globalThis.gaiax = new %@(); ", className]; + if (isDebugging) { + [self.rdInjectConfigs appendFormat:@"__globalThis.gaiax = new %@(); ", className]; + } + } + unsigned int methodCount; + Method *methods = class_copyMethodList(object_getClass(cls), &methodCount); + moduleInfo.methodsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + moduleInfo.idsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + for (NSUInteger i = 0; i < methodCount; i++) { + Method method = methods[i]; + SEL selector = method_getName(method); + NSString *selectorString = NSStringFromSelector(selector); + if ([selectorString hasPrefix:@"__gaiaxjs_export__"]) { + IMP imp = method_getImplementation(method); + GaiaXJSExportedMethod *exportedMethod = ((GaiaXJSExportedMethod *(*)(id, SEL)) imp)(cls, selector); + GaiaXJSMethodInfo *methodInfo = [[GaiaXJSMethodInfo alloc] initWithExportedMethod:exportedMethod + moduleInfo:moduleInfo]; + [moduleInfo.methodsMap setObject:methodInfo forKey:@(i)]; + [moduleInfo.idsMap setObject:@(i) forKey:methodInfo.methodName]; + [self.injectConfigs appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSMethodString:methodInfo moduleIndex:index methodIndex:i]]; + if (isDebugging) { + [self.rdInjectConfigs appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSMethodString:methodInfo moduleIndex:index methodIndex:i]]; + } + } + } + free(methods); + } +} + +- (GaiaXJSMethodInfo *)getMethodInfoByModuleId:(NSUInteger)moduleId methodId:(NSUInteger)methodId { + GaiaXJSModuleInfo *moduleInfo = [self.modulesMap objectForKey:@(moduleId)]; + if (moduleInfo == nil) { + return nil; + } + GaiaXJSMethodInfo *methodInfo = [moduleInfo.methodsMap objectForKey:@(methodId)]; + if (methodInfo == nil) { + return nil; + } + return methodInfo; +} + +- (id)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args { + GaiaXJSMethodInfo *methodInfo = [self getMethodInfoByModuleId:moduleId methodId:methodId]; + if (methodInfo != nil) { + if (timestamp > 0) { + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeSyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeSync) + }]; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokeSyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeSync) + }]; + } + NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeSyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeSync) + }]; + id result = [methodInfo invokeWithArguments:args]; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeSyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(endTime), + @"cost": @(endTime - timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeSync) + }]; + + return result; + } + return nil; +} + + +- (id)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args { + NSTimeInterval startTime = 0; + return [self invokeMethodWithContextId:contextId + moduleId:moduleId + methodId:methodId + timestamp:startTime + args:args]; +} + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback { + GaiaXJSMethodInfo *methodInfo = [self getMethodInfoByModuleId:moduleId methodId:methodId]; + if (methodInfo != nil) { + if (timestamp > 0) { + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync)}]; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync) + }]; + } + + const char *currentQueue = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + + __block NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync)}]; + [methodInfo invokeWithArguments:args callback:^(id result) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync) + }]; + const char *nextQueue = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync)}]; + if (strcmp(currentQueue, nextQueue) != 0) { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_async(context.bridge.gaiaxJSQueue, ^{ + if (callback != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync) + }]; + callback(result); + } + }); + } + } else { + if (callback != nil) { + callback(result); + } + } + } else { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0 * NSEC_PER_SEC)), context.bridge.gaiaxJSQueue, ^{ + if (callback != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokeAsyncMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypeAsync)}]; + callback(result); + } + }); + } + } else { + if (callback != nil) { + callback(result); + } + } + } + }]; + } else { + if (callback != nil) { + callback(nil); + } + } +} + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args + callback:(GaiaXJSCallbackBlock)callback { + NSTimeInterval startTime = 0; + [self invokeMethodWithContextId:contextId + moduleId:moduleId + methodId:methodId + timestamp:startTime + args:args + callback:callback]; +} + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + timestamp:(NSTimeInterval)timestamp + args:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject { + GaiaXJSMethodInfo *methodInfo = [self getMethodInfoByModuleId:moduleId methodId:methodId]; + if (methodInfo != nil) { + if (timestamp > 0) { + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseJSToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - timestamp), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise) + }]; + } + + const char *currentQueue = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + __block NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + [methodInfo invokeWithArguments:args + resolver:^(id result) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise) + }]; + const char *nextQueue = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + startTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseWillStartInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseContextToReturn), + @"timestamp": @(startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + if (strcmp(currentQueue, nextQueue) != 0) { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_async(context.bridge.gaiaxJSQueue, ^{ + if (resolve != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise) + }]; + resolve(result); + } + }); + } + } else { + if (resolve != nil) { + resolve(result); + } + } + } else { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0 * NSEC_PER_SEC)), context.bridge.gaiaxJSQueue, ^{ + if (resolve != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + resolve(result); + } + }); + } + } else { + if (resolve != nil) { + resolve(result); + } + } + } + } rejecter:^(NSString *code, NSString *message) { + const char *nextQueue = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + if (strcmp(currentQueue, nextQueue) != 0) { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_async(context.bridge.gaiaxJSQueue, ^{ + if (reject != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + reject(code, message); + } + }); + } + } else { + if (reject != nil) { + reject(code, message); + } + } + } else { + if (contextId > 0) { + GaiaXJSContext *context = [GaiaXJSFactory getContextByContextId:contextId]; + if (context != nil) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (0 * NSEC_PER_SEC)), context.bridge.gaiaxJSQueue, ^{ + if (reject != nil) { + NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970] * 1000; + [GaiaXJSHandler dispatchExecPhase:GaiaXJSExecPhaseDidEndInvokePromiseMethod extendInfo:@{@"subPhase": @(GaiaXJSInvokeMethodSubPhaseReturnToContext), + @"timestamp": @(endTime), + @"cost": @(endTime - startTime), + @"moduleName": GaiaXJSSafeString(methodInfo.moduleInfo.moduleName), + @"methodName": GaiaXJSSafeString(methodInfo.methodName), + @"apiType": @(GaiaXJSMethodTypePromise)}]; + reject(code, message); + } + }); + } + } else { + if (reject != nil) { + reject(code, message); + } + } + } + }]; + } else { + reject(@"-1", @"客户端没有对应的实现"); + } +} + +- (void)invokeMethodWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject { + NSTimeInterval startTime = 0; + [self invokeMethodWithContextId:contextId + moduleId:moduleId + methodId:methodId + timestamp:startTime + args:args + resolver:resolve rejecter:reject]; +} + + +@end diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.h b/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.h new file mode 100644 index 000000000..1c40392dc --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXJSModuleInfo; + +@interface GaiaXJSUIManager : NSObject + ++ (instancetype)defaultManager; + ++ (instancetype)debuggerManager; + +@property(nonatomic, strong) NSMapTable *modulesMap; +@property(nonatomic, strong) NSMapTable *idsMap; +@property(nonatomic, strong) NSMutableString *injectProps; +@property(nonatomic, strong) NSMutableString *rdInjectProps; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.m b/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.m new file mode 100644 index 000000000..935ae1648 --- /dev/null +++ b/GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.m @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2022, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#import "GaiaXJSUIManager.h" +#import +#import +#import +#import "GaiaXJSModuleInfo.h" +#import "GaiaXJSHelper.h" +#import +#import "GaiaXJSConvert.h" + +@implementation GaiaXJSUIManager + ++ (instancetype)defaultManager { + static dispatch_once_t onceToken; + static GaiaXJSUIManager *defaultM; + dispatch_once(&onceToken, ^{ + defaultM = [[GaiaXJSUIManager alloc] init]; + [defaultM initMaps]; + [defaultM registerModules]; + }); + return defaultM; +} + ++ (instancetype)debuggerManager { + static dispatch_once_t onceDebuggerToken; + static GaiaXJSUIManager *debuggerM; + dispatch_once(&onceDebuggerToken, ^{ + debuggerM = [[GaiaXJSUIManager alloc] init]; + [debuggerM initMaps]; + [debuggerM registerModulesWithEngineType:GaiaXJSEngineTypeDebugger]; + }); + return debuggerM; +} + + +- (void)initMaps { + self.injectProps = [NSMutableString string]; + self.rdInjectProps = [NSMutableString string]; + self.modulesMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + self.idsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; +} + +- (void)registerModulesWithEngineType:(GaiaXJSEngineType)engineType { + BOOL isDebugging = engineType == GaiaXJSEngineTypeDebugger; + static NSString *configuration = @""; + Dl_info info; + dladdr((__bridge const void *) (configuration), &info); +#ifndef __LP64__ + const struct mach_header *mhp = (struct mach_header*)info.dli_fbase; + unsigned long size = 0; + uint32_t *data = (uint32_t*)getsectiondata(mhp, "__DATA", "__gaiaxjs", &size); +#else + const struct mach_header_64 *mhp = (struct mach_header_64 *) info.dli_fbase; + unsigned long size = 0; + uint64_t *data = (uint64_t *) getsectiondata(mhp, "__DATA", "__gaiaxjs", &size); +#endif + NSUInteger counter = size / sizeof(void *); + for (NSUInteger idx = 0; idx < counter; ++idx) { + char *string = (char *) data[idx]; + NSString *str = [NSString stringWithFormat:@"GaiaXJSUI%sModule", string]; + Class cls = NSClassFromString(str); + if (cls != nil) { + GaiaXJSModuleInfo *moduleInfo = [[GaiaXJSModuleInfo alloc] init]; + moduleInfo.moduleName = str; + [self.modulesMap setObject:moduleInfo forKey:@(idx)]; + [self.idsMap setObject:@(idx) forKey:moduleInfo.moduleName]; + NSString *jsName = [GaiaXJSHelper removeGaiaXPrefix:str]; + if (![str isEqualToString:@"GaiaXJSUIViewModule"]) { + [self.injectProps appendFormat:@"var %@Props = /** @class */ (function (_super) {\ + __extends(%@Props, _super);\ + function %@Props() {\ + return _super.call(this) || this;\ + }\ + return %@Props;\ + }(Props));", jsName, jsName, jsName, jsName]; + [self.injectProps appendFormat:@"var %@Style = /** @class */ (function (_super) {\ + __extends(%@Style, _super);\ + function %@Style() {\ + return _super.call(this) || this;\ + }\ + return %@Style;\ + }(Style));", jsName, jsName, jsName, jsName]; + if (isDebugging) { + [self.rdInjectProps appendFormat:@"class %@Props extends Props {}; ", jsName]; + [self.rdInjectProps appendFormat:@"class %@Style extends Style {}; ", jsName]; + } + } else { + [self.injectProps appendFormat:@"var Style = /** @class */ (function () {\ + function Style(data) {\ + this.__data__ = __assign({}, data);\ + }\ + Object.defineProperty(Style.prototype, \"targetData\", {\ + get: function () {\ + return this.__data__;\ + },\ + enumerable: true,\ + configurable: true\ + });\ + return Style;\ + }());\ + var Props = /** @class */ (function () {\ + function Props() {\ + }\ + return Props;\ + }());"]; + if (isDebugging) { + [self.rdInjectProps appendFormat:@"class Props {}; "]; + [self.rdInjectProps appendFormat:@"class Style { targetData:any }; "]; + } + } + unsigned int methodCount; + Method *methods = class_copyMethodList(object_getClass(cls), &methodCount); + moduleInfo.methodsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + moduleInfo.idsMap = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:20]; + for (NSUInteger i = 0; i < methodCount; i++) { + Method method = methods[i]; + SEL selector = method_getName(method); + NSString *selectorString = NSStringFromSelector(selector); + if ([selectorString hasPrefix:@"gaiaxjs_propConfig_"]) { + [self createPropBlock:[selectorString substringFromIndex:@"gaiaxjs_propConfig_".length] class:cls selector:selector]; + [self.injectProps appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSPropsStringWithClass:[jsName isEqualToString:@"View"] ? @"" : jsName key:[selectorString substringFromIndex:@"gaiaxjs_propConfig_".length]]]; + if (isDebugging) { + [self.rdInjectProps appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSPropsStringWithClass:[jsName isEqualToString:@"View"] ? @"" : jsName key:[selectorString substringFromIndex:@"gaiaxjs_propConfig_".length]]]; + } + } else if ([selectorString hasPrefix:@"gaiaxjs_styleConfig_"]) { + [self createStyleBlock:[selectorString substringFromIndex:@"gaiaxjs_styleConfig_".length] class:cls selector:selector]; + [self.injectProps appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSStyleStringWithClass:[jsName isEqualToString:@"View"] ? @"" : jsName key:[selectorString substringFromIndex:@"gaiaxjs_styleConfig_".length]]]; + if (isDebugging) { + [self.rdInjectProps appendFormat:@"%@\r\n", [GaiaXJSHelper generateJSStyleStringWithClass:[jsName isEqualToString:@"View"] ? @"" : jsName key:[selectorString substringFromIndex:@"gaiaxjs_styleConfig_".length]]]; + } + } + } + free(methods); + } + } +} + +- (void)registerModules { + [self registerModulesWithEngineType:GaiaXJSEngineTypeJSC]; +} + +- (GaiaXJSPropBlock)createPropBlock:(NSString *)name class:(Class)class selector:(SEL)selector { + return nil; +} + +- (GaiaXJSStyleBlock)createStyleBlock:(NSString *)name class:(Class)class selector:(SEL)selector { + SEL type = NULL; + NSString *keyPath = nil; + NSArray *typeAndKeyPath = ((NSArray *(*)(id, SEL)) objc_msgSend)(class, selector); + type = selectorForType(typeAndKeyPath[0]); + keyPath = typeAndKeyPath.count > 1 ? typeAndKeyPath[1] : nil; + NSString *key = name; + NSArray *parts = [keyPath componentsSeparatedByString:@"."]; + if (parts) { + key = parts.lastObject; + parts = [parts subarrayWithRange:(NSRange) {0, parts.count - 1}]; + } + + // Get property getter + SEL getter = NSSelectorFromString(key); + + // Get property setter + SEL setter = NSSelectorFromString( + [NSString stringWithFormat:@"set%@%@:", [key substringToIndex:1].uppercaseString, [key substringFromIndex:1]]); + + // Build setter block + void (^setterBlock)(id target, id json) = nil; + + NSMethodSignature *typeSignature = [[GaiaXJSConvert class] methodSignatureForSelector:type]; + if (!typeSignature) { + return ^(__unused id view, __unused id json) { + }; + } + switch (typeSignature.methodReturnType[0]) { +#define GAIAX_CASE(_value, _type) \ +case _value: { \ +__block BOOL setDefaultValue = NO; \ +__block _type defaultValue; \ +_type (*convert)(id, SEL, id) = (typeof(convert))objc_msgSend; \ +_type (*get)(id, SEL) = (typeof(get))objc_msgSend; \ +void (*set)(id, SEL, _type) = (typeof(set))objc_msgSend; \ +setterBlock = ^(id target, id json) { \ +if (json) { \ +if (!setDefaultValue && target) { \ +if ([target respondsToSelector:getter]) { \ +defaultValue = get(target, getter); \ +} \ +setDefaultValue = YES; \ +} \ +set(target, setter, convert([GaiaXJSConvert class], type, json)); \ +} else if (setDefaultValue) { \ +set(target, setter, defaultValue); \ +} \ +}; \ +break; \ +} + GAIAX_CASE(_C_SEL, SEL) + GAIAX_CASE(_C_CHARPTR, const char *) + GAIAX_CASE(_C_CHR, char) + GAIAX_CASE(_C_UCHR, unsigned char) + GAIAX_CASE(_C_SHT, short) + GAIAX_CASE(_C_USHT, unsigned short) + GAIAX_CASE(_C_INT, int) + GAIAX_CASE(_C_UINT, unsigned int) + GAIAX_CASE(_C_LNG, long) + GAIAX_CASE(_C_ULNG, unsigned long) + GAIAX_CASE(_C_LNG_LNG, long long) + GAIAX_CASE(_C_ULNG_LNG, unsigned long long) + GAIAX_CASE(_C_FLT, float) + GAIAX_CASE(_C_DBL, double) + GAIAX_CASE(_C_BOOL, BOOL) + GAIAX_CASE(_C_PTR, void *) + GAIAX_CASE(_C_ID, id) + + case _C_STRUCT_B: + default: { + setterBlock = createNSInvocationSetter(typeSignature, type, getter, setter); + break; + } + } + return ^(__unused id view, __unused id json) { + // Follow keypath + id target = view; + for (NSString *part in parts) { + target = [target valueForKey:part]; + } + + // Set property with json + setterBlock(target, GaiaXJSNilIfNull(json)); + }; +} + +static GaiaXJSPropBlock createNSInvocationSetter(NSMethodSignature *typeSignature, SEL type, SEL getter, SEL setter) { + return nil; +} + +static SEL selectorForType(NSString *type) { + const char *input = type.UTF8String; + return NSSelectorFromString([GaiaXJSParseType(&input) stringByAppendingString:@":"]); +} + + +- (void)setStyleWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args { + +} + +- (void)setPropWithContextId:(NSInteger)contextId + moduleId:(NSInteger)moduleId + methodId:(NSInteger)methodId + args:(NSArray *)args { + +} + +@end diff --git a/GaiaXJSiOS/Podfile b/GaiaXJSiOS/Podfile new file mode 100644 index 000000000..f88e6c089 --- /dev/null +++ b/GaiaXJSiOS/Podfile @@ -0,0 +1,10 @@ +source 'https://github.com/CocoaPods/Specs.git' +source 'https://github.com/Artsy/Specs.git' + +target 'GaiaXJS' do + platform :ios, '9.0' + # Uncomment the next line if you're using Swift or would like to use dynamic frameworks + # use_frameworks! + + pod 'GaiaXSocket', :path => '../GaiaXSocketiOS' +end diff --git a/GaiaXJSiOS/README.md b/GaiaXJSiOS/README.md new file mode 100644 index 000000000..ee47d045a --- /dev/null +++ b/GaiaXJSiOS/README.md @@ -0,0 +1 @@ +[文档地址](https://www.yuque.com/youku-gaia) diff --git a/GaiaXSocketiOS/.gitignore b/GaiaXSocketiOS/.gitignore new file mode 100644 index 000000000..d4b2b8881 --- /dev/null +++ b/GaiaXSocketiOS/.gitignore @@ -0,0 +1,5 @@ +Pods +Podfile.lock +.DS_Store + +xcuserdata/ diff --git a/GaiaXSocketiOS/GaiaXSocket.podspec b/GaiaXSocketiOS/GaiaXSocket.podspec new file mode 100644 index 000000000..e1f497fae --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.podspec @@ -0,0 +1,25 @@ +Pod::Spec.new do |s| + + s.name = "GaiaXSocket" + s.version = "0.1.0" + s.summary = "GaiaXSocket" + s.description = "GaiaXSocket" + + + s.homepage = "https://github.com/alibaba/GaiaX" + + + s.author = { "jingcheng1988" => "zhang_jing_cheng@163.com" } + s.platform = :ios, "9.0" + s.source = { :git => "https://github.com/alibaba/GaiaX.git", :tag => "#{s.version}" } + + + s.source_files = 'GaiaXSocket/**/*.{h,m}' + s.xcconfig = { "ENABLE_BITCODE" => "NO" } + s.requires_arc = true + + s.dependency 'SocketRocket', '~> 0.5.1' + + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + +end diff --git a/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.pbxproj b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d4772cd5f --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.pbxproj @@ -0,0 +1,436 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 42406EF97760B35151C527EA /* libPods-GaiaXSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9E9353E89C5D6C40CCDC03 /* libPods-GaiaXSocket.a */; }; + 8D23C0102856E3B800EC75F6 /* GaiaXSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C00F2856E3B800EC75F6 /* GaiaXSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8D23C0182856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C0162856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.h */; }; + 8D23C0192856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D23C0172856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.m */; }; + 8D23C0202856E68200EC75F6 /* GaiaXSocketUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C01E2856E68200EC75F6 /* GaiaXSocketUtils.h */; }; + 8D23C0212856E68200EC75F6 /* GaiaXSocketUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D23C01F2856E68200EC75F6 /* GaiaXSocketUtils.m */; }; + 8D23C0242856EAA200EC75F6 /* GaiaXSocketClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C0222856EAA200EC75F6 /* GaiaXSocketClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8D23C0252856EAA200EC75F6 /* GaiaXSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D23C0232856EAA200EC75F6 /* GaiaXSocketClient.m */; }; + 8D23C0282856EAB700EC75F6 /* GaiaXSocketManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C0262856EAB700EC75F6 /* GaiaXSocketManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8D23C0292856EAB700EC75F6 /* GaiaXSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D23C0272856EAB700EC75F6 /* GaiaXSocketManager.m */; }; + 8D23C02F28570EC000EC75F6 /* GaiaXSocketProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 8D23C02E28570EC000EC75F6 /* GaiaXSocketProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDE9A30B29029C0100D5120C /* GaiaXSocketModel.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE9A30929029C0100D5120C /* GaiaXSocketModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDE9A30C29029C0100D5120C /* GaiaXSocketModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BDE9A30A29029C0100D5120C /* GaiaXSocketModel.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 5C9E9353E89C5D6C40CCDC03 /* libPods-GaiaXSocket.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-GaiaXSocket.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D23C00C2856E3B800EC75F6 /* GaiaXSocket.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GaiaXSocket.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D23C00F2856E3B800EC75F6 /* GaiaXSocket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocket.h; sourceTree = ""; }; + 8D23C0162856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketJsonRpcDefine.h; sourceTree = ""; }; + 8D23C0172856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketJsonRpcDefine.m; sourceTree = ""; }; + 8D23C01E2856E68200EC75F6 /* GaiaXSocketUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketUtils.h; sourceTree = ""; }; + 8D23C01F2856E68200EC75F6 /* GaiaXSocketUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketUtils.m; sourceTree = ""; }; + 8D23C0222856EAA200EC75F6 /* GaiaXSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketClient.h; sourceTree = ""; }; + 8D23C0232856EAA200EC75F6 /* GaiaXSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketClient.m; sourceTree = ""; }; + 8D23C0262856EAB700EC75F6 /* GaiaXSocketManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketManager.h; sourceTree = ""; }; + 8D23C0272856EAB700EC75F6 /* GaiaXSocketManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketManager.m; sourceTree = ""; }; + 8D23C02E28570EC000EC75F6 /* GaiaXSocketProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketProtocol.h; sourceTree = ""; }; + 8D23C0332857532F00EC75F6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + A1C9BBCC75A57C0EC5E290E9 /* Pods-GaiaXSocket.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXSocket.debug.xcconfig"; path = "Target Support Files/Pods-GaiaXSocket/Pods-GaiaXSocket.debug.xcconfig"; sourceTree = ""; }; + BDE9A30929029C0100D5120C /* GaiaXSocketModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketModel.h; sourceTree = ""; }; + BDE9A30A29029C0100D5120C /* GaiaXSocketModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketModel.m; sourceTree = ""; }; + FD625657B8857C352384BEA1 /* Pods-GaiaXSocket.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXSocket.release.xcconfig"; path = "Target Support Files/Pods-GaiaXSocket/Pods-GaiaXSocket.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D23C0092856E3B800EC75F6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 42406EF97760B35151C527EA /* libPods-GaiaXSocket.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 12EB8A29E4EB924D84431D77 /* Pods */ = { + isa = PBXGroup; + children = ( + A1C9BBCC75A57C0EC5E290E9 /* Pods-GaiaXSocket.debug.xcconfig */, + FD625657B8857C352384BEA1 /* Pods-GaiaXSocket.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 7F35EDA82FFAC1FAAA9A56BC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5C9E9353E89C5D6C40CCDC03 /* libPods-GaiaXSocket.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 8D23C0022856E3B800EC75F6 = { + isa = PBXGroup; + children = ( + 8D23C00E2856E3B800EC75F6 /* GaiaXSocket */, + 8D23C00D2856E3B800EC75F6 /* Products */, + 12EB8A29E4EB924D84431D77 /* Pods */, + 7F35EDA82FFAC1FAAA9A56BC /* Frameworks */, + ); + sourceTree = ""; + }; + 8D23C00D2856E3B800EC75F6 /* Products */ = { + isa = PBXGroup; + children = ( + 8D23C00C2856E3B800EC75F6 /* GaiaXSocket.framework */, + ); + name = Products; + sourceTree = ""; + }; + 8D23C00E2856E3B800EC75F6 /* GaiaXSocket */ = { + isa = PBXGroup; + children = ( + 8D23C0332857532F00EC75F6 /* Info.plist */, + 8D23C00F2856E3B800EC75F6 /* GaiaXSocket.h */, + 8D23C02E28570EC000EC75F6 /* GaiaXSocketProtocol.h */, + 8D23C0262856EAB700EC75F6 /* GaiaXSocketManager.h */, + 8D23C0272856EAB700EC75F6 /* GaiaXSocketManager.m */, + 8D23C01E2856E68200EC75F6 /* GaiaXSocketUtils.h */, + 8D23C01F2856E68200EC75F6 /* GaiaXSocketUtils.m */, + 8D23C0222856EAA200EC75F6 /* GaiaXSocketClient.h */, + 8D23C0232856EAA200EC75F6 /* GaiaXSocketClient.m */, + 8D23C0162856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.h */, + 8D23C0172856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.m */, + BDE9A30929029C0100D5120C /* GaiaXSocketModel.h */, + BDE9A30A29029C0100D5120C /* GaiaXSocketModel.m */, + ); + path = GaiaXSocket; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D23C0072856E3B800EC75F6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D23C0282856EAB700EC75F6 /* GaiaXSocketManager.h in Headers */, + 8D23C0242856EAA200EC75F6 /* GaiaXSocketClient.h in Headers */, + 8D23C02F28570EC000EC75F6 /* GaiaXSocketProtocol.h in Headers */, + BDE9A30B29029C0100D5120C /* GaiaXSocketModel.h in Headers */, + 8D23C0202856E68200EC75F6 /* GaiaXSocketUtils.h in Headers */, + 8D23C0102856E3B800EC75F6 /* GaiaXSocket.h in Headers */, + 8D23C0182856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8D23C00B2856E3B800EC75F6 /* GaiaXSocket */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8D23C0132856E3B800EC75F6 /* Build configuration list for PBXNativeTarget "GaiaXSocket" */; + buildPhases = ( + 3C4B8E2F23E77ABA6D4FC928 /* [CP] Check Pods Manifest.lock */, + 8D23C0072856E3B800EC75F6 /* Headers */, + 8D23C0082856E3B800EC75F6 /* Sources */, + 8D23C0092856E3B800EC75F6 /* Frameworks */, + 8D23C00A2856E3B800EC75F6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = GaiaXSocket; + productName = GaiaXSocket; + productReference = 8D23C00C2856E3B800EC75F6 /* GaiaXSocket.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8D23C0032856E3B800EC75F6 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1330; + TargetAttributes = { + 8D23C00B2856E3B800EC75F6 = { + CreatedOnToolsVersion = 13.3.1; + }; + }; + }; + buildConfigurationList = 8D23C0062856E3B800EC75F6 /* Build configuration list for PBXProject "GaiaXSocket" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8D23C0022856E3B800EC75F6; + productRefGroup = 8D23C00D2856E3B800EC75F6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D23C00B2856E3B800EC75F6 /* GaiaXSocket */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D23C00A2856E3B800EC75F6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3C4B8E2F23E77ABA6D4FC928 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-GaiaXSocket-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D23C0082856E3B800EC75F6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D23C0292856EAB700EC75F6 /* GaiaXSocketManager.m in Sources */, + 8D23C0252856EAA200EC75F6 /* GaiaXSocketClient.m in Sources */, + BDE9A30C29029C0100D5120C /* GaiaXSocketModel.m in Sources */, + 8D23C0192856E42D00EC75F6 /* GaiaXSocketJsonRpcDefine.m in Sources */, + 8D23C0212856E68200EC75F6 /* GaiaXSocketUtils.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8D23C0112856E3B800EC75F6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 8D23C0122856E3B800EC75F6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8D23C0142856E3B800EC75F6 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A1C9BBCC75A57C0EC5E290E9 /* Pods-GaiaXSocket.debug.xcconfig */; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = GaiaXSocket/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alibaba.GaiaXSocket; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8D23C0152856E3B800EC75F6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FD625657B8857C352384BEA1 /* Pods-GaiaXSocket.release.xcconfig */; + buildSettings = { + BUILD_LIBRARY_FOR_DISTRIBUTION = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = z; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = GaiaXSocket/Info.plist; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.alibaba.GaiaXSocket; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8D23C0062856E3B800EC75F6 /* Build configuration list for PBXProject "GaiaXSocket" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8D23C0112856E3B800EC75F6 /* Debug */, + 8D23C0122856E3B800EC75F6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8D23C0132856E3B800EC75F6 /* Build configuration list for PBXNativeTarget "GaiaXSocket" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8D23C0142856E3B800EC75F6 /* Debug */, + 8D23C0152856E3B800EC75F6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8D23C0032856E3B800EC75F6 /* Project object */; +} diff --git a/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/GaiaXSocketiOS/GaiaXSocket.xcodeproj/xcshareddata/xcschemes/GaiaXSocket.xcscheme b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/xcshareddata/xcschemes/GaiaXSocket.xcscheme new file mode 100644 index 000000000..e52e525a8 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.xcodeproj/xcshareddata/xcschemes/GaiaXSocket.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/GaiaXSocketiOS/GaiaXSocket.xcworkspace/contents.xcworkspacedata b/GaiaXSocketiOS/GaiaXSocket.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..650ff6e30 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocket.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocket.h new file mode 100644 index 000000000..56ff5b56b --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocket.h @@ -0,0 +1,29 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +//! Project version number for GaiaXSocket. +FOUNDATION_EXPORT double GaiaXSocketVersionNumber; + +//! Project version string for GaiaXSocket. +FOUNDATION_EXPORT const unsigned char GaiaXSocketVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + +#import +#import +#import +#import diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.h new file mode 100644 index 000000000..bbb5bc3ea --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.h @@ -0,0 +1,66 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXSocketModel; +typedef void(^GaiaXSocketCallback)(GaiaXSocketModel *model); + +typedef NS_ENUM(NSUInteger, GaiaXSocketStatus) { + GaiaXSocketStatusDefault = 0, + GaiaXSocketStatusConnect, + GaiaXSocketStatusDisConnect, +}; + + +@protocol GaiaXSocketClientDelegate; + +@interface GaiaXSocketClient : NSObject + +@property (nonatomic, strong) NSString *url; +@property(nonatomic, assign, readonly) BOOL isConnect; +@property(nonatomic, assign) GaiaXSocketStatus socketStatus; +@property(nonatomic, weak) id delegate; + +- (instancetype)initWithUrl:(NSString *)url delegate:(id )delegate; +@property (nonatomic, assign) BOOL closeManually; + +- (void)connectServer; +- (void)reConnectServer; +- (void)disConnectServer; + +- (void)sendRequest:(GaiaXSocketModel *)request callback:(GaiaXSocketCallback)callback; + +- (void)sendResponse:(GaiaXSocketModel *)model; + +- (void)sendeNotification:(GaiaXSocketModel *)model; + +@end + + +@protocol GaiaXSocketClientDelegate + +- (void)socketClientDidConnect:(GaiaXSocketClient *)client; + +- (void)socketClientDidDisConnect:(GaiaXSocketClient *)client; + +- (void)socketClient:(GaiaXSocketClient *)client didFailWithError:(NSError *)error; + +- (void)socketClient:(GaiaXSocketClient *)client didReceiveMessage:(GaiaXSocketModel *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.m b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.m new file mode 100644 index 000000000..471a8408e --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.m @@ -0,0 +1,281 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXSocketClient.h" +#import "GaiaXSocketProtocol.h" +#import "GaiaXSocketModel.h" +#import "GaiaXSocketUtils.h" +#import "SRWebSocket.h" + +@interface GaiaXSocketClient () + +@property (nonatomic, strong) SRWebSocket *webScoket; + +@property (nonatomic, strong) NSTimer *heartBeatTimer; +@property (nonatomic, strong) NSTimer *networkCheckTimer; + +@property (nonatomic, strong) dispatch_queue_t processingQueue; + +@property (nonatomic, strong) NSTimer *reConnectTimer; + +@property (nonatomic, strong) NSMapTable *requestIdCallbackTable; + +@end + +@implementation GaiaXSocketClient + +- (instancetype)initWithUrl:(NSString *)url delegate:(id )delegate{ + self = [self init]; + if (self) { + _url = url; + _delegate = delegate; + } + return self; +} + +- (instancetype)init{ + self = [super init]; + if (self) { + self.closeManually = NO; + self.requestIdCallbackTable = [NSMapTable strongToStrongObjectsMapTable]; + self.processingQueue = dispatch_queue_create("eu.nubomedia.websocket.processing", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (BOOL)isConnect { + return self.webScoket.readyState == SR_OPEN; +} + + +- (void)connectServer{ + if ([self isConnect]) { + return; + } + + NSURL *url = [NSURL URLWithString:self.url]; + self.webScoket = [[SRWebSocket alloc] initWithURL:url]; + [self.webScoket setDelegateDispatchQueue:self.processingQueue]; + self.webScoket.delegate = self; + [self.webScoket open]; +} + +- (void)reConnectServer{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + if ([self.reConnectTimer isValid]) { + [self.reConnectTimer invalidate]; + self.reConnectTimer = nil; + } + self.reConnectTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(doReConnectServer) userInfo:nil repeats:YES]; + }); +} + +- (void)doReConnectServer { + + if (self.webScoket.readyState == SR_OPEN ) { + if (self.reConnectTimer != nil && [self.reConnectTimer isValid]) { + [self.reConnectTimer invalidate]; + self.reConnectTimer = nil; + } + return; + } + [self disConnectServer:NO]; + + [self connectServer]; + +} + +- (void)disConnectServer: (BOOL)manually{ + self.closeManually = manually; + + if (self.webScoket != nil) { + self.webScoket.delegate = nil; + [self.webScoket close]; + self.webScoket = nil; + } + + [self distroyNetworkCheckTimer]; +} + +- (void)disConnectServer { + [self disConnectServer:YES]; +} + + +#pragma mark - + + + +- (void)setupNetworkCheckTimer{ + if (_networkCheckTimer != nil) { + return; + } + + _networkCheckTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(networkStartCheck) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:_networkCheckTimer forMode:NSRunLoopCommonModes]; + [[NSRunLoop currentRunLoop] run]; +} + +- (void)distroyNetworkCheckTimer{ + if ([_networkCheckTimer isValid]) { + [_networkCheckTimer invalidate]; + _networkCheckTimer = nil; + } +} + +- (void)networkStartCheck{ + if([GaiaXSocketUtils isNetworkReachable]){ + return; + } + + [self disConnectServer:NO]; + + [self reConnectServer]; +} + + +#pragma mark - send + + +- (void)sendResponse:(GaiaXSocketModel *)model { + if (self.webScoket.readyState != SR_OPEN) { + return; + } + [self.webScoket send:[model stringifyModel]]; +} + +- (void)sendeNotification:(GaiaXSocketModel *)model { + if (self.webScoket.readyState != SR_OPEN) { + return; + } + [self.webScoket send:[model stringifyModel]]; +} + +- (void)sendRequest:(GaiaXSocketModel *)request callback:(GaiaXSocketCallback)callback { + if (self.webScoket.readyState != SR_OPEN) { + return; + } + + [_requestIdCallbackTable setObject:callback forKey:request.messageId]; + + [self.webScoket send:[request stringifyModel]]; + +} + + +#pragma mark - SRWebSocketDelegate + + + + +- (void)webSocketDidOpen:(SRWebSocket *)webSocket{ + self.closeManually = NO; + _socketStatus = GaiaXSocketStatusConnect; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_SOCKET_CONNECT_STATE_CONNECTED" object:nil userInfo:nil]; + + if (self.delegate && [self.delegate respondsToSelector:@selector(socketClientDidConnect:)]) { + [self.delegate socketClientDidConnect:self]; + } + }); +} + +- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{ + _socketStatus = GaiaXSocketStatusDisConnect; + + + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.delegate && [self.delegate respondsToSelector:@selector(socketClient:didFailWithError:)]) { + [self.delegate socketClient:self didFailWithError:error]; + } + }); + + if(![GaiaXSocketUtils isNetworkReachable]){ + [self networkStartCheck]; + } else { + [self reConnectServer]; + } + +} + +- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)messageData{ + if (messageData == nil || ![messageData isKindOfClass:[NSString class]]) { + return; + } + + GaiaXSocketModel *model = [[GaiaXSocketModel alloc] initWithMessageString:messageData]; + GaiaXSocketCallback callback = [_requestIdCallbackTable objectForKey:model.messageId]; + if (callback != nil) { + __weak typeof(self) weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + callback(model); + [weakSelf.requestIdCallbackTable removeObjectForKey:model.messageId]; + }); + } else { + if ([model.method isEqualToString:@"close"]) { + _socketStatus = GaiaXSocketStatusDisConnect; + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.delegate && [self.delegate respondsToSelector:@selector(socketClient:didFailWithError:)]) { + [self.delegate socketClient:self didFailWithError:nil]; + } + }); + } else if ([model.method isEqualToString:@"mode/get"]) { + NSString *previewMode = @"none"; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults objectForKey:@"GAIAX_LAST_PREVIEW_MODE"] != nil) { + previewMode = [defaults stringForKey:@"GAIAX_LAST_PREVIEW_MODE"]; + } + NSString *jsMode = @"default"; + if ([defaults objectForKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"] != nil) { + jsMode = [defaults stringForKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"]; + } + GaiaXSocketModel *m = [GaiaXSocketModel responseWithMessageId:[model.messageId integerValue] + result:@{@"preview":previewMode,@"js":jsMode}]; + [self sendResponse:m]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.delegate && [self.delegate respondsToSelector:@selector(socketClient:didReceiveMessage:)]) { + [self.delegate socketClient:self didReceiveMessage:model]; + } + }); + } + } + +} + +- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{ + + dispatch_async(dispatch_get_main_queue(), ^{ + if (self.delegate && [self.delegate respondsToSelector:@selector(socketClientDidDisConnect:)]) { + [self.delegate socketClientDidDisConnect:self]; + } + }); + + if (self.closeManually) { + self.socketStatus = GaiaXSocketStatusDefault; + return; + } + + self.socketStatus = GaiaXSocketStatusDisConnect; + + if (![GaiaXSocketUtils isNetworkReachable]) { + [self networkStartCheck]; + } else { + [self reConnectServer]; + } +} + + +@end diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.h new file mode 100644 index 000000000..f67330591 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.h @@ -0,0 +1,30 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + + +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcIdKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcVersion; + +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcMethodKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcParamsKey; + +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcErrorKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcResultKey; + +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcCodeKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcDataKey; +FOUNDATION_EXTERN NSString* const GaiaXSocketJsonRpcMessageKey; diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.m b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.m new file mode 100644 index 000000000..4f5488f17 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.m @@ -0,0 +1,29 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXSocketJsonRpcDefine.h" + +NSString* const GaiaXSocketJsonRpcKey = @"jsonrpc"; +NSString* const GaiaXSocketJsonRpcVersion = @"2.0"; + +NSString* const GaiaXSocketJsonRpcIdKey = @"id"; +NSString* const GaiaXSocketJsonRpcMethodKey = @"method"; +NSString* const GaiaXSocketJsonRpcParamsKey = @"params"; + +NSString* const GaiaXSocketJsonRpcErrorKey = @"error"; +NSString* const GaiaXSocketJsonRpcResultKey = @"result"; + +NSString* const GaiaXSocketJsonRpcCodeKey = @"code"; +NSString* const GaiaXSocketJsonRpcDataKey = @"data"; +NSString* const GaiaXSocketJsonRpcMessageKey = @"message"; diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.h new file mode 100644 index 000000000..7b960991c --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.h @@ -0,0 +1,46 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "GaiaXSocketClient.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol GaiaXSocketProtocol; + +@interface GaiaXSocketManager : NSObject + +@property (nonatomic, strong) GaiaXSocketClient *socketClient; + + ++ (instancetype)sharedInstance; + + +- (void)connet:(NSString *)url; + +- (void)disconnect; + + +- (void)clearSocketUrl; + + +- (id )listenerForKey:(NSString *)key; + +- (void)registerListener:(id )listener; + +- (void)unRegisterListener:(id )listener; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.m b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.m new file mode 100644 index 000000000..af8a4935f --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.m @@ -0,0 +1,134 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXSocketManager.h" +#import "GaiaXSocketProtocol.h" +#import + +@interface GaiaXSocketManager (){ + Class _openPreviewClazz; +} + +@property (nonatomic, strong) NSMutableDictionary *listenerMap; + +@end + +@implementation GaiaXSocketManager + ++ (instancetype)sharedInstance{ + static GaiaXSocketManager *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[GaiaXSocketManager alloc] init]; + }); + return instance; +} + +- (instancetype)init{ + self = [super init]; + if (self) { + self.listenerMap = [NSMutableDictionary dictionary]; + self.socketClient = [[GaiaXSocketClient alloc] init]; + self.socketClient.delegate = self; + } + return self; +} + + +- (void)connet:(NSString *)url{ + if (self.socketClient.isConnect) { + [self.socketClient disConnectServer]; + } + + self.socketClient.url = url; + [self.socketClient connectServer]; + +} + +- (void)disconnect{ + [self.socketClient disConnectServer]; +} + + +- (id )listenerForKey:(NSString *)key { + if (key.length > 0) { + return self.listenerMap[key]; + } + return nil; +} + +- (void)registerListener:(id )listener { + if (listener && [listener conformsToProtocol:@protocol(GaiaXSocketProtocol)]) { + NSString *key = [listener gxMessageId]; + if (key.length > 0) { + self.listenerMap[key] = listener; + } + } +} + +- (void)unRegisterListener:(id )listener { + if (listener && [listener conformsToProtocol:@protocol(GaiaXSocketProtocol)]) { + NSString *key = [listener gxMessageId]; + if (key.length > 0) { + [self.listenerMap removeObjectForKey:key]; + } + } +} + + +- (void)clearSocketUrl { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"gx_socket_url"]; +} + +#pragma mark - GaiaXSocketClientDelegate + +- (void)socketClientDidConnect:(GaiaXSocketClient *)client{ + + [NSUserDefaults.standardUserDefaults setValue:client.url forKey:@"gx_socket_url"]; + [NSUserDefaults.standardUserDefaults synchronize]; + + for (id listener in self.listenerMap.allValues) { + if ([listener respondsToSelector:@selector(gxSocketClientDidConnect:)]) { + [listener gxSocketClientDidConnect:client]; + } + } +} + +- (void)socketClientDidDisConnect:(GaiaXSocketClient *)client{ + for (id listener in self.listenerMap.allValues) { + if ([listener respondsToSelector:@selector(gxSocketClientDidDisConnect:)]) { + [listener gxSocketClientDidDisConnect:client]; + } + } +} + +- (void)socketClient:(GaiaXSocketClient *)client didFailWithError:(NSError *)error{ + for (id listener in self.listenerMap.allValues) { + if ([listener respondsToSelector:@selector(gxSocketClient:didFailWithError:)]) { + [listener gxSocketClient:client didFailWithError:error]; + } + } +} + +- (void)socketClient:(GaiaXSocketClient *)client didReceiveMessage:(GaiaXSocketModel *)message{ + + [self.listenerMap enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + if ([obj respondsToSelector:@selector(gxSocketClient:didReceiveMessage:)]) { + [obj gxSocketClient:client didReceiveMessage:message]; + } + }]; + +} + +@end diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.h new file mode 100644 index 000000000..da8fc9d1f --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.h @@ -0,0 +1,48 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXSocketModel : NSObject + +@property (nonatomic, strong) NSNumber *messageId; +@property (nonatomic, strong) NSString *jsonRPCVersion; + +@property (nonatomic, strong) NSString *method; +@property (nonatomic, strong) NSDictionary *params; + +@property (nonatomic, strong) id error; +@property (nonatomic, strong) id result; + +- (GaiaXSocketModel *)initWithMessageString:(NSString *)message; + ++ (GaiaXSocketModel *)requestWithMethod:(NSString *)method + params:(NSDictionary *)params ; + ++ (GaiaXSocketModel *)responseWithMessageId:(NSInteger )messageId + result:(NSDictionary *)result; + ++ (GaiaXSocketModel *)responseWithMessageId:(NSInteger )messageId + error:(NSDictionary *)error; + ++ (GaiaXSocketModel *)notificationWithMethod:(NSString *)method + params:(NSDictionary *)params; + +- (NSString *)stringifyModel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.m b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.m new file mode 100644 index 000000000..201658fcc --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.m @@ -0,0 +1,117 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXSocketModel.h" + +static NSInteger GAIAX_SOCKET_REQUEST_ID = 1; + +@implementation GaiaXSocketModel + +- (GaiaXSocketModel *)initWithMessageString:(NSString *)message { + if (self = [super init]) { + NSDictionary *result = nil; + @try { + result = [NSJSONSerialization JSONObjectWithData:[message dataUsingEncoding:NSUTF8StringEncoding] options:0 error:NULL]; + } @catch (NSException *exception) { + + } @finally { + if (result != nil) { + self.jsonRPCVersion = result[@"jsonrpc"]; + if (result[@"id"] != nil) { + self.messageId = [NSNumber numberWithInteger: [result[@"id"] integerValue]]; + } + if (result[@"error"] != nil) { + self.error = result[@"error"]; + } else if (result[@"result"] != nil) { + self.result = result[@"result"]; + } + if (result[@"params"] != nil) { + self.params = result[@"params"]; + } + if (result[@"method"] != nil) { + self.method = result[@"method"]; + } + } + } + } + return self; +} + +- (NSString *)stringifyModel { + NSString *result = nil; + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + [dict setObject:self.jsonRPCVersion forKey:@"jsonrpc"]; + if (self.messageId != nil) { + [dict setObject:self.messageId forKey:@"id"]; + } + if (self.method != nil) { + [dict setObject:self.method forKey:@"method"]; + } + if (self.params != nil) { + [dict setObject:self.params forKey:@"params"]; + } + if (self.result != nil) { + [dict setObject:self.result forKey:@"result"]; + } + if (self.error != nil) { + [dict setObject:self.error forKey:@"error"]; + } + @try { + NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL]; + result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } @catch (NSException *exception) { + + } @finally { + return result; + } +} + ++ (GaiaXSocketModel *)requestWithMethod:(NSString *)method + params:(NSDictionary *)params { + GaiaXSocketModel *model = [[GaiaXSocketModel alloc] init]; + model.jsonRPCVersion = @"2.0"; + model.messageId = [NSNumber numberWithInteger:GAIAX_SOCKET_REQUEST_ID++]; + model.method = method; + model.params = params; + return model; +} + ++ (GaiaXSocketModel *)responseWithMessageId:(NSInteger )messageId + result:(NSDictionary *)result { + GaiaXSocketModel *model = [[GaiaXSocketModel alloc] init]; + model.jsonRPCVersion = @"2.0"; + model.messageId = [NSNumber numberWithInteger:messageId]; + model.result = result; + return model; +} + ++ (GaiaXSocketModel *)responseWithMessageId:(NSInteger )messageId + error:(NSDictionary *)error { + GaiaXSocketModel *model = [[GaiaXSocketModel alloc] init]; + model.jsonRPCVersion = @"2.0"; + model.messageId = [NSNumber numberWithInteger:messageId]; + model.error = error; + return model; +} + ++ (GaiaXSocketModel *)notificationWithMethod:(NSString *)method + params:(NSDictionary *)params { + GaiaXSocketModel *model = [[GaiaXSocketModel alloc] init]; + model.jsonRPCVersion = @"2.0"; + model.method = method; + model.params = params; + return model; +} + +@end diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketProtocol.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketProtocol.h new file mode 100644 index 000000000..2d51c1d3e --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketProtocol.h @@ -0,0 +1,50 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GaiaXSocketModel; +@class GaiaXSocketClient; + +@protocol GaiaXSocketProtocol + +@required +- (NSString *)gxMessageId; + +@optional + +@property (nonatomic, assign) BOOL isActive; + +- (void)gxSocketClientDidConnect:(GaiaXSocketClient *)client; + +- (void)gxSocketClientDidDisConnect:(GaiaXSocketClient *)client; + +- (void)gxSocketClient:(GaiaXSocketClient *)client didFailWithError:(NSError *)error; + +- (void)gxSocketClient:(GaiaXSocketClient *)client didReceiveMessage:(GaiaXSocketModel *)message; + +@end + + +@protocol GaiaXOpenPreviewProtocol + +@required ++ (void)gxOpenPreviewPage; + +@end + + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h similarity index 59% rename from GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.h rename to GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h index 0884fe571..df05edd08 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.h +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h @@ -1,8 +1,4 @@ -// -// GaiaXSocketRequest.m -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. +// Copyright (c) 2023, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,15 +16,14 @@ NS_ASSUME_NONNULL_BEGIN -@interface GaiaXSocketRequest : NSObject +@interface GaiaXSocketUtils : NSObject + ++ (BOOL)isNetworkReachable; -@property (nonatomic, strong) NSString *method; -@property (nonatomic, strong) NSNumber *requestId; -@property (nonatomic, strong) NSString *parameters; ++ (NSString *)jsonStringFromDictionary:(NSDictionary *)dictionary; -+ (instancetype)requestWithRequestId:(NSNumber *)requestId Method:(NSString *)method parameters:(nullable id)parameters; ++ (NSDictionary *)dictionaryFromJsonString:(NSString *)jsonString; -- (NSString *)toJSONString; @end diff --git a/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.m b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.m new file mode 100644 index 000000000..2d15b41ac --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.m @@ -0,0 +1,46 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXSocketUtils.h" + +@implementation GaiaXSocketUtils + ++ (BOOL)isNetworkReachable{ + return YES; +} + ++ (NSString *)jsonStringFromDictionary:(NSDictionary *)dictionary{ + if (dictionary && [dictionary isKindOfClass:[NSDictionary class]]) { + NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil]; + if (data) { + NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return jsonString; + } + } + return nil; +} + ++ (NSDictionary *)dictionaryFromJsonString:(NSString *)jsonString{ + if (jsonString && [jsonString isKindOfClass:[NSString class]]) { + NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; + if (data) { + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + return dict; + } + } + return nil; +} + + +@end diff --git a/GaiaXSocketiOS/GaiaXSocket/Info.plist b/GaiaXSocketiOS/GaiaXSocket/Info.plist new file mode 100644 index 000000000..0c8879553 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/Info.plist @@ -0,0 +1,8 @@ + + + + + CFBundleInfoDictionaryVersion + 6.0 + + diff --git a/GaiaXSocketiOS/Podfile b/GaiaXSocketiOS/Podfile new file mode 100644 index 000000000..14cb4bb30 --- /dev/null +++ b/GaiaXSocketiOS/Podfile @@ -0,0 +1,12 @@ +source 'https://github.com/CocoaPods/Specs.git' +source 'https://github.com/Artsy/Specs.git' + +target 'GaiaXSocket' do + platform :ios, '9.0' + # Uncomment the next line if you're using Swift or would like to use dynamic frameworks + # use_frameworks! + use_modular_headers! + + pod 'SocketRocket', '0.5.1' + +end diff --git a/GaiaXiOS/GaiaXiOS.podspec b/GaiaXiOS/GaiaXiOS.podspec index 5a0b733e9..6f83b58b3 100644 --- a/GaiaXiOS/GaiaXiOS.podspec +++ b/GaiaXiOS/GaiaXiOS.podspec @@ -25,6 +25,7 @@ Pod::Spec.new do |s| s.dependency 'GaiaMotionCurve' + s.dependency 'GaiaXJS' s.pod_target_xcconfig = { 'VALID_ARCHS' => 'arm64 armv7 x86_64' } diff --git a/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj b/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj index 142ed9335..d0033ed42 100644 --- a/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj +++ b/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj @@ -187,6 +187,11 @@ 9DAF453029EE9288009EE8E6 /* GXExpressionExtendTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DAF452F29EE9288009EE8E6 /* GXExpressionExtendTest.swift */; }; B188ACE529237797005C9F62 /* GXEventTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B188ACE429237797005C9F62 /* GXEventTest.swift */; }; B1FAA68E29641D9400A67420 /* GXCssTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FAA68D29641D9400A67420 /* GXCssTest.swift */; }; + BD42E32E29A4A49F00F3404E /* GXJSDelegateImplManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BD42E32C29A4A49F00F3404E /* GXJSDelegateImplManager.h */; }; + BD42E32F29A4A49F00F3404E /* GXJSDelegateImplManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BD42E32D29A4A49F00F3404E /* GXJSDelegateImplManager.m */; }; + BD42E33329A4A4B200F3404E /* GXEvent_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD42E33029A4A4B100F3404E /* GXEvent_Private.h */; }; + BD42E33429A4A4B200F3404E /* GXEventManager.h in Headers */ = {isa = PBXBuildFile; fileRef = BD42E33129A4A4B200F3404E /* GXEventManager.h */; }; + BD42E33529A4A4B200F3404E /* GXEventManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BD42E33229A4A4B200F3404E /* GXEventManager.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -384,6 +389,11 @@ 9DAF452F29EE9288009EE8E6 /* GXExpressionExtendTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GXExpressionExtendTest.swift; sourceTree = ""; }; B188ACE429237797005C9F62 /* GXEventTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GXEventTest.swift; sourceTree = ""; }; B1FAA68D29641D9400A67420 /* GXCssTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GXCssTest.swift; sourceTree = ""; }; + BD42E32C29A4A49F00F3404E /* GXJSDelegateImplManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXJSDelegateImplManager.h; sourceTree = ""; }; + BD42E32D29A4A49F00F3404E /* GXJSDelegateImplManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXJSDelegateImplManager.m; sourceTree = ""; }; + BD42E33029A4A4B100F3404E /* GXEvent_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXEvent_Private.h; sourceTree = ""; }; + BD42E33129A4A4B200F3404E /* GXEventManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GXEventManager.h; sourceTree = ""; }; + BD42E33229A4A4B200F3404E /* GXEventManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GXEventManager.m; sourceTree = ""; }; CA43FB5B0B95A83F4433A734 /* Pods-GaiaXiOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXiOS.release.xcconfig"; path = "Target Support Files/Pods-GaiaXiOS/Pods-GaiaXiOS.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -632,6 +642,7 @@ 8DE5E39D2745FC3400C9FA02 /* Binding */ = { isa = PBXGroup; children = ( + BD42E32B29A4A49F00F3404E /* JS */, 8DB5216B2759C88F00EB8126 /* Protocol */, 8DE5E3A02745FD8200C9FA02 /* Expression */, 8DE5E39F2745FD7600C9FA02 /* Event */, @@ -656,6 +667,9 @@ 8DE5E39F2745FD7600C9FA02 /* Event */ = { isa = PBXGroup; children = ( + BD42E33029A4A4B100F3404E /* GXEvent_Private.h */, + BD42E33129A4A4B200F3404E /* GXEventManager.h */, + BD42E33229A4A4B200F3404E /* GXEventManager.m */, 8D1CBCEB275770F700EC2B4D /* GXEvent.h */, 8D1CBCEC275770F700EC2B4D /* GXEvent.m */, 8DB521672759C7C900EB8126 /* GXTrack.h */, @@ -914,6 +928,15 @@ name = Frameworks; sourceTree = ""; }; + BD42E32B29A4A49F00F3404E /* JS */ = { + isa = PBXGroup; + children = ( + BD42E32C29A4A49F00F3404E /* GXJSDelegateImplManager.h */, + BD42E32D29A4A49F00F3404E /* GXJSDelegateImplManager.m */, + ); + path = JS; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -949,6 +972,7 @@ 8DFEC2802734FF3D001F3B74 /* GXTemplateData.h in Headers */, 8DFEC2582734DB80001F3B74 /* GXTemplateItem.h in Headers */, 8DB60A2C27F4764E0038BE13 /* GXFunction.h in Headers */, + BD42E32E29A4A49F00F3404E /* GXJSDelegateImplManager.h in Headers */, 8DFEC2EE27351BB6001F3B74 /* GXBaseNode.h in Headers */, 8D9FC9D0273A220800912EE6 /* GXTextNode.h in Headers */, 8D9FC9E0273A224900912EE6 /* GXIconFontNode.h in Headers */, @@ -966,6 +990,7 @@ 8DFEC2D127350F86001F3B74 /* GXConstants.h in Headers */, 8DE5E3B42747AF9600C9FA02 /* GXRichText.h in Headers */, 8DDD6B4927337C3A0042487D /* GaiaXiOS.h in Headers */, + BD42E33329A4A4B200F3404E /* GXEvent_Private.h in Headers */, 8DB60A2327F4764E0038BE13 /* GXObject.h in Headers */, 8DFEC2EA27351A03001F3B74 /* GXScrollView.h in Headers */, 8DB60A1127F4764E0038BE13 /* GXAnalyzeBridge.h in Headers */, @@ -1002,6 +1027,7 @@ 8DFEC2CE27350E34001F3B74 /* GXNode.h in Headers */, 8D9FC9D4273A221A00912EE6 /* GXGridNode.h in Headers */, 8DDF3BBF2761E9350014E4D8 /* GXAnimationModel.h in Headers */, + BD42E33429A4A4B200F3404E /* GXEventManager.h in Headers */, 8DFEC27C2734DE10001F3B74 /* UIColor+GX.h in Headers */, 8DFEC28927350509001F3B74 /* GXGradientHelper.h in Headers */, 8DFEC2C627350E0F001F3B74 /* GXStyle.h in Headers */, @@ -1196,6 +1222,7 @@ 8DE5E37327424CFD00C9FA02 /* GXTemplateContext.m in Sources */, 8DB60A1227F4764E0038BE13 /* GXContext.mm in Sources */, 8DE5E3972744DAA200C9FA02 /* GXUIHelper.m in Sources */, + BD42E33529A4A4B200F3404E /* GXEventManager.m in Sources */, 8DFEC2652734DC56001F3B74 /* GXCssItem.m in Sources */, 8DFF84E9273D183F0014C0DA /* GXRootView.m in Sources */, 8DFEC2712734DDBE001F3B74 /* NSDictionary+GX.m in Sources */, @@ -1216,6 +1243,7 @@ 8DDF3BC02761E9350014E4D8 /* GXAnimationModel.m in Sources */, 8DE5E39C2745F94E00C9FA02 /* GXLayoutManager.m in Sources */, 8DFEC2EF27351BB6001F3B74 /* GXBaseNode.m in Sources */, + BD42E32F29A4A49F00F3404E /* GXJSDelegateImplManager.m in Sources */, 8DE5E38F2744B20200C9FA02 /* GXNodeHelper.m in Sources */, 8DE14A19288E338100FCF226 /* GXProgressNode.m in Sources */, 8DE5E3A82746794300C9FA02 /* GXImageNode.m in Sources */, @@ -1442,7 +1470,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = TNX2PP585H; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1476,7 +1504,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = TNX2PP585H; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; diff --git a/GaiaXiOS/GaiaXiOS.xcodeproj/project.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate b/GaiaXiOS/GaiaXiOS.xcodeproj/project.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..f22b05b21 Binary files /dev/null and b/GaiaXiOS/GaiaXiOS.xcodeproj/project.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.h b/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.h index addc5c257..a38757b26 100644 --- a/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.h +++ b/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.h @@ -35,6 +35,11 @@ NS_ASSUME_NONNULL_BEGIN /// @param node 根节点 + (void)bindData:(GXTemplateData *)data onRootNode:(GXNode *)node; +/// 绑定数据 -(区分js和native调用) +/// @param data 原始数据 +/// @param node 根节点 +/// @param fromJS 是否是从js调用 ++ (void)bindData:(GXTemplateData *)data onRootNode:(GXNode *)node fromJS:(BOOL)fromJS; /// 计算布局 /// @param data 原始数据 diff --git a/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.m b/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.m index dbd1b0511..606cb374e 100644 --- a/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.m +++ b/GaiaXiOS/GaiaXiOS/Binding/Data/GXDataManager.m @@ -46,12 +46,22 @@ + (void)bindData:(GXTemplateData *)data onRootNode:(GXNode *)node{ return; } //绑定数据 + [self bindData:data onRootNode:node fromJS:NO]; +} + + +/// 绑定数据 -(区分js和native调用) ++ (void)bindData:(GXTemplateData *)data onRootNode:(GXNode *)node fromJS:(BOOL)fromJS { + node.orignalData = data; NSDictionary *dataDict = data.data; - [self gx_bindData:dataDict onNode:node]; + [self gx_bindData:dataDict onNode:node fromJS:fromJS]; + if (!fromJS) { + [node onReady]; + } } //递归绑定操作 -+ (void)gx_bindData:(NSDictionary *)data onNode:(GXNode *)node{ ++ (void)gx_bindData:(NSDictionary *)data onNode:(GXNode *)node fromJS:(BOOL)fromJS { //获取拍平节点 NSMapTable *flatNodes = node.flatNodes; if (flatNodes.count > 0) { @@ -77,7 +87,10 @@ + (void)gx_bindData:(NSDictionary *)data onNode:(GXNode *)node{ } //③绑定数据到子模板 - [self gx_bindData:valueDict onNode:tmpNode]; + [self gx_bindData:valueDict onNode:tmpNode fromJS:fromJS]; + if (!fromJS) { + [tmpNode onReady]; + } } else { //绑定数据到节点 diff --git a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.h b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.h index 1866a1d31..9f67216c0 100644 --- a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.h +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.h @@ -25,11 +25,16 @@ NS_ASSUME_NONNULL_BEGIN //event gesture type typedef NS_ENUM(NSUInteger, GXEventType) { - GXEventTypeUnknown = 0, // Unknown event type - GXEventTypeTap = 1,//tap - GXEventTypeLongPress = 2,//long press + GXEventTypeTap = 0,//tap + GXEventTypeLongPress = 1,//long press }; +//手势类型 +typedef NS_ENUM(NSInteger, GXEventLevel) { + GXEventLevelCover = -1,//js覆盖native + GXEventLevelNative = 0,//native高于js + GXEventLevelJS = 1,//native低于js +}; @interface GXEvent : NSObject @@ -46,13 +51,11 @@ typedef NS_ENUM(NSUInteger, GXEventType) { //gesture type:tap, longpress @property (nonatomic, assign) GXEventType eventType; -// get event type -+ (GXEventType)getType:(NSString *)eventType; - //set event information - (void)setupEventInfo:(NSDictionary *)eventInfo; - +// get event type ++ (GXEventType)eventTypeWithEventInfo:(NSDictionary *)eventInfo; @end @@ -63,6 +66,15 @@ typedef NS_ENUM(NSUInteger, GXEventType) { @end +@interface GXJsEvent : NSObject + +//对应的GXEvent实例 +@property (nonatomic, weak) GXEvent *gxEvent; +//js绑定手势类型 +@property (nonatomic, assign) GXEventType eventType; +//优先级 +@property (nonatomic, assign) GXEventLevel eventLevel; +@end NS_ASSUME_NONNULL_END diff --git a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.m b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.m index 5dd555b9d..83c58b86d 100644 --- a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.m +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.m @@ -19,6 +19,7 @@ #import "GXEvent.h" #import "GXUtils.h" #import "NSDictionary+GX.h" +#import "GXEvent_Private.h" @interface GXEvent () @@ -38,18 +39,59 @@ - (instancetype)init{ } - (void)setupEventInfo:(NSDictionary *)eventInfo { + //事件类型 + self.eventType = [GXEvent eventTypeWithEventInfo:eventInfo]; //事件信息 self.eventParams = eventInfo; } -+ (GXEventType)getType:(NSString *)eventType { - if ([@"tap" isEqualToString:eventType]) { - return GXEventTypeTap; - } else if ([@"longpress" isEqualToString:eventType]) { ++ (GXEventType)eventTypeWithEventInfo:(NSDictionary *)eventInfo{ + NSString *eventType = [eventInfo gx_stringForKey:@"eventType"]; //tap、longpress + if ([@"longpress" isEqualToString:eventType]) { return GXEventTypeLongPress; } else { - return GXEventTypeUnknown; + return GXEventTypeTap; + } +} + + +#pragma mark - JS + +//创建jsEvent +- (void)creatJsEvent:(NSDictionary *)eventInfo{ + //js事件类型处理 + GXEventType eventType = [GXEvent eventTypeWithEventInfo:eventInfo]; + + GXJsEvent *jsEvent = self.jsEvent; + if (jsEvent == nil) { + jsEvent = [[GXJsEvent alloc] init]; + jsEvent.gxEvent = self; + self.jsEvent = jsEvent; } + + jsEvent.eventType = eventType; + jsEvent.eventLevel = [self eventLevelFrom:eventInfo]; +} + +//获取js和native事件优先级 +- (GXEventLevel)eventLevelFrom:(NSDictionary *)eventInfo{ + GXEventLevel level = GXEventLevelNative; + + //事件option配置 + NSDictionary *option = [eventInfo gx_dictionaryForKey:@"option"]; + if (option) { + BOOL cover = [option gx_boolForKey:@"cover"]; + if (cover) { + level = GXEventLevelCover; + } else { + NSInteger tmpLevel = [option gx_integerForKey:@"level"]; + if (tmpLevel >= -1 && tmpLevel <= 1) { + level = (GXEventLevel)tmpLevel; + } + } + } + + return level; } @end @@ -58,3 +100,7 @@ + (GXEventType)getType:(NSString *)eventType { @implementation GXEvent(Scroll) @end + +@implementation GXJsEvent + +@end diff --git a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.h b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.h new file mode 100644 index 000000000..a27028c4a --- /dev/null +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.h @@ -0,0 +1,55 @@ +// +// GXEventManager.h +// GaiaXiOS +// +// Copyright (c) 2021, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +@class GXEvent; +@class GXNode; + +NS_ASSUME_NONNULL_BEGIN + +#define TheGXEventManager [GXEventManager defaultManager] + +@interface GXEventManager : NSObject + +//模板实例id +@property (nonatomic, assign, readonly) NSInteger instanceId; +//模板实例 +@property (nonatomic, strong, readonly) NSMapTable *map; + +/// 单例 ++ (instancetype)defaultManager; + +/// 注册事件 +/// @param event 事件 +/// @param node 节点 +- (void)registerEvent:(GXEvent *)event forNode:(GXNode *)node; + +/// 发送事件 +/// @param event 事件 +/// @param node 节点 +- (void)fireEvent:(GXEvent *)event toNode:(GXNode *)node; + + +//存储 & 读取模板的实例 +- (void)addTemplate:(GXNode *)node; +- (GXNode *)templateForkey:(NSString *)key; +- (void)removeTemplateForkey:(NSString *)key; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.m b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.m new file mode 100644 index 000000000..2de0586a4 --- /dev/null +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.m @@ -0,0 +1,219 @@ +// +// GXEventManager.m +// GaiaXiOS +// +// Copyright (c) 2021, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import "GXEventManager.h" +#import "GXNode.h" +#import "GXEvent.h" +#import "GXUtils.h" +#import "GXRootView.h" +#import "UIView+GX.h" +#import "NSArray+GX.h" +#import "GXEvent_Private.h" +#import "NSDictionary+GX.h" +#import "GXRegisterCenter.h" +#import "GXTemplateContext.h" + +@interface GXEventManager() + +//模板实例 +@property (nonatomic, strong) NSMapTable *map; +//实例id,进行自增 +@property (nonatomic, assign) NSInteger instanceId; +//信号量 +@property (nonatomic, strong) dispatch_semaphore_t semaphore; + +@end + + +@implementation GXEventManager + ++ (instancetype)defaultManager{ + static GXEventManager *manager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (nil == manager) { + manager = [[GXEventManager alloc] init]; + } + }); + return manager; +} + +- (instancetype)init{ + self = [super init]; + if (self) { + self.instanceId = 0; + //创建信号量 + self.semaphore = dispatch_semaphore_create(1); + } + return self; +} + +- (void)dealloc{ + GXLog(@"[GaiaX] 事件管理eventManager释放 - %@", self); +} + + +#pragma mark - 事件分发 + +//注册事件 +- (void)registerEvent:(GXEvent *)event forNode:(GXNode *)node{ + //类型判断 + if (event == nil || node == nil) { + return; + } + + //给节点添加手势/事件 + [node bindEvent:event]; +} + +//发送事件(Native) +- (void)fireEvent:(GXEvent *)event toNode:(GXNode *)node{ + //类型判断 + if (event == nil || node == nil) { + return; + } + + //事件分发 + GXTemplateContext *ctx = node.rootNode.templateContext; + [self handleEvent:event context:ctx]; +} + + +#pragma mark - 事件处理 + +- (void)handleEvent:(GXEvent *)event context:(GXTemplateContext *)ctx{ + GXJsEvent *jsEvent = event.jsEvent; + //js和native兼容处理Œ + if (jsEvent) { + switch (jsEvent.eventLevel) { + case GXEventLevelCover:{ + //js事件处理 + [self handleJSEvent:jsEvent context:ctx]; + } + break; + case GXEventLevelJS:{ + //js事件处理 + [self handleJSEvent:jsEvent context:ctx]; + //native事件处理 + [self handleNativeEvent:event context:ctx]; + } + break; + default:{ + //native事件处理 + [self handleNativeEvent:event context:ctx]; + //js事件处理 + [self handleJSEvent:jsEvent context:ctx]; + } + break; + } + + } else { + //native事件处理 + [self handleNativeEvent:event context:ctx]; + } +} + +// JS Event +- (void)handleJSEvent:(GXJsEvent *)event context:(GXTemplateContext *)ctx{ + //处理js事件 + GaiaXJSComponent *jsComponent = event.gxEvent.jsComponent; + if (jsComponent) { + //生成type + GaiaXJSEventType type = (GaiaXJSEventType)event.eventType; + //生成data + NSMutableDictionary *data = [NSMutableDictionary dictionary]; + GXNode *targetNode = event.gxEvent.view.gxNode; + [data gx_setObject:targetNode.type forKey:@"targetType"]; + [data gx_setObject:targetNode.nodeId forKey:@"targetId"]; + [data gx_setObject:targetNode.subType forKey:@"targetSubType"]; + [data gx_setObject:@([[NSDate date] timeIntervalSince1970]) forKey:@"timeStamp"]; + //发送js事件 + [jsComponent emmitEvent:type data:data]; + } +} + +// Native Event +- (void)handleNativeEvent:(GXEvent *)event context:(GXTemplateContext *)ctx{ + //获取eventListener & 响应方法 + id eventListener = ctx.templateData.eventListener; + if (eventListener && [eventListener respondsToSelector:@selector(gx_onGestureEvent:)]) { + [eventListener gx_onGestureEvent:event]; + } +} + + +#pragma mark - 添加模板实例 + +- (void)addTemplate:(GXNode *)node{ + if (nil == node || ![node isKindOfClass:[GXNode class]]) { + return; + } + + //等待降低信号量 + dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); + //添加实例 + NSString *key = [NSString stringWithFormat:@"%ld", (long)self.instanceId]; + [self.map setObject:node forKey:key]; + self.instanceId++; + //提高型号量 + dispatch_semaphore_signal(self.semaphore); +} + +- (GXNode *)templateForkey:(NSString *)key{ + if (nil == key) { + return nil; + } + + GXNode *node = nil; + + //等待降低信号量 + dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); + //读取value + node = [self.map objectForKey:key]; + //提高型号量 + dispatch_semaphore_signal(self.semaphore); + + return node; +} + +- (void)removeTemplateForkey:(NSString *)key{ + if (nil == key) { + return; + } + + //等待降低信号量 + dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); + //移除实例 + [self.map removeObjectForKey:key]; + //提高型号量 + dispatch_semaphore_signal(self.semaphore); +} + + +#pragma mark - lazy load + +- (NSMapTable *)map{ + if (!_map) { + _map = [NSMapTable strongToWeakObjectsMapTable]; + } + return _map; +} + + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h similarity index 50% rename from GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m rename to GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h index 654e10ddf..9ce0a7700 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h @@ -1,11 +1,14 @@ // +// GaiaEvent_Private.h +// GaiaXiOS +// // Copyright (c) 2021, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -13,19 +16,21 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef GaiaEvent_Private_h +#define GaiaEvent_Private_h + +#import "GXEvent.h" +#import -#import "GaiaXJSONRPCConstants.h" +@interface GXEvent() -NSString* const GaiaXJSONRPCKey = @"jsonrpc"; -NSString* const GaiaXJSONRPCVersion = @"2.0"; -NSString* const GaiaXJSONRPCIdKey = @"id"; +//jsComponent +@property (nonatomic, weak, nullable) GaiaXJSComponent *jsComponent; +//js事件 +@property (nonatomic, strong, nullable) GXJsEvent *jsEvent; -NSString* const GaiaXJSONRPCMethodKey = @"method"; -NSString* const GaiaXJSONRPCParamsKey = @"params"; +- (void)creatJsEvent:(NSDictionary *_Nullable)eventInfo; -NSString* const GaiaXJSONRPCResultKey = @"result"; -NSString* const GaiaXJSONRPCErrorKey = @"error"; +@end -NSString* const GaiaXJSONRPCCodeKey = @"code"; -NSString* const GaiaXJSONRPCMessageKey = @"message"; -NSString* const GaiaXJSONRPCDataKey = @"data"; +#endif /* GaiaEvent_Private_h */ diff --git a/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.h b/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.h new file mode 100644 index 000000000..9380a193c --- /dev/null +++ b/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.h @@ -0,0 +1,22 @@ +// +// GaiaJSEventManager.h +// GaiaXCore +// +// Created by zjc on 2021/7/2. +// Copyright © 2021 zhangjc. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +#define TheGXJSDelegateImplManager [GXJSDelegateImplManager defaultManager] + +@interface GXJSDelegateImplManager : NSObject + ++ (instancetype)defaultManager; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.m b/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.m new file mode 100644 index 000000000..748b08602 --- /dev/null +++ b/GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.m @@ -0,0 +1,261 @@ +// +// GaiaJSEventManager.m +// GaiaXCore +// +// Created by zjc on 2021/7/2. +// Copyright © 2021 zhangjc. All rights reserved. +// + +#import "GXJSDelegateImplManager.h" +#import "GXRootViewProtocal.h" +#import "GXTemplateContext.h" +#import "NSDictionary+GX.h" +#import "GXEvent_Private.h" +#import "GXEventManager.h" +#import "GXTemplateData.h" +#import "GXDataManager.h" +#import "GXCommonDef.h" +#import "NSArray+GX.h" +#import "UIView+GX.h" +#import "GXUtils.h" +#import "GXNode.h" +#import "GXRootView.h" +#import "GXEvent.h" + +@implementation GXJSDelegateImplManager + ++ (instancetype)defaultManager { + static dispatch_once_t onceToken; + static GXJSDelegateImplManager *manager = nil; + dispatch_once(&onceToken, ^{ + manager = [[GXJSDelegateImplManager alloc] init]; + [GaiaXJSFactory defaultFactory].modulesImplDelegate = manager; + }); + return manager; +} + + +#pragma mark - 实现代理 + +- (NSDictionary *)getElement:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return nil; + } + + //获取js透传的内容 + NSString *targetId = [extendInfo gx_stringForKey:@"targetId"]; + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //获取对应的节点 + NSMutableDictionary *resultDict = nil; + if (targetId.length && templateId.length && instanceIdStr.length) { + //通过instanceId获取节点 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + GXNode *targetNode = [node queryNodeByNodeId:targetId]; + if (targetNode) { + resultDict = [NSMutableDictionary dictionary]; + //节点id + [resultDict gx_setObject:targetId forKey:@"targetId"]; + //添加type + [resultDict gx_setObject:targetNode.type forKey:@"targetType"]; + [resultDict gx_setObject:targetNode.subType forKey:@"targetSubType"]; + } + } + } + + return resultDict; +} + + +- (BOOL)addEventListener:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return NO; + } + + //节点&模板相关属性 + NSString *targetId = [extendInfo gx_stringForKey:@"targetId"]; + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //开始注册事件 + if (targetId.length && templateId.length && instanceIdStr.length) { + dispatch_async(dispatch_get_main_queue(), ^{ + //通过instanceId获取模板信息 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + //获取target节点 & view + GXNode *targetNode = [node queryNodeByNodeId:targetId]; + UIView *targetView = targetNode.associatedView; + if (targetView == nil) { + targetView = [targetNode creatView]; + } + + //获取event + GXEventType eventType = [GXEvent eventTypeWithEventInfo:extendInfo]; + GXEvent *event = [targetView gx_eventWithType:eventType]; + if (!event) { + event = [[GXEvent alloc] init]; + event.view = (GXRootView *)(node.rootNode.associatedView); + event.templateItem = node.templateItem; + event.eventType = eventType; + event.nodeId = node.nodeId; + event.view = targetView; + //赋值 + [targetView gx_setEvent:event withType:eventType]; + } + //jsComponent + event.jsComponent = node.jsComponent; + [event creatJsEvent:extendInfo]; + + //注册事件 + [TheGXEventManager registerEvent:event forNode:targetNode]; + } + }); + } + + return YES; +} + + +- (BOOL)removeEventListener:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return NO; + } + + //节点&模板相关属性 + NSString *targetId = [extendInfo gx_stringForKey:@"targetId"]; + NSString *eventType = [extendInfo gx_stringForKey:@"eventType"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //获取对应的节点 + if (targetId.length && instanceIdStr.length && eventType.length) { + //通过instanceId获取节点 + dispatch_async(dispatch_get_main_queue(), ^{ + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + GXNode *targetNode = [node queryNodeByNodeId:targetId]; + UIView *targetView = targetNode.associatedView; + //取消事件 + if ([eventType isEqualToString:@"click"]) { + targetView.gxEvent.jsEvent = nil; + } else if ([eventType isEqualToString:@"longpress"]){ + targetView.gxLpEvent.jsEvent = nil; + } + } + }); + } + + return YES; +} + + +- (NSDictionary *)getBindingData:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return nil; + } + + //获取js透传的内容 + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //获取对应的节点 + NSDictionary *resultDict = nil; + if (templateId.length && instanceIdStr.length) { + //通过instanceId获取节点 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + //获取根节点/数据 + GXNode *rootNode = node.rootNode; + resultDict = rootNode.orignalData.data; + } + } + + return resultDict; +} + + +- (void)setBindingData:(NSDictionary *)data extendInfo:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:data] || ![GXUtils isValidDictionary:extendInfo]) { + return; + } + + //获取js透传的内容 + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //绑定数据 + if (templateId.length && instanceIdStr.length) { + //通过instanceId获取节点 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + //数据相同,直接return + GXTemplateData *templateData = node.orignalData; + if (![data isEqualToDictionary:templateData.data]) { + //重新绑定数据 + GXNode *rootNode = node.rootNode; + if (rootNode) { + //更新数据 + if (templateData) { + node.orignalData.data = data; + } + + //绑定数据 + [GXDataManager bindData:templateData onRootNode:rootNode fromJS:YES]; + } + } + } + } +} + + +- (NSNumber *)getIndex:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return nil; + } + + //获取js透传的内容 + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //获取对应的节点 + NSNumber *result = nil; + if (templateId.length && instanceIdStr.length) { + //通过instanceId获取节点 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node && node.index != -1) { + //返回index + result = @(node.index); + } + } + + return result; +} + + +- (void)refresh:(NSDictionary *)extendInfo { + if (![GXUtils isValidDictionary:extendInfo]) { + return; + } + + //获取js透传的内容 + NSString *templateId = [extendInfo gx_stringForKey:@"templateId"]; + NSString *instanceIdStr = [extendInfo gx_stringForKey:@"instanceId"]; + + //获取对应的节点 + if (templateId.length && instanceIdStr.length) { + //通过instanceId获取节点 + GXNode *node = [TheGXEventManager templateForkey:instanceIdStr]; + if (node) { + //向native发送js消息 + id eventListener = node.templateContext.templateData.eventListener; + if (eventListener && [eventListener respondsToSelector:@selector(gx_onJSEvent:)]) { + [eventListener gx_onJSEvent:extendInfo]; + } + } + } +} + + +@end diff --git a/GaiaXiOS/GaiaXiOS/Binding/Protocol/GXEventProtocal.h b/GaiaXiOS/GaiaXiOS/Binding/Protocol/GXEventProtocal.h index 1fc1381a8..54e80305e 100644 --- a/GaiaXiOS/GaiaXiOS/Binding/Protocol/GXEventProtocal.h +++ b/GaiaXiOS/GaiaXiOS/Binding/Protocol/GXEventProtocal.h @@ -36,6 +36,9 @@ NS_ASSUME_NONNULL_BEGIN //animation finished event - (void)gx_animationDidFinished:(NSDictionary *)event; +//js event +- (void)gx_onJSEvent:(NSDictionary *)eventInfo; + @end NS_ASSUME_NONNULL_END diff --git a/GaiaXiOS/GaiaXiOS/Category/NSArray+GX.h b/GaiaXiOS/GaiaXiOS/Category/NSArray+GX.h index 020ec9b96..9c30f2237 100644 --- a/GaiaXiOS/GaiaXiOS/Category/NSArray+GX.h +++ b/GaiaXiOS/GaiaXiOS/Category/NSArray+GX.h @@ -22,18 +22,18 @@ NS_ASSUME_NONNULL_BEGIN @interface NSArray (GX) -//Safely get the value by index -- (id)gx_objectAtIndex:(NSUInteger)index; - //array to string - (NSString *)gx_JSONString; -//string to array -+ (NSArray *)gx_arrayFromJSONString:(NSMutableString *)jsonString; - //deepCopy - (NSMutableArray *)gx_mutableDeepCopy; +//Safely get the value by index +- (id)gx_objectAtIndex:(NSUInteger)index; + +//string to array ++ (NSArray *)gx_arrayFromJSONString:(NSMutableString *)jsonString; + @end @interface NSMutableArray(GX) diff --git a/GaiaXiOS/GaiaXiOS/Category/UIView+GX.h b/GaiaXiOS/GaiaXiOS/Category/UIView+GX.h index 9fdd8669d..997e20485 100644 --- a/GaiaXiOS/GaiaXiOS/Category/UIView+GX.h +++ b/GaiaXiOS/GaiaXiOS/Category/UIView+GX.h @@ -31,10 +31,12 @@ NS_ASSUME_NONNULL_BEGIN //view对应node @property(nonatomic, strong)GXNode *gxNode; -//view对应的 tap event -@property(nonatomic, strong)GXEvent *gxEvent; //view对应的track @property(nonatomic, strong)GXTrack *gxTrack; +//view对应的 tap event +@property(nonatomic, strong)GXEvent *gxEvent; +//view对应的 long press event +@property(nonatomic, strong)GXEvent *gxLpEvent; //业务id @property(nonatomic, strong) NSString *gxBizId; //节点id @@ -56,17 +58,14 @@ NS_ASSUME_NONNULL_BEGIN //获取view对应的vc - (UIViewController *)gx_viewController; -//处理点击手势 -- (void)gx_handleGestureTap:(UIGestureRecognizer *)gesture; - -//处理长按手势 -- (void)gx_handleGestureLongpress:(UIGestureRecognizer *)gesture; +//处理点击手势(tap、longpress) +- (void)gx_handleGesture:(UIGestureRecognizer *)gesture; // 获取事件数据 -- (GXEvent *)getGxEvent:(GXEventType) eventType; +- (GXEvent * _Nullable)gx_eventWithType:(GXEventType)eventType; // 设置事件数据 -- (void)setGxEvent:(GXEventType) eventType with: (GXEvent *) gxEvent; +- (void)gx_setEvent:(GXEvent * _Nullable)gxEvent withType:(GXEventType)eventType; @end diff --git a/GaiaXiOS/GaiaXiOS/Category/UIView+GX.m b/GaiaXiOS/GaiaXiOS/Category/UIView+GX.m index d8d7750ce..2c1bdb5f6 100644 --- a/GaiaXiOS/GaiaXiOS/Category/UIView+GX.m +++ b/GaiaXiOS/GaiaXiOS/Category/UIView+GX.m @@ -19,11 +19,12 @@ #import "UIView+GX.h" #import "GXNode.h" #import "GXEvent.h" +#import "NSArray+GX.h" #import +#import "GXEventManager.h" #import "GXGradientHelper.h" #import "GXTemplateContext.h" #import "GXCornerRadiusHelper.h" -#import "NSArray+GX.h" //基础属性 static const void *kGXNodeKey = &kGXNodeKey; @@ -63,39 +64,6 @@ - (void)setGxNode:(GXNode *)gxNode{ objc_setAssociatedObject(self, &kGXNodeKey, gxNode, OBJC_ASSOCIATION_RETAIN); } -// gxEvents -- (GXEvent *)gxEvent { - return objc_getAssociatedObject(self, &kGXEventTapKey); -} - -- (void)setGxEvent:(GXEvent *)gxEvent { - objc_setAssociatedObject(self, &kGXEventTapKey, gxEvent, OBJC_ASSOCIATION_RETAIN); -} - -- (GXEvent *)getGxEvent:(GXEventType)eventType { - switch (eventType) { - case GXEventTypeTap: - return self.gxEvent; - case GXEventTypeLongPress: - return objc_getAssociatedObject(self, &kGXEventLongpressKey); - default: - return nil; - } -} - -- (void)setGxEvent:(GXEventType)eventType with:(GXEvent *)gxEvent { - switch (eventType) { - case GXEventTypeTap: - self.gxEvent = gxEvent; - break; - case GXEventTypeLongPress: - objc_setAssociatedObject(self, &kGXEventLongpressKey, gxEvent, OBJC_ASSOCIATION_RETAIN); - break; - default: - break; - } -} - //gxTrack - (GXTrack *)gxTrack{ return objc_getAssociatedObject(self, kGXTrackKey); @@ -141,6 +109,48 @@ - (void)setGxTemplateVersion:(NSString *)gxTemplateVersion{ objc_setAssociatedObject(self, &kGXTemplateVersionKey, gxTemplateVersion, OBJC_ASSOCIATION_RETAIN); } +// gxEvents +- (GXEvent *)gxEvent { + return objc_getAssociatedObject(self, &kGXEventTapKey); +} + +- (void)setGxEvent:(GXEvent *)gxEvent { + objc_setAssociatedObject(self, &kGXEventTapKey, gxEvent, OBJC_ASSOCIATION_RETAIN); +} + +- (GXEvent *)gxLpEvent{ + return objc_getAssociatedObject(self, &kGXEventLongpressKey); +} + +- (void)setGxLpEvent:(GXEvent *)gxLpEvent { + objc_setAssociatedObject(self, &kGXEventLongpressKey, gxLpEvent, OBJC_ASSOCIATION_RETAIN); +} + +// 设置事件数据 +- (GXEvent *)gx_eventWithType:(GXEventType)eventType { + switch (eventType) { + case GXEventTypeTap: + return self.gxEvent; + case GXEventTypeLongPress: + return self.gxLpEvent; + default: + return nil; + } +} + +- (void)gx_setEvent:(GXEvent *)gxEvent withType:(GXEventType)eventType { + switch (eventType) { + case GXEventTypeTap: + self.gxEvent = gxEvent; + break; + case GXEventTypeLongPress: + self.gxLpEvent = gxEvent; + break; + default: + break; + } +} + #pragma mark - method @@ -172,33 +182,22 @@ - (UIViewController *)gx_viewController{ } //处理手势 -- (void)gx_handleGestureTap:(UIGestureRecognizer *)gesture{ +- (void)gx_handleGesture:(UIGestureRecognizer *)gesture{ //基础信息 GXNode *node = self.gxNode; - GXEvent *event = [self getGxEvent:GXEventTypeTap]; - - //事件分发 - id eventListener = node.templateContext.templateData.eventListener; - if (eventListener && [eventListener respondsToSelector:@selector(gx_onGestureEvent:)]) { - [eventListener gx_onGestureEvent:event]; + //手势类型判断 + if ([gesture isKindOfClass:[UILongPressGestureRecognizer class]]) { + //长按事件 + if (gesture.state == UIGestureRecognizerStateBegan) { + GXEvent *event = self.gxLpEvent; + [TheGXEventManager fireEvent:event toNode:node]; + } + } else { + //点击事件 + GXEvent *event = self.gxEvent; + [TheGXEventManager fireEvent:event toNode:node]; } - - //点击埋点分发 - [node manualClickTrackEvent]; -} -//处理手势 -- (void)gx_handleGestureLongpress:(UIGestureRecognizer *)gesture{ - //基础信息 - GXNode *node = self.gxNode; - GXEvent *event = [self getGxEvent:GXEventTypeLongPress]; - - //事件分发 - id eventListener = node.templateContext.templateData.eventListener; - if (eventListener && [eventListener respondsToSelector:@selector(gx_onGestureEvent:)]) { - [eventListener gx_onGestureEvent:event]; - } - //点击埋点分发 [node manualClickTrackEvent]; } diff --git a/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m b/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m index 79de07194..8fb9d0b2d 100644 --- a/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m +++ b/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m @@ -496,13 +496,13 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL #pragma mark - appear -- (void)onAppear{ - [super onAppear]; +- (void)onShow{ + [super onShow]; [self handleVisibleCells]; } -- (void)onDisappear{ - [super onDisappear]; +- (void)onHide{ + [super onHide]; } - (void)handleVisibleCells{ diff --git a/GaiaXiOS/GaiaXiOS/Component/Node/GXScrollNode.m b/GaiaXiOS/GaiaXiOS/Component/Node/GXScrollNode.m index 2ec550341..c40fbc017 100644 --- a/GaiaXiOS/GaiaXiOS/Component/Node/GXScrollNode.m +++ b/GaiaXiOS/GaiaXiOS/Component/Node/GXScrollNode.m @@ -466,13 +466,13 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL #pragma mark - appear -- (void)onAppear{ - [super onAppear]; +- (void)onShow{ + [super onShow]; [self handleVisibleCells]; } -- (void)onDisappear{ - [super onDisappear]; +- (void)onHide{ + [super onHide]; } - (void)handleVisibleCells{ diff --git a/GaiaXiOS/GaiaXiOS/Component/Node/GXSliderNode.m b/GaiaXiOS/GaiaXiOS/Component/Node/GXSliderNode.m index d97756596..dea8f8818 100644 --- a/GaiaXiOS/GaiaXiOS/Component/Node/GXSliderNode.m +++ b/GaiaXiOS/GaiaXiOS/Component/Node/GXSliderNode.m @@ -512,13 +512,13 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL #pragma mark - appear -- (void)onAppear{ - [super onAppear]; +- (void)onShow{ + [super onShow]; [self handleVisibleCells]; } -- (void)onDisappear{ - [super onDisappear]; +- (void)onHide{ + [super onHide]; } - (void)handleVisibleCells{ diff --git a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXGridView.m b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXGridView.m index 3b7e5524e..0a2df78b3 100644 --- a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXGridView.m +++ b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXGridView.m @@ -24,13 +24,13 @@ @implementation GXGridView - (void)onAppear{ if (self.gxNode) { - [self.gxNode onAppear]; + [self.gxNode onShow]; } } - (void)onDisappear{ if (self.gxNode) { - [self.gxNode onDisappear]; + [self.gxNode onHide]; } } diff --git a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXRootView.m b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXRootView.m index 478863666..463c642a5 100644 --- a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXRootView.m +++ b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXRootView.m @@ -24,13 +24,13 @@ @implementation GXRootView - (void)onAppear{ if (self.gxNode) { - [self.gxNode onAppear]; + [self.gxNode onShow]; } } - (void)onDisappear{ if (self.gxNode) { - [self.gxNode onDisappear]; + [self.gxNode onHide]; } } diff --git a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXScrollView.m b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXScrollView.m index 791e00b96..06e495065 100644 --- a/GaiaXiOS/GaiaXiOS/Component/View/Container/GXScrollView.m +++ b/GaiaXiOS/GaiaXiOS/Component/View/Container/GXScrollView.m @@ -24,13 +24,13 @@ @implementation GXScrollView - (void)onAppear{ if (self.gxNode) { - [self.gxNode onAppear]; + [self.gxNode onShow]; } } - (void)onDisappear{ if (self.gxNode) { - [self.gxNode onDisappear]; + [self.gxNode onHide]; } } diff --git a/GaiaXiOS/GaiaXiOS/Core/Creator/GXNodeTreeCreator.m b/GaiaXiOS/GaiaXiOS/Core/Creator/GXNodeTreeCreator.m index 7eff1a170..2e1e237eb 100644 --- a/GaiaXiOS/GaiaXiOS/Core/Creator/GXNodeTreeCreator.m +++ b/GaiaXiOS/GaiaXiOS/Core/Creator/GXNodeTreeCreator.m @@ -28,6 +28,10 @@ #import "GXStyle.h" #import "GXNode.h" +#import "GXJSDelegateImplManager.h" +#import "GXEventManager.h" +#import + @implementation GXNodeTreeCreator //创建节点树,并获取根节点 @@ -94,16 +98,35 @@ - (GXNode *)creatNodeTreeWithTemplateItem:(GXTemplateItem *)templateItem if (rootNode) { //layout & flatNodes rootNode.flatNodes = flatNodes; + //处理jsContent + NSString *jsContent = [templateInfo gx_stringForKey:kGXComDef_KW_JS]; + if (jsContent.length) { + //注册Context + TheGXJSDelegateImplManager; + NSString *tmpBizId = bizId ?: @"common"; + NSInteger instanceId = TheGXEventManager.instanceId; + //真实的version + NSString *realTemplateVersion = [templateInfo gx_stringForKey:@"version"]; + //创建context + GaiaXJSContext *context = [GaiaXJSFactory newContextByBizIdIfNeeded:bizId]; + //注册Component + GaiaXJSComponent *jsComponent = [context newComponentWithBizId:tmpBizId + templateId:templateId + templateVersion:realTemplateVersion + instanceId:instanceId + jsString:jsContent]; + rootNode.jsComponent = jsComponent; + //添加模板示例 + [TheGXEventManager addTemplate:rootNode]; + } } } else { GXLog(@"[GaiaX] 构建节点树失败:(%@/%@)模板index.json文件异常", bizId, templateId); -// GXAssert(isValid, @"构建节点树失败:(%@/%@)index.json文件异常", bizId, templateId); } } else { GXLog(@"[GaiaX] 构建节点树失败:(%@/%@)模板文件为空", bizId, templateId); -// GXAssert([GXUtils isValidDictionary:templateInfo], @"构建节点树失败:(%@/%@)模板文件为空", bizId, templateId); } //赋值ctx diff --git a/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.h b/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.h index 158c2bf40..b4dc0e907 100644 --- a/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.h +++ b/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.h @@ -20,7 +20,10 @@ #import "GXTemplateItem.h" #import "GXLayout.h" #import "GXStyle.h" +#import "GXTemplateData.h" +#import +@class GXEvent; @class GXTemplateContext; NS_ASSUME_NONNULL_BEGIN @@ -87,6 +90,9 @@ typedef NS_ENUM(NSUInteger, GXBindType) { //节点id @property(nonatomic, strong) NSString *nodeId; +//节点类型 +@property(nonatomic, strong) NSString *type; +@property(nonatomic, strong) NSString *subType; //是否为模板类型(根模板/嵌套子模板) @property(nonatomic, assign) BOOL isTemplateType; //模板信息 @@ -141,6 +147,8 @@ typedef NS_ENUM(NSUInteger, GXBindType) { //是否需要绑定数据 - (BOOL)shouldBind; +//绑定事件 +- (void)bindEvent:(GXEvent *)event; //数据绑定 - (void)bindData:(NSDictionary *)data; //动画绑定 @@ -161,15 +169,29 @@ typedef NS_ENUM(NSUInteger, GXBindType) { //是否正在显示 @property (nonatomic, assign) BOOL isAppear; -//视图出现/消失 -- (void)onAppear; -- (void)onDisappear; - //埋点处理 - (void)manualClickTrackEvent; - (void)manualExposureTrackEvent; @end +@interface GXNode(JS) + +//原始数据 +@property (nonatomic, strong) GXTemplateData *orignalData; +//jsComponent +@property(nonatomic, strong) GaiaXJSComponent *jsComponent; + +//生命周期 +- (void)onReady; + +- (void)onShow; + +- (void)onHide; + +- (void)onDestroy; + +@end + NS_ASSUME_NONNULL_END diff --git a/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.m b/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.m index 9ebaa1bfc..f63dbf6ee 100644 --- a/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.m +++ b/GaiaXiOS/GaiaXiOS/Core/StretchKit/Classes/GXNode.m @@ -20,6 +20,7 @@ #import "GXEvent.h" #import "GXUtils.h" #import "UIView+GX.h" +#import "NSArray+GX.h" #import "GXStretch.h" #import "GXBaseNode.h" #import "GXCommonDef.h" @@ -30,9 +31,13 @@ #import "NSDictionary+GX.h" #import "GXTemplateEngine.h" #import "GXTemplateContext.h" -#import "NSArray+GX.h" +#import "GXGridNode.h" +#import "GXScrollNode.h" +#import "GXRootViewNode.h" @interface GXNode (){ + //js是否ready + BOOL _isReady; //Stretch GXStretch *_stretch; //当前根节点 @@ -44,6 +49,9 @@ @interface GXNode (){ //节点id @property(nonatomic, strong) NSString *nodeId; +//节点类型 +@property(nonatomic, strong) NSString *type; +@property(nonatomic, strong) NSString *subType; //是否模板类型 @property(nonatomic, assign) BOOL isTemplateType; //模板信息 @@ -79,6 +87,10 @@ @interface GXNode (){ //节点是否正在展示 @property (nonatomic, assign) BOOL isAppear; +//JS原始数据 +@property (nonatomic, strong) GXTemplateData *orignalData; +//jsComponent +@property (nonatomic, strong) GaiaXJSComponent *jsComponent; @end @@ -233,6 +245,20 @@ - (void)dealloc { @implementation GXNode(Template) +- (NSString *)type{ + if (!_type) { + _type = [self.viewJson gx_stringForKey:@"type"]; + } + return _type; +} + +- (NSString *)subType{ + if (!_subType) { + _subType = [self.viewJson gx_stringForKey:@"sub-type"]; + } + return _subType; +} + @end @@ -345,7 +371,7 @@ - (void)applyData:(NSDictionary *)data type:(GXBindType)type{ [resultEventArray gx_addObject:resultEvent]; } } - [self bindEvent:resultEventArray]; + [self bindEvents:resultEventArray]; } //绑定埋点 if (self.track) { @@ -439,59 +465,57 @@ - (void)bindAnimation:(NSDictionary *)animation{ } //事件绑定 -- (void)bindEvent:(NSArray *)events{ +- (void)bindEvents:(NSArray *)events{ UIView *view = self.associatedView; // 绑定event for (int i = 0; i < events.count; i++) { - NSDictionary *event = [events gx_objectAtIndex:i]; - NSString *type = [event gx_stringForKey: @"type"]; - GXEventType eventType = [GXEvent getType:type]; - - // 兜底默认为 tap 类型 - if (eventType == GXEventTypeUnknown) { - eventType = GXEventTypeTap; - } + NSDictionary *eventInfo = [events gx_objectAtIndex:i]; + GXEventType eventType = [GXEvent eventTypeWithEventInfo:eventInfo]; // 获取event - GXEvent *gxEvent = [view getGxEvent:eventType]; + GXEvent *gxEvent = [view gx_eventWithType:eventType]; if (nil == gxEvent) { gxEvent = [[GXEvent alloc] init]; gxEvent.templateItem = self.templateItem; + gxEvent.eventType = eventType; gxEvent.nodeId = self.nodeId; gxEvent.view = view; - gxEvent.eventType = eventType; - //赋值 - [view setGxEvent:eventType with:gxEvent]; + //绑定到view + [view gx_setEvent:gxEvent withType:eventType]; } // 更新数据 - [gxEvent setupEventInfo:event]; + [gxEvent setupEventInfo:eventInfo]; // 绑定事件 - switch (eventType) { - case GXEventTypeTap: - // 点击事件 - if (!_tap) { - _tap = [[UITapGestureRecognizer alloc] initWithTarget:view action:@selector(gx_handleGestureTap:)]; - _tap.delegate = self; - view.userInteractionEnabled = true; - [view addGestureRecognizer:_tap]; - } - break; - case GXEventTypeLongPress: - // 长按事件 - if (!_longPress) { - _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:view action:@selector(gx_handleGestureLongpress:)]; - _longPress.delegate = self; - view.userInteractionEnabled = true; - [view addGestureRecognizer:_longPress]; - } - break; - default: - GXLog(@"[GaiaX] 不支持的事件类型:%@", type); - break; + [self bindEvent:gxEvent]; + } +} + +- (void)bindEvent:(GXEvent *)event{ + //设置userInterface + UIView *view = self.associatedView; + if (!view.userInteractionEnabled) { + view.userInteractionEnabled = YES; + } + + //添加手势类型 + if (event.eventType == GXEventTypeLongPress) { + //长按手势 + if (!_longPress) { + _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:view action:@selector(gx_handleGesture:)]; + _longPress.delegate = self; + [view addGestureRecognizer:_longPress]; + } + } else { + //tap手势 + if (!_tap) { + _tap = [[UITapGestureRecognizer alloc] initWithTarget:view action:@selector(gx_handleGesture:)]; + _tap.delegate = self; + [view addGestureRecognizer:_tap]; } } + } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { @@ -564,21 +588,7 @@ - (void)configureStyleInfo:(NSDictionary *)styleInfo{ -#pragma mark -视图出现/消失 & 埋点 -- (void)onAppear{ - self.isAppear = YES; - [self manualExposureTrackEvent]; - for (GXNode *node in self.children) { - [node onAppear]; - } -} - -- (void)onDisappear{ - self.isAppear = NO; - for (GXNode *node in self.children) { - [node onDisappear]; - } -} +#pragma mark - 埋点 - (void)manualClickTrackEvent{ GXTrack *track = self.associatedView.gxTrack; @@ -601,4 +611,54 @@ - (void)manualExposureTrackEvent{ } +@end + +@implementation GXNode(JS) + +- (void)onReady{ + //调用js事件 + if (_jsComponent) { + //区分首次 + if (!_isReady) { + _isReady = YES; + [_jsComponent onReady]; + } else { + [_jsComponent onReuse]; + } + } +} + +- (void)onShow{ + //处理JS + if (_jsComponent) { + [_jsComponent onShow]; + } + + //分发子节点(透传子节点,处理曝光) + self.isAppear = YES; + [self manualExposureTrackEvent]; + for (GXNode *node in self.children) { + [node onShow]; + } +} + +- (void)onHide{ + //处理JS + if (_jsComponent) { + [_jsComponent onHide]; + } + + //分发子节点 + self.isAppear = NO; + for (GXNode *node in self.children) { + [node onHide]; + } +} + +- (void)onDestroy{ + if (_jsComponent) { + [_jsComponent onDestroy]; + } +} + @end diff --git a/GaiaXiOS/Podfile b/GaiaXiOS/Podfile index ba3ca5aec..7a22ae093 100644 --- a/GaiaXiOS/Podfile +++ b/GaiaXiOS/Podfile @@ -17,6 +17,9 @@ target 'GaiaXiOS' do # 曲线动画 pod 'GaiaMotionCurve' + pod 'GaiaXJS', :path =>'../GaiaXJSiOS' + pod 'GaiaXSocket', :path => '../GaiaXSocketiOS' + end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj b/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj index de148482e..f5434d561 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj +++ b/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 269C88802213603DA9119E06 /* libPods-GaiaXiOSDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A666F1BF3AB1AB58DEEDEE8 /* libPods-GaiaXiOSDemo.a */; }; 8D0210DD278F1FF10032958A /* GaiaXPreviewTemplateSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D0210DC278F1FF10032958A /* GaiaXPreviewTemplateSource.m */; }; - 8D1FD1B0279E833D00835648 /* GaiaXScanView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D1FD1AF279E833D00835648 /* GaiaXScanView.m */; }; 8D2180DE2771AA98001401C8 /* NormalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2180DD2771AA98001401C8 /* NormalViewController.m */; }; 8D2180E12771AAA5001401C8 /* NestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2180E02771AAA5001401C8 /* NestViewController.m */; }; 8D2180E42771AAB2001401C8 /* ContainerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D2180E32771AAB2001401C8 /* ContainerViewController.m */; }; @@ -25,10 +24,7 @@ 8D5D29B0276AD6A1005FD699 /* uper.json in Resources */ = {isa = PBXBuildFile; fileRef = 8D5D29AB276AD6A1005FD699 /* uper.json */; }; 8D7570F828D0AF2A004AF92D /* RecycleListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7570F528D0AF2A004AF92D /* RecycleListViewController.m */; }; 8D7570F928D0AF2A004AF92D /* RecycleTemplateListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7570F728D0AF2A004AF92D /* RecycleTemplateListCell.m */; }; - 8D88D4C22788349F004F1614 /* GaiaXJSONRPCConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D88D4C12788349F004F1614 /* GaiaXJSONRPCConstants.m */; }; - 8D88D4C5278834AF004F1614 /* GaiaXSocketRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D88D4C3278834AF004F1614 /* GaiaXSocketRequest.m */; }; 8D88D4C927883574004F1614 /* GaiaXPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D88D4C827883574004F1614 /* GaiaXPreviewViewController.m */; }; - 8D88D4CC27883587004F1614 /* GaiaXSocketClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D88D4CB27883587004F1614 /* GaiaXSocketClient.m */; }; 8DA5D7AD275F40DF000182C9 /* GaiaXEmptyFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DA5D7AC275F40DF000182C9 /* GaiaXEmptyFile.swift */; }; 8DA5D7B0275F411A000182C9 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DA5D7AF275F411A000182C9 /* libsqlite3.tbd */; }; 8DA5D7B2275F417F000182C9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DA5D7B1275F417F000182C9 /* libz.tbd */; }; @@ -44,16 +40,23 @@ 8DC8F0412770A804003F5073 /* GaiaXHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DC8F0402770A804003F5073 /* GaiaXHelper.m */; }; 8DDC0A8327D06512008CB84C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8DDC0A8527D06512008CB84C /* Localizable.strings */; }; 8DDC0A8927D06949008CB84C /* FunctionList.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8DDC0A8B27D06949008CB84C /* FunctionList.plist */; }; - 8DE156C2278C5CD300E1AA68 /* GaiaXScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8DE156C1278C5CD300E1AA68 /* GaiaXScanViewController.m */; }; 9D573E2E2941D94400BDF713 /* StyleViewConotroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D573E2D2941D94400BDF713 /* StyleViewConotroller.m */; }; + BD7C2DAA29A4E7F400838273 /* GaiaXJSSwiftExampleModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DA629A4E7F400838273 /* GaiaXJSSwiftExampleModule.swift */; }; + BD7C2DAB29A4E7F400838273 /* GaiaXJSExampleModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DA729A4E7F400838273 /* GaiaXJSExampleModule.m */; }; + BD7C2DAC29A4E7F400838273 /* GaiaXJSSwiftExampleModule.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DA929A4E7F400838273 /* GaiaXJSSwiftExampleModule.m */; }; + BD7C2DAF29A4E81C00838273 /* JSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DAD29A4E81C00838273 /* JSViewController.m */; }; + BD7C2DCB29A4E9C400838273 /* GaiaXScanView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DBD29A4E9C400838273 /* GaiaXScanView.m */; }; + BD7C2DCC29A4E9C400838273 /* GaiaXScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DBE29A4E9C400838273 /* GaiaXScanViewController.m */; }; + BD7C2DCD29A4E9C400838273 /* GaiaXCommandCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DC329A4E9C400838273 /* GaiaXCommandCenter.m */; }; + BD7C2DCE29A4E9C400838273 /* GaiaXDevTools.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DC429A4E9C400838273 /* GaiaXDevTools.m */; }; + BD7C2DCF29A4E9C400838273 /* GaiaXSocketToastView.m in Sources */ = {isa = PBXBuildFile; fileRef = BD7C2DC629A4E9C400838273 /* GaiaXSocketToastView.m */; }; + BD7C2DD129A5B54000838273 /* gx-with-js.json in Resources */ = {isa = PBXBuildFile; fileRef = BD7C2DD029A5B54000838273 /* gx-with-js.json */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 8580D0337E7D6E56B21F09AC /* Pods-GaiaXiOSDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXiOSDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-GaiaXiOSDemo/Pods-GaiaXiOSDemo.debug.xcconfig"; sourceTree = ""; }; 8D0210DB278F1FF10032958A /* GaiaXPreviewTemplateSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXPreviewTemplateSource.h; sourceTree = ""; }; 8D0210DC278F1FF10032958A /* GaiaXPreviewTemplateSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXPreviewTemplateSource.m; sourceTree = ""; }; - 8D1FD1AE279E833D00835648 /* GaiaXScanView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXScanView.h; sourceTree = ""; }; - 8D1FD1AF279E833D00835648 /* GaiaXScanView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXScanView.m; sourceTree = ""; }; 8D2180DC2771AA98001401C8 /* NormalViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NormalViewController.h; sourceTree = ""; }; 8D2180DD2771AA98001401C8 /* NormalViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NormalViewController.m; sourceTree = ""; }; 8D2180DF2771AAA5001401C8 /* NestViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NestViewController.h; sourceTree = ""; }; @@ -79,14 +82,8 @@ 8D7570F528D0AF2A004AF92D /* RecycleListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecycleListViewController.m; sourceTree = ""; }; 8D7570F628D0AF2A004AF92D /* RecycleTemplateListCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecycleTemplateListCell.h; sourceTree = ""; }; 8D7570F728D0AF2A004AF92D /* RecycleTemplateListCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecycleTemplateListCell.m; sourceTree = ""; }; - 8D88D4C02788349F004F1614 /* GaiaXJSONRPCConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSONRPCConstants.h; sourceTree = ""; }; - 8D88D4C12788349F004F1614 /* GaiaXJSONRPCConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSONRPCConstants.m; sourceTree = ""; }; - 8D88D4C3278834AF004F1614 /* GaiaXSocketRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketRequest.m; sourceTree = ""; }; - 8D88D4C4278834AF004F1614 /* GaiaXSocketRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketRequest.h; sourceTree = ""; }; 8D88D4C727883574004F1614 /* GaiaXPreviewViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXPreviewViewController.h; sourceTree = ""; }; 8D88D4C827883574004F1614 /* GaiaXPreviewViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXPreviewViewController.m; sourceTree = ""; }; - 8D88D4CA27883587004F1614 /* GaiaXSocketClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketClient.h; sourceTree = ""; }; - 8D88D4CB27883587004F1614 /* GaiaXSocketClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketClient.m; sourceTree = ""; }; 8DA5D7AB275F40DF000182C9 /* GaiaXiOSDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GaiaXiOSDemo-Bridging-Header.h"; sourceTree = ""; }; 8DA5D7AC275F40DF000182C9 /* GaiaXEmptyFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GaiaXEmptyFile.swift; sourceTree = ""; }; 8DA5D7AF275F411A000182C9 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; @@ -115,12 +112,28 @@ 8DDC0A8827D06882008CB84C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; }; 8DDC0A8A27D06949008CB84C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = en; path = en.lproj/FunctionList.plist; sourceTree = ""; }; 8DDC0A8C27D0694E008CB84C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "zh-Hans"; path = "zh-Hans.lproj/FunctionList.plist"; sourceTree = ""; }; - 8DE156C0278C5CD300E1AA68 /* GaiaXScanViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GaiaXScanViewController.h; sourceTree = ""; }; - 8DE156C1278C5CD300E1AA68 /* GaiaXScanViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiaXScanViewController.m; sourceTree = ""; }; 9A666F1BF3AB1AB58DEEDEE8 /* libPods-GaiaXiOSDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-GaiaXiOSDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 9D573E2D2941D94400BDF713 /* StyleViewConotroller.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StyleViewConotroller.m; sourceTree = ""; }; 9D573E2F2941D97B00BDF713 /* StyleViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StyleViewController.h; sourceTree = ""; }; B80658C1C14A90166664E38A /* Pods-GaiaXiOSDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXiOSDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-GaiaXiOSDemo/Pods-GaiaXiOSDemo.release.xcconfig"; sourceTree = ""; }; + BD7C2DA629A4E7F400838273 /* GaiaXJSSwiftExampleModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GaiaXJSSwiftExampleModule.swift; sourceTree = ""; }; + BD7C2DA729A4E7F400838273 /* GaiaXJSExampleModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSExampleModule.m; sourceTree = ""; }; + BD7C2DA829A4E7F400838273 /* GaiaXJSExampleModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXJSExampleModule.h; sourceTree = ""; }; + BD7C2DA929A4E7F400838273 /* GaiaXJSSwiftExampleModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXJSSwiftExampleModule.m; sourceTree = ""; }; + BD7C2DAD29A4E81C00838273 /* JSViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSViewController.m; sourceTree = ""; }; + BD7C2DAE29A4E81C00838273 /* JSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSViewController.h; sourceTree = ""; }; + BD7C2DB429A4E9C400838273 /* GaiaXTemplateSourceInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXTemplateSourceInterface.h; sourceTree = ""; }; + BD7C2DBD29A4E9C400838273 /* GaiaXScanView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXScanView.m; sourceTree = ""; }; + BD7C2DBE29A4E9C400838273 /* GaiaXScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXScanViewController.m; sourceTree = ""; }; + BD7C2DBF29A4E9C400838273 /* GaiaXScanView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXScanView.h; sourceTree = ""; }; + BD7C2DC029A4E9C400838273 /* GaiaXScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXScanViewController.h; sourceTree = ""; }; + BD7C2DC229A4E9C400838273 /* GaiaXSocketToastView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXSocketToastView.h; sourceTree = ""; }; + BD7C2DC329A4E9C400838273 /* GaiaXCommandCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXCommandCenter.m; sourceTree = ""; }; + BD7C2DC429A4E9C400838273 /* GaiaXDevTools.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXDevTools.m; sourceTree = ""; }; + BD7C2DC529A4E9C400838273 /* GaiaXCommandCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXCommandCenter.h; sourceTree = ""; }; + BD7C2DC629A4E9C400838273 /* GaiaXSocketToastView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GaiaXSocketToastView.m; sourceTree = ""; }; + BD7C2DC729A4E9C400838273 /* GaiaXDevTools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GaiaXDevTools.h; sourceTree = ""; }; + BD7C2DD029A5B54000838273 /* gx-with-js.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "gx-with-js.json"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -140,6 +153,9 @@ 8D2180D82771AA5C001401C8 /* Render */ = { isa = PBXGroup; children = ( + BD7C2DAE29A4E81C00838273 /* JSViewController.h */, + BD7C2DAD29A4E81C00838273 /* JSViewController.m */, + BD7C2DA529A4E7F400838273 /* NativeModules */, 8D2180DF2771AAA5001401C8 /* NestViewController.h */, 8D2180E02771AAA5001401C8 /* NestViewController.m */, 8D2180DC2771AA98001401C8 /* NormalViewController.h */, @@ -177,6 +193,7 @@ 8DDC0A8B27D06949008CB84C /* FunctionList.plist */, 8D5D29AB276AD6A1005FD699 /* uper.json */, 8D5D29AA276AD6A1005FD699 /* uper-top.json */, + BD7C2DD029A5B54000838273 /* gx-with-js.json */, 8D57F1D1277300DF00FF8CC3 /* multi-scroll.json */, 8D5D29A9276AD6A1005FD699 /* recommend.json */, 8DC6060D2772D1F200BACC09 /* vertical-item.json */, @@ -190,29 +207,17 @@ 8D88D4BD2788348F004F1614 /* Preview */ = { isa = PBXGroup; children = ( - 8DE156CA278D20BD00E1AA68 /* Scan */, + BD7C2DC129A4E9C400838273 /* DevTools */, + BD7C2DBC29A4E9C400838273 /* Scan */, + BD7C2DB429A4E9C400838273 /* GaiaXTemplateSourceInterface.h */, 8D88D4C727883574004F1614 /* GaiaXPreviewViewController.h */, 8D88D4C827883574004F1614 /* GaiaXPreviewViewController.m */, 8D0210DB278F1FF10032958A /* GaiaXPreviewTemplateSource.h */, 8D0210DC278F1FF10032958A /* GaiaXPreviewTemplateSource.m */, - 8D88D4C627883511004F1614 /* SocketClient */, ); path = Preview; sourceTree = ""; }; - 8D88D4C627883511004F1614 /* SocketClient */ = { - isa = PBXGroup; - children = ( - 8D88D4CA27883587004F1614 /* GaiaXSocketClient.h */, - 8D88D4CB27883587004F1614 /* GaiaXSocketClient.m */, - 8D88D4C4278834AF004F1614 /* GaiaXSocketRequest.h */, - 8D88D4C3278834AF004F1614 /* GaiaXSocketRequest.m */, - 8D88D4C02788349F004F1614 /* GaiaXJSONRPCConstants.h */, - 8D88D4C12788349F004F1614 /* GaiaXJSONRPCConstants.m */, - ); - path = SocketClient; - sourceTree = ""; - }; 8DB52172275A0DCF00EB8126 = { isa = PBXGroup; children = ( @@ -258,17 +263,6 @@ path = GaiaXiOSDemo; sourceTree = ""; }; - 8DE156CA278D20BD00E1AA68 /* Scan */ = { - isa = PBXGroup; - children = ( - 8DE156C0278C5CD300E1AA68 /* GaiaXScanViewController.h */, - 8DE156C1278C5CD300E1AA68 /* GaiaXScanViewController.m */, - 8D1FD1AE279E833D00835648 /* GaiaXScanView.h */, - 8D1FD1AF279E833D00835648 /* GaiaXScanView.m */, - ); - path = Scan; - sourceTree = ""; - }; BADDA2347CA93853E7C3628B /* Frameworks */ = { isa = PBXGroup; children = ( @@ -281,6 +275,41 @@ name = Frameworks; sourceTree = ""; }; + BD7C2DA529A4E7F400838273 /* NativeModules */ = { + isa = PBXGroup; + children = ( + BD7C2DA829A4E7F400838273 /* GaiaXJSExampleModule.h */, + BD7C2DA729A4E7F400838273 /* GaiaXJSExampleModule.m */, + BD7C2DA929A4E7F400838273 /* GaiaXJSSwiftExampleModule.m */, + BD7C2DA629A4E7F400838273 /* GaiaXJSSwiftExampleModule.swift */, + ); + path = NativeModules; + sourceTree = ""; + }; + BD7C2DBC29A4E9C400838273 /* Scan */ = { + isa = PBXGroup; + children = ( + BD7C2DBF29A4E9C400838273 /* GaiaXScanView.h */, + BD7C2DBD29A4E9C400838273 /* GaiaXScanView.m */, + BD7C2DC029A4E9C400838273 /* GaiaXScanViewController.h */, + BD7C2DBE29A4E9C400838273 /* GaiaXScanViewController.m */, + ); + path = Scan; + sourceTree = ""; + }; + BD7C2DC129A4E9C400838273 /* DevTools */ = { + isa = PBXGroup; + children = ( + BD7C2DC529A4E9C400838273 /* GaiaXCommandCenter.h */, + BD7C2DC329A4E9C400838273 /* GaiaXCommandCenter.m */, + BD7C2DC729A4E9C400838273 /* GaiaXDevTools.h */, + BD7C2DC429A4E9C400838273 /* GaiaXDevTools.m */, + BD7C2DC229A4E9C400838273 /* GaiaXSocketToastView.h */, + BD7C2DC629A4E9C400838273 /* GaiaXSocketToastView.m */, + ); + path = DevTools; + sourceTree = ""; + }; E7EF62B3BAD2B05C5011EBA1 /* Pods */ = { isa = PBXGroup; children = ( @@ -301,6 +330,7 @@ 8DB52177275A0DCF00EB8126 /* Sources */, 8DB52178275A0DCF00EB8126 /* Frameworks */, 8DB52179275A0DCF00EB8126 /* Resources */, + 5DA9A3EB6A9C60809124B614 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -354,6 +384,7 @@ 8D5D29AF276AD6A1005FD699 /* uper-top.json in Resources */, 8DB5218B275A0DD200EB8126 /* Assets.xcassets in Resources */, 8DB52189275A0DCF00EB8126 /* Main.storyboard in Resources */, + BD7C2DD129A5B54000838273 /* gx-with-js.json in Resources */, 8D57F1D4277312A300FF8CC3 /* subscribe-item.json in Resources */, 8D5D29B0276AD6A1005FD699 /* uper.json in Resources */, 8D5D29AD276AD6A1005FD699 /* horizontal-item.json in Resources */, @@ -368,6 +399,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 5DA9A3EB6A9C60809124B614 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-GaiaXiOSDemo/Pods-GaiaXiOSDemo-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-GaiaXiOSDemo/Pods-GaiaXiOSDemo-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-GaiaXiOSDemo/Pods-GaiaXiOSDemo-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; B26DE67764C534DA904A83BC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -397,29 +445,33 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D88D4C22788349F004F1614 /* GaiaXJSONRPCConstants.m in Sources */, + BD7C2DCC29A4E9C400838273 /* GaiaXScanViewController.m in Sources */, + BD7C2DAF29A4E81C00838273 /* JSViewController.m in Sources */, + BD7C2DCE29A4E9C400838273 /* GaiaXDevTools.m in Sources */, 8D2180E12771AAA5001401C8 /* NestViewController.m in Sources */, 8D7570F828D0AF2A004AF92D /* RecycleListViewController.m in Sources */, 8D7570F928D0AF2A004AF92D /* RecycleTemplateListCell.m in Sources */, 8D88D4C927883574004F1614 /* GaiaXPreviewViewController.m in Sources */, 8DB52186275A0DCF00EB8126 /* ViewController.m in Sources */, + BD7C2DCD29A4E9C400838273 /* GaiaXCommandCenter.m in Sources */, 8D57F1DA2773412700FF8CC3 /* TemplateListCell.m in Sources */, + BD7C2DCB29A4E9C400838273 /* GaiaXScanView.m in Sources */, 8D57F1D727733F0B00FF8CC3 /* ListViewController.m in Sources */, + BD7C2DAA29A4E7F400838273 /* GaiaXJSSwiftExampleModule.swift in Sources */, + BD7C2DAB29A4E7F400838273 /* GaiaXJSExampleModule.m in Sources */, 8D2180E42771AAB2001401C8 /* ContainerViewController.m in Sources */, + BD7C2DCF29A4E9C400838273 /* GaiaXSocketToastView.m in Sources */, 8DB52180275A0DCF00EB8126 /* AppDelegate.m in Sources */, - 8D88D4CC27883587004F1614 /* GaiaXSocketClient.m in Sources */, 8D2180E72771AAC3001401C8 /* DataViewController.m in Sources */, + BD7C2DAC29A4E7F400838273 /* GaiaXJSSwiftExampleModule.m in Sources */, 8DA5D7AD275F40DF000182C9 /* GaiaXEmptyFile.swift in Sources */, 8DB52191275A0DD200EB8126 /* main.m in Sources */, 8D0210DD278F1FF10032958A /* GaiaXPreviewTemplateSource.m in Sources */, - 8DE156C2278C5CD300E1AA68 /* GaiaXScanViewController.m in Sources */, 8DC8F0412770A804003F5073 /* GaiaXHelper.m in Sources */, 8DB52183275A0DCF00EB8126 /* SceneDelegate.m in Sources */, - 8D1FD1B0279E833D00835648 /* GaiaXScanView.m in Sources */, 8D2180DE2771AA98001401C8 /* NormalViewController.m in Sources */, 8D2180EA2771AACD001401C8 /* EventViewController.m in Sources */, 9D573E2E2941D94400BDF713 /* StyleViewConotroller.m in Sources */, - 8D88D4C5278834AF004F1614 /* GaiaXSocketRequest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -591,7 +643,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = VY8F8V9AUC; + DEVELOPMENT_TEAM = W4ZRQF48G9; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -663,7 +715,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = VY8F8V9AUC; + DEVELOPMENT_TEAM = W4ZRQF48G9; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; diff --git a/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate b/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..031caff40 Binary files /dev/null and b/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 000000000..2fb6710f7 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Base.lproj/Main.storyboard b/GaiaXiOSDemo/GaiaXiOSDemo/Base.lproj/Main.storyboard index b9eae6f10..df1d1dc6a 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Base.lproj/Main.storyboard +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -14,7 +14,7 @@ - + @@ -36,13 +36,7 @@ - - - - - - - + diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.h new file mode 100644 index 000000000..cc022e9ef --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.h @@ -0,0 +1,26 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXCommandCenter : NSObject + ++ (instancetype)sharedInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.m new file mode 100644 index 000000000..a8dabc9d8 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.m @@ -0,0 +1,138 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import "GaiaXCommandCenter.h" +#import +#import "GaiaXSocketToastView.h" +#import +#import "GaiaXScanViewController.h" + +@implementation GaiaXCommandCenter + + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static GaiaXCommandCenter *commandCenter = nil; + dispatch_once(&onceToken, ^{ + commandCenter = [[GaiaXCommandCenter alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:commandCenter selector:@selector(openSaoYiSao:) name:@"GAIAX_SOCKET_COMMAND_OPEN_SAOYISAO" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:commandCenter selector:@selector(closeSocketConnect:) name:@"GAIAX_SOCKET_COMMAND_CLOSE_SOCKET_CONNECT" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:commandCenter selector:@selector(socketConnectStateConnected:) name:@"GAIAX_SOCKET_CONNECT_STATE_CONNECTED" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:commandCenter selector:@selector(commandAction:) name:@"GAIAX_SOCKET_COMMAND" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:commandCenter selector:@selector(updatedAction:) name:@"GAIAX_TEMPLATES_UPDATED_LIST" object:nil]; + }); + return commandCenter; +} + +- (void)commandAction:(NSNotification *)notify { + NSDictionary *userInfo = notify.userInfo; + if (userInfo) { + if ([userInfo[@"type"] isEqualToString:@"preview"]) { + + } else if ([userInfo[@"type"] isEqualToString:@"js"]) { + if ([userInfo[@"action"] isEqualToString:@"open"]) { + [GaiaXJSConfig setBreakPointDebuggingEnabled:YES]; + GaiaXSocketToastView *toastView = [[GaiaXSocketToastView alloc] init]; + [toastView showToastWithTitle:@"GaiaX DevTools【GaiaXJS 断点调试】模式已打开" messages:nil]; + [self setLastJSDebuggerMode:@"breakpoint"]; + } else if ([userInfo[@"action"] isEqualToString:@"close"]) { + [GaiaXJSConfig setBreakPointDebuggingEnabled:NO]; + GaiaXSocketToastView *toastView = [[GaiaXSocketToastView alloc] init]; + [toastView showToastWithTitle:@"GaiaX DevTools【GaiaXJS 断点调试】模式已关闭" messages:nil]; + [self setLastJSDebuggerMode:nil]; + } + } + } +} + +- (void)updatedAction:(NSNotification *)notify { + NSDictionary *userInfo = notify.userInfo; + if (userInfo) { + NSArray *list = userInfo[@"ids"]; + if (list && list.count > 0) { + GaiaXSocketToastView *toastView = [[GaiaXSocketToastView alloc] init]; + [toastView showToastWithTitle:@"推送成功( GaiaX DevTools )" messages:list]; + } + } +} + +- (void)openSaoYiSao:(NSNotification *)notify { + UIViewController *vc = [[GaiaXScanViewController alloc] init]; + vc.title = NSLocalizedString(@"fastpreview", nil); + [(UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController pushViewController:vc animated:YES]; +} + +- (void)closeSocketConnect:(NSNotification *)notify { + GaiaXSocketManager *manager = [GaiaXSocketManager sharedInstance]; + GaiaXSocketClient *socketClient = [manager socketClient]; + [socketClient sendeNotification:[GaiaXSocketModel notificationWithMethod:@"close" params:nil]]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [manager disconnect]; + }); +} + +- (void)socketConnectStateConnected:(NSNotification *)notify { + GaiaXSocketClient *socketClient = [[GaiaXSocketManager sharedInstance] socketClient]; + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + dict[@"version"] = @"2.0"; + dict[@"deviceName"] = [UIDevice currentDevice].name; + dict[@"deviceMode"] = [UIDevice currentDevice].model; + dict[@"systemName"] = [UIDevice currentDevice].systemName; + dict[@"systemVersion"] = [UIDevice currentDevice].systemVersion; + [socketClient sendRequest:[GaiaXSocketModel requestWithMethod:@"initialized" params:dict] callback:^(GaiaXSocketModel * _Nonnull response) { + GaiaXSocketToastView *toastView = [[GaiaXSocketToastView alloc] init]; + [toastView showToastWithTitle:@"GaiaX DevTools 已成功连接到 Gaia Studio" messages:nil]; + }]; +} + + +- (NSString *)getLastPreviewMode { + NSString *result = @"none"; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults objectForKey:@"GAIAX_LAST_PREVIEW_MODE"] != nil) { + result = [defaults stringForKey:@"GAIAX_LAST_PREVIEW_MODE"]; + } + return result; +} + + +- (void)setLastPreviewMode:(NSString *)mode { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if(mode == nil) { + [defaults removeObjectForKey:@"GAIAX_LAST_PREVIEW_MODE"]; + } else { + [defaults setObject:mode forKey:@"GAIAX_LAST_PREVIEW_MODE"]; + } +} + +- (NSString *)getLastJSDebuggerMode { + NSString *result = @"default"; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults objectForKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"] != nil) { + result = [defaults stringForKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"]; + } + return result; +} + +- (void)setLastJSDebuggerMode:(NSString *)mode { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if(mode == nil) { + [defaults removeObjectForKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"]; + } else { + [defaults setObject:mode forKey:@"GAIAX_JS_LAST_DEBUGGER_MODE"]; + } +} + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.h new file mode 100644 index 000000000..70ae71a71 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.h @@ -0,0 +1,30 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + + +@interface GaiaXDevTools : UIView + ++ (instancetype)sharedInstance; + ++ (void)show; + ++ (void)dismiss; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.m new file mode 100644 index 000000000..e20952701 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.m @@ -0,0 +1,215 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import "GaiaXDevTools.h" +#import "GaiaXPreviewViewController.h" +#import +#import + +@interface GaiaXDevTools () + +@property (nonatomic, strong) UILabel *tipLabel; +@property (nonatomic, strong) UIAlertController* alertController; +@property (nonatomic, assign) GaiaXSocketStatus socketStatus; +@property (nonatomic, strong) NSTimer *checkStatusTimer; + +@end + +@implementation GaiaXDevTools + +- (void)setSocketStatus:(GaiaXSocketStatus)socketStatus { + _socketStatus = socketStatus; + if (socketStatus == GaiaXSocketStatusDefault) { + self.tipLabel.text = @"GaiaX DevTools 等待连接到 Gaia Studio..."; + self.tipLabel.textColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5]; + self.backgroundColor = [UIColor colorWithRed:245/255.0 green:168/255.0 blue:35/255.0 alpha:1]; + } else if (socketStatus == GaiaXSocketStatusConnect) { + self.tipLabel.text = @"GaiaX DevTools 已连接到 Gaia Studio"; + self.backgroundColor = [UIColor colorWithRed:41/255.0 green:142/255.0 blue:70/255.0 alpha:1]; + self.tipLabel.textColor = [UIColor whiteColor]; + } else if (socketStatus == GaiaXSocketStatusDisConnect) { + self.tipLabel.text = @"GaiaX DevTools 已与 Gaia Studio 断开"; + self.tipLabel.textColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5]; + self.backgroundColor = [UIColor redColor]; + } +} + ++ (instancetype)sharedInstance { + static GaiaXDevTools *devTool = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + devTool = [[GaiaXDevTools alloc] initWithFrame:CGRectMake(0,0, UIScreen.mainScreen.bounds.size.width, [self statusBarHeight]+20)]; + [devTool addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:devTool action:@selector(tapAction:)]]; + devTool.tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, [self statusBarHeight], devTool.bounds.size.width, 20)]; + devTool.tipLabel.textAlignment = NSTextAlignmentCenter; + devTool.tipLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightBold]; + + devTool.socketStatus = [[GaiaXSocketManager sharedInstance] socketClient].socketStatus; + [devTool addSubview:devTool.tipLabel]; + }); + return devTool; +} + + ++ (NSInteger)statusBarHeight { + if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) { + return 20; + } + return [self isLiuHaiPing] ? 44 : 20; +} + + ++ (BOOL)isLiuHaiPing { + if (UIUserInterfaceIdiomPhone != UI_USER_INTERFACE_IDIOM()) { + return NO; + } + //iOS11,判断底部的inset + BOOL result = NO; + if (@available(iOS 11.0, *)) { + UIWindow *mainWindow = [[UIApplication sharedApplication] keyWindow]; + if (mainWindow.safeAreaInsets.bottom > 0.0) { + result = YES; + } + } + return result; +} + + +- (void)tapAction:(UITapGestureRecognizer *)gesture { + + BOOL socketDidConnect = self.socketStatus == GaiaXSocketStatusConnect; + + self.alertController = [UIAlertController alertControllerWithTitle:@"GaiaX DevTools" + message:@"支持【多合一模式】" + preferredStyle:UIAlertControllerStyleActionSheet]; + self.alertController.popoverPresentationController.sourceView = gesture.view; + self.alertController.popoverPresentationController.sourceRect = gesture.view.bounds; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + UIAlertAction *closeAction = [UIAlertAction actionWithTitle:@"关闭 GaiaX DevTools" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [GaiaXDevTools dismiss]; + }]; + + UIAlertAction *connectToAction = nil; + if (socketDidConnect) { + connectToAction = [UIAlertAction actionWithTitle:@"断开连接【Gaia Studio】" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_SOCKET_COMMAND_CLOSE_SOCKET_CONNECT" object:nil userInfo:nil]; + }]; + } else { + connectToAction = [UIAlertAction actionWithTitle:@"扫码连接到【Gaia Studio】" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_SOCKET_COMMAND_OPEN_SAOYISAO" object:nil userInfo:nil]; + }]; + } + + UINavigationController *currentViewController = (UINavigationController *)[UIApplication sharedApplication].keyWindow.rootViewController; + UIAlertAction *preivewAction = nil; + if ([currentViewController.topViewController isKindOfClass:[GaiaXPreviewViewController class]]) { + preivewAction = [UIAlertAction actionWithTitle:@"关闭【实时预览】" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + GaiaXPreviewViewController *controller = [[GaiaXPreviewViewController alloc] initWithNibName:nil bundle:nil]; + controller.hidesBottomBarWhenPushed = YES; + [currentViewController popViewControllerAnimated:YES]; + }]; + } else { + preivewAction = [UIAlertAction actionWithTitle:@"打开【实时预览】" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + GaiaXPreviewViewController *controller = [[GaiaXPreviewViewController alloc] initWithNibName:nil bundle:nil]; + [currentViewController pushViewController:controller animated:YES]; + }]; + preivewAction.enabled = socketDidConnect; + } + + + UIAlertAction *jsBreakpointAction = nil; + if ([GaiaXJSConfig isBreakPointDebugging]) { + jsBreakpointAction = [UIAlertAction actionWithTitle:@"关闭 GaiaXJS【断点调试】模式" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_SOCKET_COMMAND" object:nil userInfo:@{@"action": @"close", @"type" : @"js" , @"subType": @"breakpoint"}]; + }]; + } else { + jsBreakpointAction = [UIAlertAction actionWithTitle:@"打开 GaiaXJS【断点调试】模式" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_SOCKET_COMMAND" object:nil userInfo:@{@"action": @"open", @"type" : @"js" , @"subType": @"breakpoint"}]; + }]; + jsBreakpointAction.enabled = socketDidConnect; + } + + + [self.alertController addAction:cancelAction]; + [self.alertController addAction:connectToAction]; + [self.alertController addAction:preivewAction]; + [self.alertController addAction:jsBreakpointAction]; + [self.alertController addAction:closeAction]; + [[[UIApplication sharedApplication] windows][0].rootViewController presentViewController:self.alertController animated:YES completion:^{ + + }]; +} + ++ (void)show { + GaiaXDevTools *devTool = [GaiaXDevTools sharedInstance]; + if (devTool.superview == nil) { + [[[UIApplication sharedApplication] windows][0] addSubview:devTool]; + } else { + [devTool removeFromSuperview]; + [[[UIApplication sharedApplication] windows][0] addSubview:devTool]; + } + if ([devTool.checkStatusTimer isValid]) { + [devTool.checkStatusTimer invalidate]; + devTool.checkStatusTimer = nil; + } + devTool.checkStatusTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:devTool selector:@selector(checkStatus) userInfo:nil repeats:YES]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_DEVTOOLS_DID_OPENED" object:nil userInfo:nil]; +} + +- (void)checkStatus { + if (self.socketStatus != [[GaiaXSocketManager sharedInstance] socketClient].socketStatus) { + self.socketStatus = [[GaiaXSocketManager sharedInstance] socketClient].socketStatus; + [self.alertController dismissViewControllerAnimated:YES completion:^{ + + }]; + } +} + ++ (void)dismiss { + [[NSNotificationCenter defaultCenter] removeObserver:[GaiaXDevTools sharedInstance] name:@"GAIAX_SOCKET_CONNECT_STATE_CONNECTED" object:nil]; + [[GaiaXDevTools sharedInstance] removeFromSuperview]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"GAIAX_DEVTOOLS_SWITCH"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_DEVTOOLS_DID_CLOSED" object:nil userInfo:nil]; +} + ++ (UIViewController *)findCurrentViewController { + UIWindow *window = [[UIApplication sharedApplication].delegate window]; + UIViewController *topViewController = [window rootViewController]; + + while (true) { + + if (topViewController.presentedViewController) { + + topViewController = topViewController.presentedViewController; + + } else if ([topViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController*)topViewController topViewController]) { + + topViewController = [(UINavigationController *)topViewController topViewController]; + + } else if ([topViewController isKindOfClass:[UITabBarController class]]) { + + UITabBarController *tab = (UITabBarController *)topViewController; + topViewController = tab.selectedViewController; + + } else { + break; + } + } + return topViewController; +} + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.h new file mode 100644 index 000000000..0b68bbbc6 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.h @@ -0,0 +1,28 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXSocketToastView : UIView + + +- (void)showToastWithTitle:(NSString *)title + messages:(NSArray *)messages; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.m new file mode 100644 index 000000000..acb52e3e4 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.m @@ -0,0 +1,133 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import "GaiaXSocketToastView.h" + +@interface GaiaXSocketToastView () + +@property(nonatomic, strong) UIVisualEffectView *blurView; +@property(nonatomic, strong) UIView *seperatorView; +@property(nonatomic, strong) UILabel *titleLabel; +@property(nonatomic, strong) UILabel *timeLabel; +@property(nonatomic, strong) NSMutableArray *contents; +@property(nonatomic, assign) CGFloat maxWidth; + +@end + +@implementation GaiaXSocketToastView + +- (void)showToastWithTitle:(NSString *)title messages:(NSArray *)messages { + self.tag = 10201; + self.clipsToBounds = YES; + self.layer.cornerRadius = 10; + CGFloat maxWidth = 0; + + self.contents = [NSMutableArray array]; + UIBlurEffect *blurEffect = + [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + self.blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + self.blurView.backgroundColor = [UIColor colorWithRed:41 / 255.0 + green:142 / 255.0 + blue:70 / 255.0 + alpha:1]; + [self addSubview:self.blurView]; + + self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = [UIColor whiteColor]; + self.titleLabel.text = title; + NSDictionary *fontWithAttributes = + @{NSFontAttributeName : self.titleLabel.font}; + CGSize size = [self.titleLabel.text sizeWithAttributes:fontWithAttributes]; + maxWidth = MAX(size.width, maxWidth); + [self addSubview:self.titleLabel]; + + self.timeLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.timeLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightMedium]; + self.timeLabel.textAlignment = NSTextAlignmentLeft; + self.timeLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6]; + NSDate *now = [NSDate date]; + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + [formatter setDateFormat:@"yyyy/MM/dd HH:mm:ss"]; + self.timeLabel.text = + [NSString stringWithFormat:@"%@", [formatter stringFromDate:now]]; + NSDictionary *fontWithAttributes2 = + @{NSFontAttributeName : self.timeLabel.font}; + CGSize size2 = [self.timeLabel.text sizeWithAttributes:fontWithAttributes2]; + maxWidth = MAX(size2.width, maxWidth); + [self addSubview:self.timeLabel]; + + for (NSInteger i = 0; i < messages.count; i++) { + if (i == 0) { + self.seperatorView = [[UIView alloc] initWithFrame:CGRectZero]; + self.seperatorView.backgroundColor = + [[UIColor whiteColor] colorWithAlphaComponent:0.5]; + [self addSubview:self.seperatorView]; + } + UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; + label.font = [UIFont systemFontOfSize:13 weight:UIFontWeightMedium]; + label.textAlignment = NSTextAlignmentLeft; + label.textColor = [UIColor whiteColor]; + label.text = messages[i]; + [self.contents addObject:label]; + [self addSubview:label]; + NSDictionary *fontWithAttributes = @{NSFontAttributeName : label.font}; + CGSize size = [label.text sizeWithAttributes:fontWithAttributes]; + maxWidth = MAX(size.width, maxWidth); + } + self.maxWidth = maxWidth; + [self computeLayout]; + UIWindow *window = [UIApplication sharedApplication].keyWindow; + if ([window viewWithTag:10201] != nil) { + [[window viewWithTag:10201] removeFromSuperview]; + } + [window addSubview:self]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + [self removeFromSuperview]; + }); +} + +- (void)computeLayout { + CGFloat leftRightMargin = 12; + CGFloat width = self.maxWidth + 2 * leftRightMargin; + CGFloat height = 0; + CGFloat originY = 12; + CGFloat gap = 3; + self.titleLabel.frame = + CGRectMake(leftRightMargin, originY, self.maxWidth, 15); + originY += 15 + gap; + self.timeLabel.frame = + CGRectMake(leftRightMargin, originY, self.maxWidth, 13); + originY += 13 + gap; + self.seperatorView.frame = + CGRectMake(leftRightMargin, originY, self.maxWidth, 1); + originY += 1 + gap; + for (NSInteger i = 0; i < self.contents.count; i++) { + UILabel *label = self.contents[i]; + label.frame = CGRectMake(12, originY, self.maxWidth, 15); + originY += 15 + gap; + } + height = originY + 4; + + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + self.frame = + CGRectMake((window.bounds.size.width - width) / 2, + window.bounds.size.height - height - 100, width, height); + self.blurView.frame = self.bounds; +} + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.h index 51666b88c..48dd6c03c 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.h +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.h @@ -1,8 +1,4 @@ -// -// GaiaXPreviewTemplateSource.h -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. +// Copyright (c) 2023, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,7 +13,7 @@ // limitations under the License. #import -#import +#import "GXTemplateSourceProtocal.h" NS_ASSUME_NONNULL_BEGIN diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.m index b6d13026a..e67c3fc65 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.m +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewTemplateSource.m @@ -1,8 +1,4 @@ -// -// GaiaXPreviewTemplateSource.m -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. +// Copyright (c) 2023, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#import "GaiaXPreviewTemplateSource.h" +#import "GaiaXPreviewTemplateSource.h" +#import +#import "GXTemplateItem.h" @interface GaiaXPreviewTemplateSource () @property (nonatomic, strong) NSMutableDictionary *previewSource; diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.h index 401db71fd..a62b0c35d 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.h +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.h @@ -1,8 +1,4 @@ -// -// GaiaXPreviewViewController.h -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. +// Copyright (c) 2023, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,8 +18,7 @@ NS_ASSUME_NONNULL_BEGIN @interface GaiaXPreviewViewController : UIViewController -//初始化方法 -- (instancetype)initWithUrl:(NSString *)url; +@property (nonatomic, strong) NSString *templateId; @end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.m index e333b9fc6..6e33f711a 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.m +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXPreviewViewController.m @@ -1,8 +1,4 @@ -// -// GaiaXPreviewViewController.m -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. +// Copyright (c) 2023, Alibaba Group Holding Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,17 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. + #import "GaiaXPreviewViewController.h" #import "GaiaXPreviewTemplateSource.h" -#import "GaiaXSocketClient.h" +#import #import +#import #import "GaiaXHelper.h" -#define kScreenWidth [[UIScreen mainScreen] bounds].size.width -#define kScreenHeight [[UIScreen mainScreen] bounds].size.height +#define kScreenWidth [UIScreen mainScreen].bounds.size.width +#define kScreenHeight [UIScreen mainScreen].bounds.size.height #define kStatusBarHeight [[UIApplication sharedApplication] statusBarFrame].size.height -@interface GaiaXPreviewViewController () { +@interface GaiaXPreviewViewController (){ UIView *_rootView; NSDictionary *_mockData; GXTemplateItem *_templateItem; @@ -34,146 +32,151 @@ @interface GaiaXPreviewViewController () 0 ? (width - tmpWidth) / 2.f : 0; - CGRect frame = _rootView.frame; - frame.origin.y = 50; - frame.origin.x = x; - _rootView.frame = frame; -} - -//获取到嵌套模板 -- (void)gaiaXSocketClient:(GaiaXSocketClient *)client didReceiveNestedTemplateInfo:(NSDictionary *)templateInfo { - // 获取嵌套模板 - NSDictionary *package = nil; - NSString *templateId = [templateInfo gx_stringForKey:@"templateId"]; - NSString *indexJsonStr = [templateInfo gx_stringForKey:@"index.json"]; - NSDictionary *indexJsonDict = [NSDictionary gx_dictionaryFromJSONString:indexJsonStr]; - - //读取package信息 & 嵌套关系 - if ([GaiaXHelper isValidDictionary:indexJsonDict]) { - //处理模板数据 - [self handleTemlateInfo:templateInfo]; - //获取依赖关系 - package = [indexJsonDict gx_dictionaryForKey:@"package"]; - if (package) { - [self getNestedTemplate:package]; - } + CGRect frame = self.preview.frame; + frame.size.width = measureWidth; + frame.size.height = measureHeight+2*20; + frame.origin.x = (_artboardSize.width-measureWidth)/2; + frame.origin.y = (MAX(0, _artboardSize.height-measureHeight-2*20)) /5; + self.preview.frame = frame; + self.artboardView.frame = CGRectMake(0, 20, frame.size.width, frame.size.height-2*20); + if (updatedTemplates.count > 0) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"GAIAX_TEMPLATES_UPDATED_LIST" object:nil userInfo:@{@"ids": updatedTemplates}]; } - - //加入依赖关系,用于请求嵌套模板 - [self.dependenciesTemplateInfo gx_setObject:templateInfo forKey:templateId]; - - // 嵌套模板获取完毕,刷新预览View - [self gaiaXSocketClient:_client didReceiveTemplateInfo:_templateInfo]; -} - -//断开连接 -- (void)gaiaXSocketClientDidDisconnect:(GaiaXSocketClient *)client { - //清理缓存模板信息 & 预览模板 - [_previewTemplateSource clearPreviewTemplates]; - _dependenciesTemplateInfo = nil; - _previewTemplateSource = nil; } -#pragma mark - 嵌套模板 -- (void)getNestedTemplate:(NSDictionary *)package{ - NSDictionary *dependencies = package[@"dependencies"]; - if (dependencies && [dependencies isKindOfClass:[NSDictionary class]] && dependencies.count > 0) { - [dependencies enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - [self sendNestedTemplateToStudio:key]; - }]; - } -} - -- (void)sendNestedTemplateToStudio:(NSString *)templateId{ - if (![self.dependenciesTemplateInfo.allKeys containsObject:templateId]) { - GaiaXSocketRequest *request = [GaiaXSocketRequest requestWithRequestId:@(888) - Method:@"template/getTemplateData" - parameters:@{@"id":templateId}]; - [_client sendRequestToServer:request]; - } -} +#pragma mark - 请求嵌套模板 #pragma mark - 添加模板缓存,并处理mock数据 -- (void)handleTemlateInfo:(NSDictionary *)templateInfo{ - if ([GXUtils isValidDictionary:templateInfo]) { +- (void)handleTemlateId:(NSString *)templateId data:(NSDictionary *)templateInfo updatedTemplates:(NSMutableArray *)updatedTemplates{ + if ([GaiaXHelper isValidDictionary:templateInfo]) { //获取模板id - NSString *templateId = [templateInfo gx_stringForKey:@"templateId"]; if (templateId.length <= 0) { return; } @@ -282,12 +245,15 @@ - (void)handleTemlateInfo:(NSDictionary *)templateInfo{ BOOL isRoot = [templateId isEqualToString:_templateId]; //获取模板文件 + NSString *indexJSStr = [templateInfo gx_stringForKey:@"index.js"]; NSString *indexCssStr = [templateInfo gx_stringForKey:@"index.css"]; NSString *indexJsonStr = [templateInfo gx_stringForKey:@"index.json"]; NSString *indexMockStr = [templateInfo gx_stringForKey:@"index.mock"]; NSMutableDictionary *result = [NSMutableDictionary dictionary]; - // CSS样式解析 + //JS解析 + result[kGXComDef_KW_JS] = indexJSStr; + //CSS样式解析 result[kGXComDef_KW_SY] = [GXUtils parserStyleString:indexCssStr]; //视图层级解析 NSDictionary *indexJsonDict = [NSDictionary gx_dictionaryFromJSONString:indexJsonStr]; @@ -315,7 +281,7 @@ - (void)handleTemlateInfo:(NSDictionary *)templateInfo{ //容器模板 NSMutableArray *nodes = [NSMutableArray array]; for (int i = 0; i < 10; i++) { - [nodes addObject:@{@"value":@{@"data": @"'mock'"}}]; + [nodes addObject:@{@"data":@"mock"}]; } [dbDict gx_setObject:@{@"value":nodes} forKey:templateId]; @@ -323,7 +289,7 @@ - (void)handleTemlateInfo:(NSDictionary *)templateInfo{ //普通模板 NSDictionary *dependencies = [[indexJsonDict gx_dictionaryForKey:@"package"] gx_dictionaryForKey:@"dependencies"]; [dependencies enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - [dbDict gx_setObject:@{@"value":@{@"data": @"'mock'"}} forKey:key]; + [dbDict gx_setObject:@{@"data":@"mock"} forKey:key]; }]; } @@ -333,15 +299,28 @@ - (void)handleTemlateInfo:(NSDictionary *)templateInfo{ //获取数据源 if (isRoot) { - _mockData = @{@"value":@{@"data": @"'mock'"}}; + _mockData = @{@"data":@"mock"}; } } //添加到预览缓存池 [_previewTemplateSource addPreviewTemplate:result forTemplateId:templateId]; + [updatedTemplates addObject:templateId]; } } +#pragma mark - 侧滑 + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ + return [gestureRecognizer isKindOfClass:UIScreenEdgePanGestureRecognizer.class]; +} + + + @end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXTemplateSourceInterface.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXTemplateSourceInterface.h new file mode 100644 index 000000000..39bc588b0 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXTemplateSourceInterface.h @@ -0,0 +1,32 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import + +NS_ASSUME_NONNULL_BEGIN +//@class GaiaXTemplateItem; +@protocol GaiaXTemplateSourceInterface + +@required +// priority +//- (NSInteger)priority; +//获取预览的数据源 +//- (NSDictionary *)getTemplateInfoWithTemplateItem:(GaiaXTemplateItem *)templateItem; + +- (NSDictionary *)getTemplateInfoWithTemplateId:(NSString *)templateId; + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/Scan/GaiaXScanViewController.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/Scan/GaiaXScanViewController.m index 88b7c75eb..073c6147b 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/Scan/GaiaXScanViewController.m +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/Scan/GaiaXScanViewController.m @@ -17,9 +17,10 @@ // limitations under the License. #import "GaiaXScanViewController.h" -#import "GaiaXPreviewViewController.h" #import "GaiaXScanView.h" #import "GaiaXHelper.h" +#import +#import "GaiaXCommandCenter.h" @interface GaiaXScanViewController () @@ -44,13 +45,27 @@ - (void)viewDidLoad { } - (void)didRecievedScanContent:(NSString *)content{ + if (self.isFinished) { return; } self.isFinished = YES; - GaiaXPreviewViewController *previewController = [[GaiaXPreviewViewController alloc] initWithUrl:content]; - [self.navigationController pushViewController:previewController animated:YES]; + + NSString *resultString = [GaiaXHelper URLDecodedString:content]; + //解析url的参数 + NSDictionary *params = [GaiaXHelper parameterFromUrl:resultString]; + //socketUrl + NSString *socketUrl = [params valueForKey:@"url"]; + socketUrl = socketUrl.stringByRemovingPercentEncoding; + //type + NSString *type = [params valueForKey:@"type"]; + + if ([type isEqualToString:@"connect"]){ + //建立socket连接 + [GaiaXSocketManager.sharedInstance connet:socketUrl]; + [self.navigationController popViewControllerAnimated:YES]; + } } diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.h deleted file mode 100644 index 80f40fd46..000000000 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2021, Alibaba Group Holding Limited. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#import - -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCKey; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCVersion; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCIdKey; - -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCMethodKey; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCParamsKey; - -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCResultKey; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCErrorKey; - -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCCodeKey; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCMessageKey; -FOUNDATION_EXTERN NSString* const GaiaXJSONRPCDataKey; diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.h deleted file mode 100644 index 429f00014..000000000 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.h +++ /dev/null @@ -1,100 +0,0 @@ -// -// GaiaXSocketClient.h -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#import -#import "GaiaXSocketRequest.h" - -NS_ASSUME_NONNULL_BEGIN - -@class GaiaXSocketClient; - -typedef NS_ENUM(NSInteger, GaiaXWebSocketStatus){ - GaiaXWebSocketStatusDefault = 0, //初始状态,未连接 - GaiaXWebSocketStatusConnect, //已连接 - GaiaXWebSocketStatusDisConnect, //断开连接 -}; - -@protocol GaiaXSocketClientDelegate - -@optional - -/** - *接受到模板信息 - * @param client 客户端socket. - * @param templateInfo 模板信息. - */ --(void)gaiaXSocketClient:(GaiaXSocketClient *)client didReceiveTemplateInfo:(NSDictionary *)templateInfo; - -/** - * 接受到嵌套模板信息 - * @param client 客户端socket. - * @param templateInfo 模板信息. - */ --(void)gaiaXSocketClient:(GaiaXSocketClient *)client didReceiveNestedTemplateInfo:(NSDictionary *)templateInfo; - -/** - * scoket连接初始化成功 - * @param client 客户端socket. - */ --(void)gaiaXSocketClientDidInitialize:(GaiaXSocketClient *)client; - -/** - *scoket连接出错 - * @param client 客户端socket. - * @param error 错误. - */ --(void)gaiaXSocketClient:(GaiaXSocketClient *)client didFailWithError:(NSError *)error; -/** - *scoket连接成功 - * @param client 客户端socket. - */ --(void)gaiaXSocketClientDidConnect:(GaiaXSocketClient *)client; -/** - *scoket取消连接 - * @param client 客户端socket. - */ --(void)gaiaXSocketClientDidDisconnect:(GaiaXSocketClient *)client; - -@end - - - -@interface GaiaXSocketClient : NSObject - -//是否连接 -@property (nonatomic, assign) BOOL isConnect; -//socket状态 -@property (nonatomic, assign) GaiaXWebSocketStatus socketStatus; -//socket代理 -@property (nonatomic, weak) id delegate; - -//初始化 -- (instancetype)initWithURL:(NSURL *)url delegate:(id)delegate; - -//建立长连接 -- (void)connectServer; -//重新连接 -- (void)reConnectServer; -//关闭连接 -- (void)webSocketClose; -//向服务器发送数据 -- (void)sendRequestToServer:(GaiaXSocketRequest *)request; - -@end - -NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.m deleted file mode 100644 index e5340e3a6..000000000 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.m +++ /dev/null @@ -1,420 +0,0 @@ -// -// GaiaXSocketClient.m -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#import "GaiaXSocketClient.h" -#import -#import -#import "GaiaXHelper.h" - -@interface GaiaXSocketClient () - -@property (nonatomic, strong) NSURL *url; -@property (nonatomic, strong) SRWebSocket *webScoket; - -@property (nonatomic, strong) NSTimer *headerBeatTimer; //心跳定时器 -@property (nonatomic, strong) NSTimer *networkTestingTimer; //没有网络的时候检测定时器 -@property (nonatomic, assign) NSTimeInterval reConnectTime; //重连时间 -@property (nonatomic, strong) NSMutableArray *sendDataArray; //存储要发送给服务器的数据 - -@property (nonatomic, assign) BOOL isActiveClose; //用于判断是否主动关闭长连接,如果是主动断开连接,连接失败的代理中,就不用执行 重新连接方法 -@property (nonatomic, strong) dispatch_queue_t processingQueue; - -@end - - -@implementation GaiaXSocketClient - -- (instancetype)initWithURL:(NSURL *)url delegate:(id)delegate { - self = [self init]; - if (self) { - _url = url; - _delegate = delegate; - _processingQueue = dispatch_queue_create("eu.nubomedia.websocket.processing", DISPATCH_QUEUE_SERIAL); - } - return self; -} - -- (instancetype)init{ - self = [super init]; - if (self) { - self.reConnectTime = 0; - self.isActiveClose = NO; - self.sendDataArray = [NSMutableArray array]; - } - return self; -} - -//建立长连接 -- (void)connectServer{ - if(self.webScoket){ - return; - } - - self.webScoket = [[SRWebSocket alloc] initWithURL:_url]; - [self.webScoket setDelegateDispatchQueue:self.processingQueue]; - self.webScoket.delegate = self; - [self.webScoket open]; -} - -//发送心跳 -- (void)sendPing:(id)sender{ - NSData *heartData = [[NSData alloc] initWithBase64EncodedString:@"heart" options:NSUTF8StringEncoding]; - [self.webScoket sendPing:heartData error:nil]; -} - -//关闭长连接 -- (void)webSocketClose{ - self.isConnect = NO; - self.isActiveClose = YES; - self.socketStatus = GaiaXWebSocketStatusDefault; - - //关闭socket - if (self.webScoket) { - [self.webScoket close]; - self.webScoket = nil; - } - - //关闭心跳定时器 - [self destoryHeartBeat]; - //关闭网络检测定时器 - [self destoryNetWorkStartTesting]; -} - -#pragma mark - socket delegate - -//已经连接 -- (void)webSocketDidOpen:(SRWebSocket *)webSocket{ - self.isConnect = YES; - self.socketStatus = GaiaXWebSocketStatusConnect; - - //开始心跳 - [self initHeartBeat]; - - //代理方法 - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClientDidConnect:)]) { - [self.delegate gaiaXSocketClientDidConnect:self]; - } - }) -} - -//连接失败 -- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error{ - self.isConnect = NO; - self.socketStatus = GaiaXWebSocketStatusDisConnect; - // NSLog(@"连接失败,这里可以实现掉线自动重连,要注意以下几点"); - // NSLog(@"1.判断当前网络环境,如果断网了就不要连了,等待网络到来,在发起重连"); - // NSLog(@"2.判断调用层是否需要连接,不需要的时候不k连接,浪费流量"); - // NSLog(@"3.连接次数限制,如果连接失败了,重试10次左右就可以了"); - - //判断网络环境 - if (![GaiaXHelper isNetworkReachable]) { - //没有网络,开启网络监测定时器 - [self noNetWorkStartTesting]; - } else { - //连接失败,重新连接 - [self reConnectServer]; - } - - //代理方法 - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClient:didFailWithError:)]) { - [self.delegate gaiaXSocketClient:self didFailWithError:error]; - } - }) -} - -//接收消息 -- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)messageData{ - //NSLog(@"接收消息 ---- %@", messageData); - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - if (![GXUtils isValidString:messageData] && ![GXUtils isValidDictionary:messageData]) { - return; - } - GXStrongSelf(self) - - //获取messageData的内容 - NSDictionary *messageDictionary = nil; - if ([messageData isKindOfClass:[NSString class]]) { - messageDictionary = [NSDictionary gx_dictionaryFromJSONString:messageData]; - } else { - messageDictionary = (NSDictionary *)messageData; - } - - //获取消息ID - NSInteger messageId = [messageDictionary gx_integerForKey:@"id"]; - - switch (messageId) { - case 1:{//初始化消息 - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClientDidInitialize:)]) { - [self.delegate gaiaXSocketClientDidInitialize:self]; - } - } - break; - case 666:{//获取当前模板消息 - NSDictionary *result = [messageDictionary gx_dictionaryForKey:@"result"]; - NSDictionary *data = [result gx_dictionaryForKey:@"data"]; - if (data) { - //获取templateId - NSMutableDictionary *templateInfo = [NSMutableDictionary dictionaryWithDictionary:data]; - [templateInfo gx_setObject:[result gx_stringForKey:@"templateId"] forKey:@"templateId"]; - //代理方法 - if ([self.delegate respondsToSelector:@selector(gaiaXSocketClient:didReceiveTemplateInfo:)]) { - [self.delegate gaiaXSocketClient:self didReceiveTemplateInfo:templateInfo]; - } - } - } - break; - case 888:{//获取嵌套模板消息 - NSDictionary *result = [messageDictionary gx_dictionaryForKey:@"result"]; - NSDictionary *data = [result gx_dictionaryForKey:@"data"]; - if (data) { - //获取templateId - NSMutableDictionary *templateInfo = [NSMutableDictionary dictionaryWithDictionary:data]; - [templateInfo gx_setObject:[result gx_stringForKey:@"templateId"] forKey:@"templateId"]; - //代理方法 - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClient:didReceiveNestedTemplateInfo:)]) { - [self.delegate gaiaXSocketClient:self didReceiveNestedTemplateInfo:templateInfo]; - } - } - } - break; - - default:{//获取通知 - NSString *method = [messageDictionary gx_stringForKey:@"method"]; - if ([method isEqualToString:@"template/didChangedNotification"] || - [method isEqualToString:@"template/didManualChangedNotification"]) { - NSDictionary *result = [messageDictionary gx_dictionaryForKey:@"params"]; - NSDictionary *data = [result gx_dictionaryForKey:@"data"]; - if (data) { - //获取templateId - NSMutableDictionary *templateInfo = [NSMutableDictionary dictionaryWithDictionary:data]; - [templateInfo gx_setObject:[result gx_stringForKey:@"templateId"] forKey:@"templateId"]; - //代理方法 - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClient:didReceiveTemplateInfo:)]) { - [self.delegate gaiaXSocketClient:self didReceiveTemplateInfo:templateInfo]; - } - } - } - } - break; - } - - }); - -} - -//关闭连接 -- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean{ - //代理 - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.delegate && [self.delegate respondsToSelector:@selector(gaiaXSocketClientDidDisconnect:)]) { - [self.delegate gaiaXSocketClientDidDisconnect:self]; - } - }); - - self.isConnect = NO; - - if (self.isActiveClose) { - self.socketStatus = GaiaXWebSocketStatusDefault; - return; - } - - //更新status - self.socketStatus = GaiaXWebSocketStatusDisConnect; - - //断开时销毁心跳 - [self destoryHeartBeat]; - - //判断网络 - if (![GaiaXHelper isNetworkReachable]) { - //没有网络,开启网络监测定时器 - [self noNetWorkStartTesting]; - } else { - //重连 - self.webScoket = nil; - [self reConnectServer]; - } -} - - -/** - 接受服务端发生Pong消息,我们在建立长连接之后会建立与服务器端的心跳包 - 心跳包是我们用来告诉服务端:客户端还在线,心跳包是ping消息,于此同时服务端也会返回给我们一个pong消息 - */ -- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongData{ - //do nothing -} - -#pragma mark - NSTimer - -//初始化心跳 -- (void)initHeartBeat{ - if (self.headerBeatTimer) { - return; - } - - [self destoryHeartBeat]; - - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - self.headerBeatTimer = [NSTimer timerWithTimeInterval:10 target:self selector:@selector(senderheartBeat) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:self.headerBeatTimer forMode:NSRunLoopCommonModes]; - }); -} - -//重新连接 -- (void)reConnectServer{ - //关闭之前的连接 - [self webSocketClose]; - - //重连10次 2^10 = 1024 - if (self.reConnectTime > 1024) { - self.reConnectTime = 0; - return; - } - - GXWeakSelf(self) - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - GXStrongSelf(self) - if (self.webScoket.readyState == SR_OPEN && self.webScoket.readyState == SR_CONNECTING) { - return ; - } - - //链接服务器 - [self connectServer]; - - //设置事件 - if (self.reConnectTime == 0) {//重连时间2的指数级增长 - self.reConnectTime = 2; - } else { - self.reConnectTime *= 2; - } - }); -} - -//发送心跳 -- (void)senderheartBeat{ - //和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小 - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.webScoket.readyState == SR_OPEN) { - //NSLog(@"发送心跳"); - [self sendPing:nil]; - - }else if (self.webScoket.readyState == SR_CONNECTING){ - //NSLog(@"正在连接中"); - [self reConnectServer]; - - }else if (self.webScoket.readyState == SR_CLOSED || self.webScoket.readyState == SR_CLOSING){ - //NSLog(@"断开,重连"); - [self reConnectServer]; - - }else{ - //NSLog(@"没网络,发送失败,一旦断网 socket 会被我设置 nil 的"); - } - }); -} - -//取消心跳 -- (void)destoryHeartBeat{ - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.headerBeatTimer) { - [self.headerBeatTimer invalidate]; - self.headerBeatTimer = nil; - } - }); -} - -//没有网络的时候开始定时 -- 用于网络检测 -- (void)noNetWorkStartTestingTimer{ - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - self.networkTestingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(noNetWorkStartTesting) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:self.networkTestingTimer forMode:NSDefaultRunLoopMode]; - }); -} - -//定时检测网络 -- (void)noNetWorkStartTesting{ - if (![GaiaXHelper isNetworkReachable]) { - //关闭网络检测定时器 - [self destoryNetWorkStartTesting]; - //重新连接 - [self reConnectServer]; - } -} - -//取消网络检测 -- (void)destoryNetWorkStartTesting{ - GXWeakSelf(self) - GX_DISPATCH_MAIN_THREAD(^{ - GXStrongSelf(self) - if (self.networkTestingTimer) { - [self.networkTestingTimer invalidate]; - self.networkTestingTimer = nil; - } - }); -} - -- (void)sendRequestToServer:(GaiaXSocketRequest *)request{ - //处理消息 - NSString *msg = [request toJSONString]; - [self.sendDataArray addObject:msg]; - - //没有网络 - if(![GaiaXHelper isNetworkReachable]){ - //开启网络检测定时器 - [self noNetWorkStartTesting]; - - } else { - - if (self.webScoket != nil) { - //只有长连接OPEN开启状态才能调用send方法 - if (self.webScoket.readyState == SR_OPEN) { - //发送消息 - [self.webScoket send:msg]; - - } else if (self.webScoket.readyState == SR_CONNECTING){ - //正在连接,donothing - - } else if (self.webScoket.readyState == SR_CLOSING || self.webScoket.readyState == SR_CLOSED){ - //调用 reConnectServer 方法重连,连接成功后 继续发送数据 - [self reConnectServer]; - } - - } else { - [self connectServer];//连接服务器 - } - } -} - - -@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.m deleted file mode 100644 index 281eedac9..000000000 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// GaiaXSocketRequest.m -// GaiaXiOSDemo -// -// Copyright (c) 2021, Alibaba Group Holding Limited. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#import "GaiaXSocketRequest.h" -#import "GaiaXJSONRPCConstants.h" - -@implementation GaiaXSocketRequest - -+ (instancetype)requestWithRequestId:(NSNumber *)requestId Method:(NSString *)method parameters:(id)parameters { - GaiaXSocketRequest *request = [[GaiaXSocketRequest alloc] init]; - request.parameters = parameters; - request.requestId = requestId; - request.method = method; - return request; -} - -- (NSDictionary *)toJSONDictionary { - NSMutableDictionary *json = [NSMutableDictionary dictionary]; - [json setObject:GaiaXJSONRPCVersion forKey:GaiaXJSONRPCKey]; - [json setObject:self.method forKey:GaiaXJSONRPCMethodKey]; - - if (self.parameters) { - [json setObject:self.parameters forKey:GaiaXJSONRPCParamsKey]; - } - - if (self.requestId) { - [json setObject:self.requestId forKey:GaiaXJSONRPCIdKey]; - } - - return [json copy]; -} - -- (NSString *)toJSONString { - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self toJSONDictionary] - options:NSJSONWritingPrettyPrinted - error:nil]; - NSString * str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - return str; -} - -@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.h b/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.h new file mode 100644 index 000000000..9a363fb15 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.h @@ -0,0 +1,23 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface JSViewController : UIViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.m b/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.m new file mode 100644 index 000000000..fa7b77f09 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.m @@ -0,0 +1,60 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "JSViewController.h" +#import +#import "GaiaXHelper.h" + +@interface JSViewController () + +@property (nonatomic, strong) UIView *view1; + +@end + +@implementation JSViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor whiteColor]; + //templateItem + GXTemplateItem *templateItem1 = [[GXTemplateItem alloc] init]; + templateItem1.templateId = @"gx-with-js"; + templateItem1.bizId = [GaiaXHelper bizId]; + templateItem1.isLocal = YES; + + //渲染view + _view1 = [TheGXTemplateEngine creatViewByTemplateItem:templateItem1 measureSize:CGSizeMake(self.view.frame.size.width - 20, NAN)]; + CGRect frame1 = _view1.frame; + frame1.origin.x = 10; + frame1.origin.y = 100; + _view1.frame = frame1; + [self.view addSubview:_view1]; + + //绑定数据 + GXTemplateData *data1 = [[GXTemplateData alloc] init]; + data1.data = [GaiaXHelper jsonWithFileName:@"gx-with-js"]; + [TheGXTemplateEngine bindData:data1 onView:_view1]; +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.h b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.h new file mode 100644 index 000000000..6edb3414c --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.h @@ -0,0 +1,23 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GaiaXJSExampleModule : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.m b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.m new file mode 100644 index 000000000..27f1faa79 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.m @@ -0,0 +1,51 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GaiaXJSExampleModule.h" +#import + +@implementation GaiaXJSExampleModule + +GAIAXJS_EXPORT_MODULE(Example) + +// Sync Method +GAIAXJS_EXPORT_SYNC_METHOD(void, log:(NSString *)data) { + NSLog(@"GaiaXJS log %@", data); +} + +// Async Method with Callback +GAIAXJS_EXPORT_ASYNC_METHOD(log2:(NSString *)data + callback:(GaiaXJSCallbackBlock)callback) { + // some code here ... + if (callback != nil) { + callback(@{}); + } +} + +// Async Method with Promise +GAIAXJS_EXPORT_SYNC_METHOD(void, log3:(NSString *)data + resolver:(GaiaXJSPromiseResolveBlock)resolve + rejecter:(GaiaXJSPromiseRejectBlock)reject) { + // some code here ... + if (true) { + if (resolve != nil) { + resolve(@{}); + } + return; + } + if (reject != nil) { + reject(@"-1", @"error occured"); + } +} +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.m b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.m new file mode 100644 index 000000000..b35b72325 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.m @@ -0,0 +1,22 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#import + +@interface GAIAXJS_EXPORT_EXTERN_MODULE(SwiftExample, GaiaXJSSwiftExampleModule, NSObject); + +GAIAXJS_EXPORT_EXTERN_SYNC_METHOD(void, log:(NSString *)data); + +@end diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.swift b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.swift new file mode 100644 index 000000000..acfc5b014 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.swift @@ -0,0 +1,24 @@ +// Copyright (c) 2023, Alibaba Group Holding Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +import Foundation + +@objc(GaiaXJSSwiftExampleModule) +class GaiaXJSSwiftExampleModule: NSObject { + @objc(log:) + func log(data: String) -> Void { + print("GaiaXJS Swift log ", data) + } +} diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.css b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.css new file mode 100755 index 000000000..17113455d --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.css @@ -0,0 +1,52 @@ +#gx-with-js { + width: 100%; + height: 100px; + align-items: center; + border-color: #979797; + border-width: 1px; + border-style: solid; + border-radius: 5px; +} +#left-image { + width: 50px; + height: 50px; + margin-left: 12px; + margin-right: 12px; + border-radius: 5px; +} +#middle-container { + height: 100%; + flex-direction: column; + flex-grow: 1; + justify-content: center; +} +#title { + width: 100px; + text-overflow: ellipsis; + height: 20px; + color: #000000; + font-size: 15px; +} +#sub-title { + width: 100px; + text-overflow: ellipsis; + height: 20px; + color: #9b9b9b; + font-size: 15px; +} +#button { + width: 50px; + height: 30px; + border-radius: 5px; + background-image: linear-gradient(to bottom, #d0021b 0%, #f5a623 100%); + margin-left: 12px; + margin-right: 12px; +} +#button-title { + width: 100%; + text-overflow: ellipsis; + height: 100%; + color: #ffffff; + font-size: 15px; + text-align: center; +} diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.databinding b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.databinding new file mode 100755 index 000000000..c2656835c --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.databinding @@ -0,0 +1,16 @@ +{ + "data":{ + "left-image":{ + "value":"$img", + }, + "sub-title":{ + "value":"$desc" + }, + "title":{ + "value":"$title" + }, + "button-title":{ + "value":"$button" + } + } +} diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.js b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.js new file mode 100644 index 000000000..a9ac30656 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.js @@ -0,0 +1,5 @@ +//------ts start------ +//UEsDBAoAAAAAAJkxLFaxQdIpkQIAAJECAAAIAAAAaW5kZXguanNDb21wb25lbnQoewogIHN0YXRlOiB7fSwKICBvblNob3c6IGZ1bmN0aW9uICgpIHsKICAgIC8v5q+P5qyh5qih5p2/5pi+56S65pe25Zue6LCDCiAgfSwKICBvblJlYWR5OiBmdW5jdGlvbiAoKSB7CiAgICAvL+aooeadv+a4suafk+WujOaIkOWQjuWbnuiwg++8jOeUn+WRveWRqOacn+WGheWPquWbnuiwg+S4gOasoQogICAgbGV0IHZpZXcgPSB0aGlzLmdldEVsZW1lbnRCeUlkKCJidXR0b24tdGl0bGUiKTsKICAgIGlmICh2aWV3KSB7CiAgICAgIHZpZXcuYWRkRXZlbnRMaXN0ZW5lcigiY2xpY2siLCAoZXZlbnQpID0+IHsKICAgICAgICAvL0B0cy1pZ25vcmUKICAgICAgICBFeGFtcGxlLmxvZygiaW52b2tlIEV4YW1wbGUgbG9nIG1ldGhvZCIpOwogICAgICAgIC8vQHRzLWlnbm9yZQogICAgICAgIFN3aWZ0RXhhbXBsZS5sb2coImludm9rZSBFeGFtcGxlIGxvZyBtZXRob2QiKTsKICAgICAgfSk7CiAgICB9CiAgfSwKICBvbkhpZGU6IGZ1bmN0aW9uICgpIHsKICAgIC8v5q+P5qyh5qih5p2/6ZqQ6JeP5pe25Zue6LCDCiAgfSwKICBvblJldXNlOiBmdW5jdGlvbiAoKSB7CiAgICAvL+aooeadv+WkjeeUqOaXtuWbnuiwgwogIH0sCiAgb25EZXN0cm95OiBmdW5jdGlvbiAoKSB7CiAgICAvL+aooeadv+WunuS+i+mHiuaUvuaXtuWbnuiwgwogIH0sCn0pOwpQSwECFAAKAAAAAACZMSxWsUHSKZECAACRAgAACAAAAAAAAAAAAAAAAAAAAAAAaW5kZXguanNQSwUGAAAAAAEAAQA2AAAAtwIAAAAA +//------ts end------ + +Component({state:{},onShow:function(){},onReady:function(){var n=this.getElementById("button-title");n&&n.addEventListener("click",(function(n){Example.log("invoke Example log method"),SwiftExample.log("invoke Example log method")}))},onHide:function(){},onReuse:function(){},onDestroy:function(){}}); diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.json b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.json new file mode 100755 index 000000000..db8e20271 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.json @@ -0,0 +1,20 @@ +{ + "type": "gaia-template", + "id": "gx-with-js", + "layers": [ + { "id": "left-image", "type": "image" }, + { + "id": "middle-container", + "type": "view", + "layers": [ + { "id": "title", "type": "text" }, + { "id": "sub-title", "type": "text" } + ] + }, + { + "id": "button", + "type": "view", + "layers": [{ "id": "button-title", "type": "text" }] + } + ] +} diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/en.lproj/FunctionList.plist b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/en.lproj/FunctionList.plist index f849b3c41..deeaffd67 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/en.lproj/FunctionList.plist +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/en.lproj/FunctionList.plist @@ -50,5 +50,11 @@ class StyleViewController + + title + Template With JS + class + JSViewController + diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/gx-with-js.json b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/gx-with-js.json new file mode 100644 index 000000000..829b954d8 --- /dev/null +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/gx-with-js.json @@ -0,0 +1,6 @@ +{ + "img": "https://t7.baidu.com/it/u=376303577,3502948048&fm=193&f=GIF", + "title": "我是标题", + "desc": "我是副标题", + "button": "按钮" +} diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist index 30dfbb15f..9ded66ef6 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist @@ -44,6 +44,12 @@ class RecycleListViewController + + title + JS模板 + class + JSViewController + title 样式 diff --git a/GaiaXiOSDemo/GaiaXiOSDemo/ViewController.m b/GaiaXiOSDemo/GaiaXiOSDemo/ViewController.m index 57fca7e31..592d23133 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/ViewController.m +++ b/GaiaXiOSDemo/GaiaXiOSDemo/ViewController.m @@ -21,7 +21,9 @@ #import "GaiaXScanViewController.h" #import "GaiaXPreviewViewController.h" #import "GaiaXHelper.h" - +#import "GaiaXDevTools.h" +#import "GaiaXCommandCenter.h" +#import "GaiaXSocketManager.h" @interface ViewController () @@ -47,6 +49,16 @@ - (void)viewDidLoad { //数据处理 & reload self.dataArray = [GaiaXHelper loadGaiaXFounctionList]; [self.tableView reloadData]; + + + [GaiaXCommandCenter sharedInstance]; + + [GaiaXDevTools show]; + + NSString *url = [NSUserDefaults.standardUserDefaults stringForKey:@"gx_socket_url"]; + if (url.length > 0) { + [[GaiaXSocketManager sharedInstance] connet:url]; + } } @@ -79,18 +91,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath #pragma mark - -- (IBAction)previewAction:(id)sender{ - if (self.isSimuLator) { - NSString *content = @"gaiax://gaiax/preview?url=ws://30.78.146.17:9001&id=test-template&type=auto"; - GaiaXPreviewViewController *previewController = [[GaiaXPreviewViewController alloc] initWithUrl:content]; - [self.navigationController pushViewController:previewController animated:YES]; - }else { - UIViewController *vc = [[GaiaXScanViewController alloc] init]; - vc.title = NSLocalizedString(@"fastpreview", nil); - [self.navigationController pushViewController:vc animated:YES]; - } -} - -(BOOL)isSimuLator { diff --git a/GaiaXiOSDemo/Podfile b/GaiaXiOSDemo/Podfile index 38f04663d..c19256c78 100644 --- a/GaiaXiOSDemo/Podfile +++ b/GaiaXiOSDemo/Podfile @@ -13,7 +13,8 @@ target 'GaiaXiOSDemo' do # 曲线动画 # pod 'GaiaXiOS' pod 'GaiaXiOS', :path =>'../GaiaXiOS' - + pod 'GaiaXJS', :path =>'../GaiaXJSiOS' + pod 'GaiaXSocket', :path =>'../GaiaXSocketiOS' # 曲线动画 pod 'GaiaMotionCurve'