From 5bf3bcea2bdef43f53ee88a4f987b3a25fbc9aab Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:30:59 +0800 Subject: [PATCH 1/6] add GaiaXSocket --- GaiaXSocketiOS/.gitignore | 5 + GaiaXSocketiOS/GaiaXSocket.podspec | 25 + .../GaiaXSocket.xcodeproj/project.pbxproj | 436 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/GaiaXSocket.xcscheme | 67 +++ .../contents.xcworkspacedata | 10 + GaiaXSocketiOS/GaiaXSocket/GaiaXSocket.h | 29 ++ .../GaiaXSocket/GaiaXSocketClient.h | 66 +++ .../GaiaXSocket/GaiaXSocketClient.m | 281 +++++++++++ .../GaiaXSocket/GaiaXSocketJsonRpcDefine.h | 30 ++ .../GaiaXSocket/GaiaXSocketJsonRpcDefine.m | 29 ++ .../GaiaXSocket/GaiaXSocketManager.h | 46 ++ .../GaiaXSocket/GaiaXSocketManager.m | 134 ++++++ GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.h | 48 ++ GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.m | 117 +++++ .../GaiaXSocket/GaiaXSocketProtocol.h | 50 ++ GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h | 30 ++ GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.m | 46 ++ GaiaXSocketiOS/GaiaXSocket/Info.plist | 8 + GaiaXSocketiOS/Podfile | 12 + 21 files changed, 1484 insertions(+) create mode 100644 GaiaXSocketiOS/.gitignore create mode 100644 GaiaXSocketiOS/GaiaXSocket.podspec create mode 100644 GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.pbxproj create mode 100644 GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 GaiaXSocketiOS/GaiaXSocket.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 GaiaXSocketiOS/GaiaXSocket.xcodeproj/xcshareddata/xcschemes/GaiaXSocket.xcscheme create mode 100644 GaiaXSocketiOS/GaiaXSocket.xcworkspace/contents.xcworkspacedata create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocket.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketClient.m create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketJsonRpcDefine.m create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketManager.m create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketModel.m create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketProtocol.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h create mode 100644 GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.m create mode 100644 GaiaXSocketiOS/GaiaXSocket/Info.plist create mode 100644 GaiaXSocketiOS/Podfile 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..f6b809857 --- /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 = { "jingcheng.zjc" => "jingcheng.zjc@alibaba-inc.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/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.h new file mode 100644 index 000000000..df05edd08 --- /dev/null +++ b/GaiaXSocketiOS/GaiaXSocket/GaiaXSocketUtils.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 GaiaXSocketUtils : NSObject + ++ (BOOL)isNetworkReachable; + ++ (NSString *)jsonStringFromDictionary:(NSDictionary *)dictionary; + ++ (NSDictionary *)dictionaryFromJsonString:(NSString *)jsonString; + + +@end + +NS_ASSUME_NONNULL_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 From 9568eda3e9a008b72c4e3491329b87d999b516d7 Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:40:06 +0800 Subject: [PATCH 2/6] update author --- GaiaXSocketiOS/GaiaXSocket.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GaiaXSocketiOS/GaiaXSocket.podspec b/GaiaXSocketiOS/GaiaXSocket.podspec index f6b809857..e1f497fae 100644 --- a/GaiaXSocketiOS/GaiaXSocket.podspec +++ b/GaiaXSocketiOS/GaiaXSocket.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.homepage = "https://github.com/alibaba/GaiaX" - s.author = { "jingcheng.zjc" => "jingcheng.zjc@alibaba-inc.com" } + 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}" } From bfb49c71e9b4517960a0e7f2ac8b8a18f980cceb Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:54:14 +0800 Subject: [PATCH 3/6] add GaiaXJS --- GaiaXJSiOS/.gitignore | 5 + GaiaXJSiOS/GaiaXJS.podspec | 21 + GaiaXJSiOS/GaiaXJS.xcodeproj/project.pbxproj | 738 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/GaiaXJS.xcscheme | 67 ++ .../contents.xcworkspacedata | 10 + GaiaXJSiOS/GaiaXJS/GaiaXJS.h | 40 + GaiaXJSiOS/GaiaXJS/Info.plist | 22 + .../Resources/GaiaXJS.bundle/bootstrap.min.js | 1 + GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.h | 31 + GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.m | 48 ++ GaiaXJSiOS/GaiaXJS/src/GaiaXJSDefines.h | 229 ++++++ .../src/GaiaXJSExecPhaseImplDelegate.h | 32 + GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.h | 41 + GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.m | 216 +++++ GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.h | 35 + GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.m | 46 ++ GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.h | 53 ++ GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.m | 335 ++++++++ .../GaiaXJS/src/GaiaXJSModulesImplDelegate.h | 78 ++ GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.h | 49 ++ GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.m | 74 ++ .../GaiaXJS/src/bridge/GaiaXJSConvert.h | 45 ++ .../GaiaXJS/src/bridge/GaiaXJSConvert.m | 84 ++ .../src/bridge/jscore/GaiaXJSCModule.h | 43 + .../src/bridge/jscore/GaiaXJSCModule.m | 195 +++++ .../modules/GaiaXJSBuiltInModule+Storage.h | 26 + .../modules/GaiaXJSBuiltInModule+Storage.m | 55 ++ .../src/bridge/modules/GaiaXJSBuiltInModule.h | 27 + .../src/bridge/modules/GaiaXJSBuiltInModule.m | 91 +++ .../modules/GaiaXJSNativeEventManager.h | 32 + .../modules/GaiaXJSNativeEventManager.m | 123 +++ .../bridge/modules/GaiaXJSNativeEventModule.h | 27 + .../bridge/modules/GaiaXJSNativeEventModule.m | 90 +++ .../modules/GaiaXJSNativeLoggerModule.h | 29 + .../modules/GaiaXJSNativeLoggerModule.m | 58 ++ .../modules/GaiaXJSNativeTargetModule.h | 27 + .../modules/GaiaXJSNativeTargetModule.m | 35 + .../src/bridge/uis/GaiaXImageUIModule.h | 33 + .../src/bridge/uis/GaiaXJSUIImageModule.h | 29 + .../src/bridge/uis/GaiaXJSUIImageModule.m | 27 + .../src/bridge/uis/GaiaXJSUITextModule.h | 29 + .../src/bridge/uis/GaiaXJSUITextModule.m | 29 + .../src/bridge/uis/GaiaXJSUIViewModule.h | 29 + .../src/bridge/uis/GaiaXJSUIViewModule.m | 25 + .../GaiaXJS/src/component/GaiaXJSComponent.h | 87 +++ .../GaiaXJS/src/component/GaiaXJSComponent.m | 204 +++++ .../GaiaXJS/src/context/GaiaXJSCContext.h | 30 + .../GaiaXJS/src/context/GaiaXJSCContext.m | 137 ++++ .../GaiaXJS/src/context/GaiaXJSContext.h | 68 ++ .../GaiaXJS/src/context/GaiaXJSContext.m | 131 ++++ .../src/context/GaiaXJSDebuggerContext.h | 27 + .../src/context/GaiaXJSDebuggerContext.m | 75 ++ .../src/debugger/GaiaXJSWebSocketWrapper.h | 38 + .../src/debugger/GaiaXJSWebSocketWrapper.m | 190 +++++ .../GaiaXJS/src/runtime/GaiaXJSCRuntime.h | 30 + .../GaiaXJS/src/runtime/GaiaXJSCRuntime.m | 29 + .../GaiaXJS/src/runtime/GaiaXJSDRuntime.h | 29 + .../GaiaXJS/src/runtime/GaiaXJSDRuntime.m | 32 + .../GaiaXJS/src/runtime/GaiaXJSRuntime.h | 30 + .../GaiaXJS/src/runtime/GaiaXJSRuntime.m | 23 + .../wrapper/module/GaiaXJSMethodArgument.h | 33 + .../wrapper/module/GaiaXJSMethodArgument.m | 31 + .../src/wrapper/module/GaiaXJSMethodInfo.h | 47 ++ .../src/wrapper/module/GaiaXJSMethodInfo.m | 329 ++++++++ .../src/wrapper/module/GaiaXJSModuleInfo.h | 31 + .../src/wrapper/module/GaiaXJSModuleInfo.m | 24 + .../src/wrapper/module/GaiaXJSModuleManager.h | 85 ++ .../src/wrapper/module/GaiaXJSModuleManager.m | 506 ++++++++++++ .../GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.h | 37 + .../GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.m | 273 +++++++ GaiaXJSiOS/Podfile | 10 + GaiaXJSiOS/README.md | 0 74 files changed, 5940 insertions(+) create mode 100644 GaiaXJSiOS/.gitignore create mode 100644 GaiaXJSiOS/GaiaXJS.podspec create mode 100644 GaiaXJSiOS/GaiaXJS.xcodeproj/project.pbxproj create mode 100644 GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 GaiaXJSiOS/GaiaXJS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 GaiaXJSiOS/GaiaXJS.xcodeproj/xcshareddata/xcschemes/GaiaXJS.xcscheme create mode 100644 GaiaXJSiOS/GaiaXJS.xcworkspace/contents.xcworkspacedata create mode 100644 GaiaXJSiOS/GaiaXJS/GaiaXJS.h create mode 100644 GaiaXJSiOS/GaiaXJS/Info.plist create mode 100644 GaiaXJSiOS/GaiaXJS/Resources/GaiaXJS.bundle/bootstrap.min.js create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSConfig.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSDefines.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSExecPhaseImplDelegate.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSFactory.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSHandler.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSHelper.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/GaiaXJSModulesImplDelegate.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSBridge.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/GaiaXJSConvert.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/jscore/GaiaXJSCModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule+Storage.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSBuiltInModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventManager.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeEventModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeLoggerModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/modules/GaiaXJSNativeTargetModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXImageUIModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIImageModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUITextModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/bridge/uis/GaiaXJSUIViewModule.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/component/GaiaXJSComponent.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSCContext.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSContext.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/context/GaiaXJSDebuggerContext.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/debugger/GaiaXJSWebSocketWrapper.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSCRuntime.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSDRuntime.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/runtime/GaiaXJSRuntime.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodArgument.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSMethodInfo.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleInfo.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/module/GaiaXJSModuleManager.m create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.h create mode 100644 GaiaXJSiOS/GaiaXJS/src/wrapper/ui/GaiaXJSUIManager.m create mode 100644 GaiaXJSiOS/Podfile create mode 100644 GaiaXJSiOS/README.md 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..e69de29bb From c8646811d7f2a24caca6cca2cc322dbe45486d48 Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:55:57 +0800 Subject: [PATCH 4/6] modify GaiaX with JS --- GaiaXiOS/GaiaXiOS.podspec | 1 + GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj | 32 ++- .../UserInterfaceState.xcuserstate | Bin 0 -> 16596 bytes .../GaiaXiOS/Binding/Data/GXDataManager.h | 5 + .../GaiaXiOS/Binding/Data/GXDataManager.m | 19 +- GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.h | 26 +- GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent.m | 56 +++- .../GaiaXiOS/Binding/Event/GXEventManager.h | 55 ++++ .../GaiaXiOS/Binding/Event/GXEventManager.m | 219 +++++++++++++++ .../GaiaXiOS/Binding/Event/GXEvent_Private.h | 36 +++ .../Binding/JS/GXJSDelegateImplManager.h | 22 ++ .../Binding/JS/GXJSDelegateImplManager.m | 261 ++++++++++++++++++ .../Binding/Protocol/GXEventProtocal.h | 3 + GaiaXiOS/GaiaXiOS/Category/NSArray+GX.h | 12 +- GaiaXiOS/GaiaXiOS/Category/UIView+GX.h | 17 +- GaiaXiOS/GaiaXiOS/Category/UIView+GX.m | 113 ++++---- GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m | 8 +- .../GaiaXiOS/Component/Node/GXScrollNode.m | 8 +- .../GaiaXiOS/Component/Node/GXSliderNode.m | 8 +- .../Component/View/Container/GXGridView.m | 4 +- .../Component/View/Container/GXRootView.m | 4 +- .../Component/View/Container/GXScrollView.m | 4 +- .../GaiaXiOS/Core/Creator/GXNodeTreeCreator.m | 27 +- .../GaiaXiOS/Core/StretchKit/Classes/GXNode.h | 30 +- .../GaiaXiOS/Core/StretchKit/Classes/GXNode.m | 166 +++++++---- GaiaXiOS/Podfile | 3 + 26 files changed, 973 insertions(+), 166 deletions(-) create mode 100644 GaiaXiOS/GaiaXiOS.xcodeproj/project.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.h create mode 100644 GaiaXiOS/GaiaXiOS/Binding/Event/GXEventManager.m create mode 100644 GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h create mode 100644 GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.h create mode 100644 GaiaXiOS/GaiaXiOS/Binding/JS/GXJSDelegateImplManager.m diff --git a/GaiaXiOS/GaiaXiOS.podspec b/GaiaXiOS/GaiaXiOS.podspec index b58636819..1ca787c35 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 6b55dd3a0..2745dc6b5 100644 --- a/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj +++ b/GaiaXiOS/GaiaXiOS.xcodeproj/project.pbxproj @@ -185,6 +185,11 @@ 960DAA88A4F50DDC29631263 /* libPods-GaiaXiOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D8EA6C49DAEB4EA87E7B1A6 /* libPods-GaiaXiOS.a */; }; 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 */ @@ -381,6 +386,11 @@ A23EDE6F4FF3A79714BEBD6C /* Pods-GaiaXiOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GaiaXiOSTests.release.xcconfig"; path = "Target Support Files/Pods-GaiaXiOSTests/Pods-GaiaXiOSTests.release.xcconfig"; 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 */ @@ -627,6 +637,7 @@ 8DE5E39D2745FC3400C9FA02 /* Binding */ = { isa = PBXGroup; children = ( + BD42E32B29A4A49F00F3404E /* JS */, 8DB5216B2759C88F00EB8126 /* Protocol */, 8DE5E3A02745FD8200C9FA02 /* Expression */, 8DE5E39F2745FD7600C9FA02 /* Event */, @@ -651,6 +662,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 */, @@ -910,6 +924,15 @@ name = Frameworks; sourceTree = ""; }; + BD42E32B29A4A49F00F3404E /* JS */ = { + isa = PBXGroup; + children = ( + BD42E32C29A4A49F00F3404E /* GXJSDelegateImplManager.h */, + BD42E32D29A4A49F00F3404E /* GXJSDelegateImplManager.m */, + ); + path = JS; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -944,6 +967,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 */, @@ -961,6 +985,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 */, @@ -997,6 +1022,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 */, @@ -1190,6 +1216,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 */, @@ -1210,6 +1237,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 */, @@ -1437,7 +1465,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = VY8F8V9AUC; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -1470,7 +1498,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = VY8F8V9AUC; + 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 0000000000000000000000000000000000000000..f22b05b21a5dc2cf743df26f46e6f8248021c5e0 GIT binary patch literal 16596 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 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/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h new file mode 100644 index 000000000..9ce0a7700 --- /dev/null +++ b/GaiaXiOS/GaiaXiOS/Binding/Event/GXEvent_Private.h @@ -0,0 +1,36 @@ +// +// 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 +// +// 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 GaiaEvent_Private_h +#define GaiaEvent_Private_h + +#import "GXEvent.h" +#import + +@interface GXEvent() + +//jsComponent +@property (nonatomic, weak, nullable) GaiaXJSComponent *jsComponent; +//js事件 +@property (nonatomic, strong, nullable) GXJsEvent *jsEvent; + +- (void)creatJsEvent:(NSDictionary *_Nullable)eventInfo; + +@end + +#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 072070875..a712e71fc 100644 --- a/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m +++ b/GaiaXiOS/GaiaXiOS/Component/Node/GXGridNode.m @@ -452,13 +452,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 From eb56b4fe50e6f77cd8a15030d2a337ac417ffa89 Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:57:09 +0800 Subject: [PATCH 5/6] modify demo with js --- .../GaiaXiOSDemo.xcodeproj/project.pbxproj | 148 ++++-- .../UserInterfaceState.xcuserstate | Bin 0 -> 139159 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../GaiaXiOSDemo/Base.lproj/Main.storyboard | 14 +- .../GaiaXCommandCenter.h} | 17 +- .../Preview/DevTools/GaiaXCommandCenter.m | 138 ++++++ .../Preview/DevTools/GaiaXDevTools.h | 30 ++ .../Preview/DevTools/GaiaXDevTools.m | 215 +++++++++ .../Preview/DevTools/GaiaXSocketToastView.h | 28 ++ .../Preview/DevTools/GaiaXSocketToastView.m | 133 ++++++ .../Preview/GaiaXPreviewTemplateSource.h | 8 +- .../Preview/GaiaXPreviewTemplateSource.m | 10 +- .../Preview/GaiaXPreviewViewController.h | 9 +- .../Preview/GaiaXPreviewViewController.m | 323 +++++++------- .../Preview/GaiaXTemplateSourceInterface.h | 32 ++ .../Preview/Scan/GaiaXScanViewController.m | 21 +- .../SocketClient/GaiaXJSONRPCConstants.h | 30 -- .../SocketClient/GaiaXJSONRPCConstants.m | 31 -- .../Preview/SocketClient/GaiaXSocketClient.h | 100 ----- .../Preview/SocketClient/GaiaXSocketClient.m | 420 ------------------ .../Preview/SocketClient/GaiaXSocketRequest.m | 56 --- .../GaiaXiOSDemo/Render/JSViewController.h | 23 + .../GaiaXiOSDemo/Render/JSViewController.m | 60 +++ .../NativeModules/GaiaXJSExampleModule.h | 23 + .../NativeModules/GaiaXJSExampleModule.m | 51 +++ .../NativeModules/GaiaXJSSwiftExampleModule.m | 22 + .../GaiaXJSSwiftExampleModule.swift | 24 + .../GaiaXTemplate.bundle/gx-with-js/index.css | 52 +++ .../gx-with-js/index.databinding | 16 + .../GaiaXTemplate.bundle/gx-with-js/index.js | 5 + .../gx-with-js/index.json | 20 + .../Resource/en.lproj/FunctionList.plist | 6 + .../GaiaXiOSDemo/Resource/gx-with-js.json | 6 + .../Resource/zh-Hans.lproj/FunctionList.plist | 6 + GaiaXiOSDemo/GaiaXiOSDemo/ViewController.m | 26 +- GaiaXiOSDemo/Podfile | 3 +- 36 files changed, 1196 insertions(+), 916 deletions(-) create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo.xcworkspace/xcuserdata/ronghui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist rename GaiaXiOSDemo/GaiaXiOSDemo/Preview/{SocketClient/GaiaXSocketRequest.h => DevTools/GaiaXCommandCenter.h} (59%) create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.h create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXDevTools.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.h create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXSocketToastView.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/GaiaXTemplateSourceInterface.h delete mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.h delete mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m delete mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.h delete mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketClient.m delete mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.h create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/JSViewController.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.h create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSExampleModule.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.m create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Render/NativeModules/GaiaXJSSwiftExampleModule.swift create mode 100755 GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.css create mode 100755 GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.databinding create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.js create mode 100755 GaiaXiOSDemo/GaiaXiOSDemo/Resource/GaiaXTemplate.bundle/gx-with-js/index.json create mode 100644 GaiaXiOSDemo/GaiaXiOSDemo/Resource/gx-with-js.json diff --git a/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj b/GaiaXiOSDemo/GaiaXiOSDemo.xcodeproj/project.pbxproj index 130fedb0b..aee515713 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 0000000000000000000000000000000000000000..031caff40ac71f83f3f3a2ff744e6307f89d8d6c GIT binary patch literal 139159 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 rnSgwq>B!WPsdGKvj9@-~RqD;s3sZ&Z~a|v6zyd literal 0 HcmV?d00001 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/SocketClient/GaiaXSocketRequest.h b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.h similarity index 59% rename from GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.h rename to GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.h index 0884fe571..cc022e9ef 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXSocketRequest.h +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/DevTools/GaiaXCommandCenter.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. @@ -16,19 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. + #import NS_ASSUME_NONNULL_BEGIN -@interface GaiaXSocketRequest : NSObject - -@property (nonatomic, strong) NSString *method; -@property (nonatomic, strong) NSNumber *requestId; -@property (nonatomic, strong) NSString *parameters; - -+ (instancetype)requestWithRequestId:(NSNumber *)requestId Method:(NSString *)method parameters:(nullable id)parameters; +@interface GaiaXCommandCenter : NSObject -- (NSString *)toJSONString; ++ (instancetype)sharedInstance; @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/GaiaXJSONRPCConstants.m b/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m deleted file mode 100644 index 654e10ddf..000000000 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Preview/SocketClient/GaiaXJSONRPCConstants.m +++ /dev/null @@ -1,31 +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 "GaiaXJSONRPCConstants.h" - -NSString* const GaiaXJSONRPCKey = @"jsonrpc"; -NSString* const GaiaXJSONRPCVersion = @"2.0"; -NSString* const GaiaXJSONRPCIdKey = @"id"; - -NSString* const GaiaXJSONRPCMethodKey = @"method"; -NSString* const GaiaXJSONRPCParamsKey = @"params"; - -NSString* const GaiaXJSONRPCResultKey = @"result"; -NSString* const GaiaXJSONRPCErrorKey = @"error"; - -NSString* const GaiaXJSONRPCCodeKey = @"code"; -NSString* const GaiaXJSONRPCMessageKey = @"message"; -NSString* const GaiaXJSONRPCDataKey = @"data"; 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 f2dcf6fef..b00063f63 100644 --- a/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist +++ b/GaiaXiOSDemo/GaiaXiOSDemo/Resource/zh-Hans.lproj/FunctionList.plist @@ -44,5 +44,11 @@ class RecycleListViewController + + title + JS模板 + class + JSViewController + 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' From a4e562d3036ff483d6bbead954c0a901dba979c0 Mon Sep 17 00:00:00 2001 From: ronghui1219 Date: Wed, 1 Mar 2023 14:59:50 +0800 Subject: [PATCH 6/6] add readme.md --- GaiaXJSiOS/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/GaiaXJSiOS/README.md b/GaiaXJSiOS/README.md index e69de29bb..ee47d045a 100644 --- a/GaiaXJSiOS/README.md +++ b/GaiaXJSiOS/README.md @@ -0,0 +1 @@ +[文档地址](https://www.yuque.com/youku-gaia)