├── .gitignore ├── Example └── iOS Example │ ├── iOS Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcuserdata │ │ └── lhc.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── iOS Example │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── H5 │ │ ├── hcJsBridge.js │ │ ├── hcJsBridge.min.js │ │ ├── test.html │ │ ├── testWithNoJsFile.html │ │ ├── vconsole.min.js │ │ └── vue.js │ ├── Info.plist │ ├── JsApi │ │ ├── DemoJsApi.h │ │ ├── DemoJsApi.m │ │ ├── TestJsApi.h │ │ └── TestJsApi.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m │ ├── iOS ExampleTests │ ├── Info.plist │ └── iOS_ExampleTests.m │ └── iOS ExampleUITests │ ├── Info.plist │ └── iOS_ExampleUITests.m ├── HCWebViewJsBridge.podspec ├── HCWebViewJsBridge ├── HCCoreJSExport.h ├── HCCoreJSExportImpl.h ├── HCCoreJSExportImpl.m ├── HCJsApiMethod.h ├── HCJsApiMethod.m ├── HCJsApiName.h ├── HCJsApiName.m ├── HCWKWebViewJsBridge.h ├── HCWKWebViewJsBridge.m ├── HCWebViewJavaScript.h ├── HCWebViewJavaScript.m ├── HCWebViewJsBridgeUtil.h └── HCWebViewJsBridgeUtil.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | # Pods/ 40 | # 41 | # Add this line if you want to avoid checking in source code from the Xcode workspace 42 | # *.xcworkspace 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build/ 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. 54 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots/**/*.png 61 | fastlane/test_output 62 | 63 | # Code Injection 64 | # 65 | # After new code Injection tools there's a generated folder /iOSInjectionProject 66 | # https://github.com/johnno1962/injectionforxcode 67 | 68 | iOSInjectionProject/ 69 | Example/iOS Example/iOS Example.xcodeproj/project.xcworkspace/xcuserdata/lhc.xcuserdatad/UserInterfaceState.xcuserstate 70 | *.xcuserstate 71 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E34C7EA2235D46BE0096D99D /* testWithNoJsFile.html in Resources */ = {isa = PBXBuildFile; fileRef = E34C7EA1235D46BE0096D99D /* testWithNoJsFile.html */; }; 11 | E34C7EA5235D50E60096D99D /* HCWebViewJavaScript.m in Sources */ = {isa = PBXBuildFile; fileRef = E34C7EA4235D50E60096D99D /* HCWebViewJavaScript.m */; }; 12 | E3B10A06248684900022B1F2 /* hcJsBridge.min.js in Resources */ = {isa = PBXBuildFile; fileRef = E3B10A05248684900022B1F2 /* hcJsBridge.min.js */; }; 13 | E3E35AD2233E0BFB00075B23 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35AD1233E0BFB00075B23 /* AppDelegate.m */; }; 14 | E3E35AD5233E0BFB00075B23 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35AD4233E0BFB00075B23 /* ViewController.m */; }; 15 | E3E35AD8233E0BFB00075B23 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E3E35AD6233E0BFB00075B23 /* Main.storyboard */; }; 16 | E3E35ADA233E0BFC00075B23 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E3E35AD9233E0BFC00075B23 /* Assets.xcassets */; }; 17 | E3E35ADD233E0BFC00075B23 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E3E35ADB233E0BFC00075B23 /* LaunchScreen.storyboard */; }; 18 | E3E35AE0233E0BFC00075B23 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35ADF233E0BFC00075B23 /* main.m */; }; 19 | E3E35AEA233E0BFC00075B23 /* iOS_ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35AE9233E0BFC00075B23 /* iOS_ExampleTests.m */; }; 20 | E3E35AF5233E0BFC00075B23 /* iOS_ExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35AF4233E0BFC00075B23 /* iOS_ExampleUITests.m */; }; 21 | E3E35B0A233E164200075B23 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E3E35B09233E164200075B23 /* WebKit.framework */; }; 22 | E3E35B1B233E173800075B23 /* HCWKWebViewJsBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B0D233E173800075B23 /* HCWKWebViewJsBridge.m */; }; 23 | E3E35B1C233E173800075B23 /* HCWebViewJsBridgeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B0E233E173800075B23 /* HCWebViewJsBridgeUtil.m */; }; 24 | E3E35B1D233E173800075B23 /* HCJsApiName.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B0F233E173800075B23 /* HCJsApiName.m */; }; 25 | E3E35B1F233E173800075B23 /* HCCoreJSExportImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B17233E173800075B23 /* HCCoreJSExportImpl.m */; }; 26 | E3E35B21233E173800075B23 /* HCJsApiMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B19233E173800075B23 /* HCJsApiMethod.m */; }; 27 | E3E35B24233E177D00075B23 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = E3E35B22233E177D00075B23 /* test.html */; }; 28 | E3E35B25233E177D00075B23 /* hcJsBridge.js in Resources */ = {isa = PBXBuildFile; fileRef = E3E35B23233E177D00075B23 /* hcJsBridge.js */; }; 29 | E3E35B28233E17C700075B23 /* DemoJsApi.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B27233E17C700075B23 /* DemoJsApi.m */; }; 30 | E3E35B452340E7A300075B23 /* vue.js in Resources */ = {isa = PBXBuildFile; fileRef = E3E35B442340E7A300075B23 /* vue.js */; }; 31 | E3E35B482340E7C900075B23 /* TestJsApi.m in Sources */ = {isa = PBXBuildFile; fileRef = E3E35B462340E7C900075B23 /* TestJsApi.m */; }; 32 | E3E35B4A2340EC2100075B23 /* vconsole.min.js in Resources */ = {isa = PBXBuildFile; fileRef = E3E35B492340EC2000075B23 /* vconsole.min.js */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | E3E35AE6233E0BFC00075B23 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = E3E35AC5233E0BFB00075B23 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = E3E35ACC233E0BFB00075B23; 41 | remoteInfo = "iOS Example"; 42 | }; 43 | E3E35AF1233E0BFC00075B23 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = E3E35AC5233E0BFB00075B23 /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = E3E35ACC233E0BFB00075B23; 48 | remoteInfo = "iOS Example"; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | E34C7EA1235D46BE0096D99D /* testWithNoJsFile.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = testWithNoJsFile.html; sourceTree = ""; }; 54 | E34C7EA3235D50E60096D99D /* HCWebViewJavaScript.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HCWebViewJavaScript.h; sourceTree = ""; }; 55 | E34C7EA4235D50E60096D99D /* HCWebViewJavaScript.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HCWebViewJavaScript.m; sourceTree = ""; }; 56 | E3B10A05248684900022B1F2 /* hcJsBridge.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = hcJsBridge.min.js; sourceTree = ""; }; 57 | E3E35ACD233E0BFB00075B23 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | E3E35AD0233E0BFB00075B23 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 59 | E3E35AD1233E0BFB00075B23 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 60 | E3E35AD3233E0BFB00075B23 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 61 | E3E35AD4233E0BFB00075B23 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 62 | E3E35AD7233E0BFB00075B23 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 63 | E3E35AD9233E0BFC00075B23 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 64 | E3E35ADC233E0BFC00075B23 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 65 | E3E35ADE233E0BFC00075B23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 66 | E3E35ADF233E0BFC00075B23 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 67 | E3E35AE5233E0BFC00075B23 /* iOS ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "iOS ExampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | E3E35AE9233E0BFC00075B23 /* iOS_ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOS_ExampleTests.m; sourceTree = ""; }; 69 | E3E35AEB233E0BFC00075B23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 70 | E3E35AF0233E0BFC00075B23 /* iOS ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "iOS ExampleUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | E3E35AF4233E0BFC00075B23 /* iOS_ExampleUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOS_ExampleUITests.m; sourceTree = ""; }; 72 | E3E35AF6233E0BFC00075B23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | E3E35B09233E164200075B23 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 74 | E3E35B0D233E173800075B23 /* HCWKWebViewJsBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCWKWebViewJsBridge.m; sourceTree = ""; }; 75 | E3E35B0E233E173800075B23 /* HCWebViewJsBridgeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCWebViewJsBridgeUtil.m; sourceTree = ""; }; 76 | E3E35B0F233E173800075B23 /* HCJsApiName.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCJsApiName.m; sourceTree = ""; }; 77 | E3E35B10233E173800075B23 /* HCJsApiMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCJsApiMethod.h; sourceTree = ""; }; 78 | E3E35B12233E173800075B23 /* HCCoreJSExportImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCCoreJSExportImpl.h; sourceTree = ""; }; 79 | E3E35B13233E173800075B23 /* HCWKWebViewJsBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCWKWebViewJsBridge.h; sourceTree = ""; }; 80 | E3E35B15233E173800075B23 /* HCCoreJSExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCCoreJSExport.h; sourceTree = ""; }; 81 | E3E35B16233E173800075B23 /* HCWebViewJsBridgeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCWebViewJsBridgeUtil.h; sourceTree = ""; }; 82 | E3E35B17233E173800075B23 /* HCCoreJSExportImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCCoreJSExportImpl.m; sourceTree = ""; }; 83 | E3E35B19233E173800075B23 /* HCJsApiMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HCJsApiMethod.m; sourceTree = ""; }; 84 | E3E35B1A233E173800075B23 /* HCJsApiName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCJsApiName.h; sourceTree = ""; }; 85 | E3E35B22233E177D00075B23 /* test.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test.html; sourceTree = ""; }; 86 | E3E35B23233E177D00075B23 /* hcJsBridge.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = hcJsBridge.js; sourceTree = ""; }; 87 | E3E35B26233E17C700075B23 /* DemoJsApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoJsApi.h; sourceTree = ""; }; 88 | E3E35B27233E17C700075B23 /* DemoJsApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoJsApi.m; sourceTree = ""; }; 89 | E3E35B442340E7A300075B23 /* vue.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = vue.js; sourceTree = ""; }; 90 | E3E35B462340E7C900075B23 /* TestJsApi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestJsApi.m; sourceTree = ""; }; 91 | E3E35B472340E7C900075B23 /* TestJsApi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestJsApi.h; sourceTree = ""; }; 92 | E3E35B492340EC2000075B23 /* vconsole.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = vconsole.min.js; sourceTree = ""; }; 93 | /* End PBXFileReference section */ 94 | 95 | /* Begin PBXFrameworksBuildPhase section */ 96 | E3E35ACA233E0BFB00075B23 /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | E3E35B0A233E164200075B23 /* WebKit.framework in Frameworks */, 101 | ); 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | E3E35AE2233E0BFC00075B23 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | E3E35AED233E0BFC00075B23 /* Frameworks */ = { 112 | isa = PBXFrameworksBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | /* End PBXFrameworksBuildPhase section */ 119 | 120 | /* Begin PBXGroup section */ 121 | E3B10A032486844B0022B1F2 /* H5 */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | E3B10A05248684900022B1F2 /* hcJsBridge.min.js */, 125 | E3E35B442340E7A300075B23 /* vue.js */, 126 | E3E35B492340EC2000075B23 /* vconsole.min.js */, 127 | E3E35B23233E177D00075B23 /* hcJsBridge.js */, 128 | E3E35B22233E177D00075B23 /* test.html */, 129 | E34C7EA1235D46BE0096D99D /* testWithNoJsFile.html */, 130 | ); 131 | path = H5; 132 | sourceTree = ""; 133 | }; 134 | E3B10A04248684670022B1F2 /* JsApi */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | E3E35B26233E17C700075B23 /* DemoJsApi.h */, 138 | E3E35B27233E17C700075B23 /* DemoJsApi.m */, 139 | E3E35B472340E7C900075B23 /* TestJsApi.h */, 140 | E3E35B462340E7C900075B23 /* TestJsApi.m */, 141 | ); 142 | path = JsApi; 143 | sourceTree = ""; 144 | }; 145 | E3E35AC4233E0BFB00075B23 = { 146 | isa = PBXGroup; 147 | children = ( 148 | E3E35ACF233E0BFB00075B23 /* iOS Example */, 149 | E3E35AE8233E0BFC00075B23 /* iOS ExampleTests */, 150 | E3E35AF3233E0BFC00075B23 /* iOS ExampleUITests */, 151 | E3E35ACE233E0BFB00075B23 /* Products */, 152 | E3E35B08233E164200075B23 /* Frameworks */, 153 | ); 154 | sourceTree = ""; 155 | }; 156 | E3E35ACE233E0BFB00075B23 /* Products */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | E3E35ACD233E0BFB00075B23 /* iOS Example.app */, 160 | E3E35AE5233E0BFC00075B23 /* iOS ExampleTests.xctest */, 161 | E3E35AF0233E0BFC00075B23 /* iOS ExampleUITests.xctest */, 162 | ); 163 | name = Products; 164 | sourceTree = ""; 165 | }; 166 | E3E35ACF233E0BFB00075B23 /* iOS Example */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | E3E35B0B233E173800075B23 /* HCWebViewJsBridge */, 170 | E3E35AD0233E0BFB00075B23 /* AppDelegate.h */, 171 | E3E35AD1233E0BFB00075B23 /* AppDelegate.m */, 172 | E3E35AD3233E0BFB00075B23 /* ViewController.h */, 173 | E3E35AD4233E0BFB00075B23 /* ViewController.m */, 174 | E3B10A04248684670022B1F2 /* JsApi */, 175 | E3E35AD6233E0BFB00075B23 /* Main.storyboard */, 176 | E3E35AD9233E0BFC00075B23 /* Assets.xcassets */, 177 | E3E35ADB233E0BFC00075B23 /* LaunchScreen.storyboard */, 178 | E3E35ADE233E0BFC00075B23 /* Info.plist */, 179 | E3E35ADF233E0BFC00075B23 /* main.m */, 180 | E3B10A032486844B0022B1F2 /* H5 */, 181 | ); 182 | path = "iOS Example"; 183 | sourceTree = ""; 184 | }; 185 | E3E35AE8233E0BFC00075B23 /* iOS ExampleTests */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | E3E35AE9233E0BFC00075B23 /* iOS_ExampleTests.m */, 189 | E3E35AEB233E0BFC00075B23 /* Info.plist */, 190 | ); 191 | path = "iOS ExampleTests"; 192 | sourceTree = ""; 193 | }; 194 | E3E35AF3233E0BFC00075B23 /* iOS ExampleUITests */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | E3E35AF4233E0BFC00075B23 /* iOS_ExampleUITests.m */, 198 | E3E35AF6233E0BFC00075B23 /* Info.plist */, 199 | ); 200 | path = "iOS ExampleUITests"; 201 | sourceTree = ""; 202 | }; 203 | E3E35B08233E164200075B23 /* Frameworks */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | E3E35B09233E164200075B23 /* WebKit.framework */, 207 | ); 208 | name = Frameworks; 209 | sourceTree = ""; 210 | }; 211 | E3E35B0B233E173800075B23 /* HCWebViewJsBridge */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | E3E35B13233E173800075B23 /* HCWKWebViewJsBridge.h */, 215 | E3E35B0D233E173800075B23 /* HCWKWebViewJsBridge.m */, 216 | E3E35B16233E173800075B23 /* HCWebViewJsBridgeUtil.h */, 217 | E3E35B0E233E173800075B23 /* HCWebViewJsBridgeUtil.m */, 218 | E3E35B1A233E173800075B23 /* HCJsApiName.h */, 219 | E3E35B0F233E173800075B23 /* HCJsApiName.m */, 220 | E3E35B10233E173800075B23 /* HCJsApiMethod.h */, 221 | E3E35B19233E173800075B23 /* HCJsApiMethod.m */, 222 | E3E35B15233E173800075B23 /* HCCoreJSExport.h */, 223 | E3E35B12233E173800075B23 /* HCCoreJSExportImpl.h */, 224 | E3E35B17233E173800075B23 /* HCCoreJSExportImpl.m */, 225 | E34C7EA3235D50E60096D99D /* HCWebViewJavaScript.h */, 226 | E34C7EA4235D50E60096D99D /* HCWebViewJavaScript.m */, 227 | ); 228 | name = HCWebViewJsBridge; 229 | path = ../../../HCWebViewJsBridge; 230 | sourceTree = ""; 231 | }; 232 | /* End PBXGroup section */ 233 | 234 | /* Begin PBXNativeTarget section */ 235 | E3E35ACC233E0BFB00075B23 /* iOS Example */ = { 236 | isa = PBXNativeTarget; 237 | buildConfigurationList = E3E35AF9233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS Example" */; 238 | buildPhases = ( 239 | E3E35AC9233E0BFB00075B23 /* Sources */, 240 | E3E35ACA233E0BFB00075B23 /* Frameworks */, 241 | E3E35ACB233E0BFB00075B23 /* Resources */, 242 | ); 243 | buildRules = ( 244 | ); 245 | dependencies = ( 246 | ); 247 | name = "iOS Example"; 248 | productName = "iOS Example"; 249 | productReference = E3E35ACD233E0BFB00075B23 /* iOS Example.app */; 250 | productType = "com.apple.product-type.application"; 251 | }; 252 | E3E35AE4233E0BFC00075B23 /* iOS ExampleTests */ = { 253 | isa = PBXNativeTarget; 254 | buildConfigurationList = E3E35AFC233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS ExampleTests" */; 255 | buildPhases = ( 256 | E3E35AE1233E0BFC00075B23 /* Sources */, 257 | E3E35AE2233E0BFC00075B23 /* Frameworks */, 258 | E3E35AE3233E0BFC00075B23 /* Resources */, 259 | ); 260 | buildRules = ( 261 | ); 262 | dependencies = ( 263 | E3E35AE7233E0BFC00075B23 /* PBXTargetDependency */, 264 | ); 265 | name = "iOS ExampleTests"; 266 | productName = "iOS ExampleTests"; 267 | productReference = E3E35AE5233E0BFC00075B23 /* iOS ExampleTests.xctest */; 268 | productType = "com.apple.product-type.bundle.unit-test"; 269 | }; 270 | E3E35AEF233E0BFC00075B23 /* iOS ExampleUITests */ = { 271 | isa = PBXNativeTarget; 272 | buildConfigurationList = E3E35AFF233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS ExampleUITests" */; 273 | buildPhases = ( 274 | E3E35AEC233E0BFC00075B23 /* Sources */, 275 | E3E35AED233E0BFC00075B23 /* Frameworks */, 276 | E3E35AEE233E0BFC00075B23 /* Resources */, 277 | ); 278 | buildRules = ( 279 | ); 280 | dependencies = ( 281 | E3E35AF2233E0BFC00075B23 /* PBXTargetDependency */, 282 | ); 283 | name = "iOS ExampleUITests"; 284 | productName = "iOS ExampleUITests"; 285 | productReference = E3E35AF0233E0BFC00075B23 /* iOS ExampleUITests.xctest */; 286 | productType = "com.apple.product-type.bundle.ui-testing"; 287 | }; 288 | /* End PBXNativeTarget section */ 289 | 290 | /* Begin PBXProject section */ 291 | E3E35AC5233E0BFB00075B23 /* Project object */ = { 292 | isa = PBXProject; 293 | attributes = { 294 | LastUpgradeCheck = 1020; 295 | ORGANIZATIONNAME = lhc; 296 | TargetAttributes = { 297 | E3E35ACC233E0BFB00075B23 = { 298 | CreatedOnToolsVersion = 10.2; 299 | }; 300 | E3E35AE4233E0BFC00075B23 = { 301 | CreatedOnToolsVersion = 10.2; 302 | TestTargetID = E3E35ACC233E0BFB00075B23; 303 | }; 304 | E3E35AEF233E0BFC00075B23 = { 305 | CreatedOnToolsVersion = 10.2; 306 | TestTargetID = E3E35ACC233E0BFB00075B23; 307 | }; 308 | }; 309 | }; 310 | buildConfigurationList = E3E35AC8233E0BFB00075B23 /* Build configuration list for PBXProject "iOS Example" */; 311 | compatibilityVersion = "Xcode 9.3"; 312 | developmentRegion = en; 313 | hasScannedForEncodings = 0; 314 | knownRegions = ( 315 | en, 316 | Base, 317 | ); 318 | mainGroup = E3E35AC4233E0BFB00075B23; 319 | productRefGroup = E3E35ACE233E0BFB00075B23 /* Products */; 320 | projectDirPath = ""; 321 | projectRoot = ""; 322 | targets = ( 323 | E3E35ACC233E0BFB00075B23 /* iOS Example */, 324 | E3E35AE4233E0BFC00075B23 /* iOS ExampleTests */, 325 | E3E35AEF233E0BFC00075B23 /* iOS ExampleUITests */, 326 | ); 327 | }; 328 | /* End PBXProject section */ 329 | 330 | /* Begin PBXResourcesBuildPhase section */ 331 | E3E35ACB233E0BFB00075B23 /* Resources */ = { 332 | isa = PBXResourcesBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | E3E35B24233E177D00075B23 /* test.html in Resources */, 336 | E3E35ADD233E0BFC00075B23 /* LaunchScreen.storyboard in Resources */, 337 | E3E35ADA233E0BFC00075B23 /* Assets.xcassets in Resources */, 338 | E3E35B25233E177D00075B23 /* hcJsBridge.js in Resources */, 339 | E3E35AD8233E0BFB00075B23 /* Main.storyboard in Resources */, 340 | E3E35B4A2340EC2100075B23 /* vconsole.min.js in Resources */, 341 | E34C7EA2235D46BE0096D99D /* testWithNoJsFile.html in Resources */, 342 | E3B10A06248684900022B1F2 /* hcJsBridge.min.js in Resources */, 343 | E3E35B452340E7A300075B23 /* vue.js in Resources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | E3E35AE3233E0BFC00075B23 /* Resources */ = { 348 | isa = PBXResourcesBuildPhase; 349 | buildActionMask = 2147483647; 350 | files = ( 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | E3E35AEE233E0BFC00075B23 /* Resources */ = { 355 | isa = PBXResourcesBuildPhase; 356 | buildActionMask = 2147483647; 357 | files = ( 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | /* End PBXResourcesBuildPhase section */ 362 | 363 | /* Begin PBXSourcesBuildPhase section */ 364 | E3E35AC9233E0BFB00075B23 /* Sources */ = { 365 | isa = PBXSourcesBuildPhase; 366 | buildActionMask = 2147483647; 367 | files = ( 368 | E3E35B482340E7C900075B23 /* TestJsApi.m in Sources */, 369 | E3E35B1C233E173800075B23 /* HCWebViewJsBridgeUtil.m in Sources */, 370 | E34C7EA5235D50E60096D99D /* HCWebViewJavaScript.m in Sources */, 371 | E3E35AD5233E0BFB00075B23 /* ViewController.m in Sources */, 372 | E3E35B1D233E173800075B23 /* HCJsApiName.m in Sources */, 373 | E3E35B1F233E173800075B23 /* HCCoreJSExportImpl.m in Sources */, 374 | E3E35B28233E17C700075B23 /* DemoJsApi.m in Sources */, 375 | E3E35B1B233E173800075B23 /* HCWKWebViewJsBridge.m in Sources */, 376 | E3E35AE0233E0BFC00075B23 /* main.m in Sources */, 377 | E3E35B21233E173800075B23 /* HCJsApiMethod.m in Sources */, 378 | E3E35AD2233E0BFB00075B23 /* AppDelegate.m in Sources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | E3E35AE1233E0BFC00075B23 /* Sources */ = { 383 | isa = PBXSourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | E3E35AEA233E0BFC00075B23 /* iOS_ExampleTests.m in Sources */, 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | }; 390 | E3E35AEC233E0BFC00075B23 /* Sources */ = { 391 | isa = PBXSourcesBuildPhase; 392 | buildActionMask = 2147483647; 393 | files = ( 394 | E3E35AF5233E0BFC00075B23 /* iOS_ExampleUITests.m in Sources */, 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | }; 398 | /* End PBXSourcesBuildPhase section */ 399 | 400 | /* Begin PBXTargetDependency section */ 401 | E3E35AE7233E0BFC00075B23 /* PBXTargetDependency */ = { 402 | isa = PBXTargetDependency; 403 | target = E3E35ACC233E0BFB00075B23 /* iOS Example */; 404 | targetProxy = E3E35AE6233E0BFC00075B23 /* PBXContainerItemProxy */; 405 | }; 406 | E3E35AF2233E0BFC00075B23 /* PBXTargetDependency */ = { 407 | isa = PBXTargetDependency; 408 | target = E3E35ACC233E0BFB00075B23 /* iOS Example */; 409 | targetProxy = E3E35AF1233E0BFC00075B23 /* PBXContainerItemProxy */; 410 | }; 411 | /* End PBXTargetDependency section */ 412 | 413 | /* Begin PBXVariantGroup section */ 414 | E3E35AD6233E0BFB00075B23 /* Main.storyboard */ = { 415 | isa = PBXVariantGroup; 416 | children = ( 417 | E3E35AD7233E0BFB00075B23 /* Base */, 418 | ); 419 | name = Main.storyboard; 420 | sourceTree = ""; 421 | }; 422 | E3E35ADB233E0BFC00075B23 /* LaunchScreen.storyboard */ = { 423 | isa = PBXVariantGroup; 424 | children = ( 425 | E3E35ADC233E0BFC00075B23 /* Base */, 426 | ); 427 | name = LaunchScreen.storyboard; 428 | sourceTree = ""; 429 | }; 430 | /* End PBXVariantGroup section */ 431 | 432 | /* Begin XCBuildConfiguration section */ 433 | E3E35AF7233E0BFC00075B23 /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | ALWAYS_SEARCH_USER_PATHS = NO; 437 | CLANG_ANALYZER_NONNULL = YES; 438 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 439 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 440 | CLANG_CXX_LIBRARY = "libc++"; 441 | CLANG_ENABLE_MODULES = YES; 442 | CLANG_ENABLE_OBJC_ARC = YES; 443 | CLANG_ENABLE_OBJC_WEAK = YES; 444 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 445 | CLANG_WARN_BOOL_CONVERSION = YES; 446 | CLANG_WARN_COMMA = YES; 447 | CLANG_WARN_CONSTANT_CONVERSION = YES; 448 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 449 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 450 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 451 | CLANG_WARN_EMPTY_BODY = YES; 452 | CLANG_WARN_ENUM_CONVERSION = YES; 453 | CLANG_WARN_INFINITE_RECURSION = YES; 454 | CLANG_WARN_INT_CONVERSION = YES; 455 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 456 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 457 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 460 | CLANG_WARN_STRICT_PROTOTYPES = YES; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | CODE_SIGN_IDENTITY = "iPhone Developer"; 466 | COPY_PHASE_STRIP = NO; 467 | DEBUG_INFORMATION_FORMAT = dwarf; 468 | ENABLE_STRICT_OBJC_MSGSEND = YES; 469 | ENABLE_TESTABILITY = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu11; 471 | GCC_DYNAMIC_NO_PIC = NO; 472 | GCC_NO_COMMON_BLOCKS = YES; 473 | GCC_OPTIMIZATION_LEVEL = 0; 474 | GCC_PREPROCESSOR_DEFINITIONS = ( 475 | "DEBUG=1", 476 | "$(inherited)", 477 | ); 478 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 479 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 480 | GCC_WARN_UNDECLARED_SELECTOR = YES; 481 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 482 | GCC_WARN_UNUSED_FUNCTION = YES; 483 | GCC_WARN_UNUSED_VARIABLE = YES; 484 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 485 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 486 | MTL_FAST_MATH = YES; 487 | ONLY_ACTIVE_ARCH = YES; 488 | SDKROOT = iphoneos; 489 | }; 490 | name = Debug; 491 | }; 492 | E3E35AF8233E0BFC00075B23 /* Release */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | ALWAYS_SEARCH_USER_PATHS = NO; 496 | CLANG_ANALYZER_NONNULL = YES; 497 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 498 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 499 | CLANG_CXX_LIBRARY = "libc++"; 500 | CLANG_ENABLE_MODULES = YES; 501 | CLANG_ENABLE_OBJC_ARC = YES; 502 | CLANG_ENABLE_OBJC_WEAK = YES; 503 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 504 | CLANG_WARN_BOOL_CONVERSION = YES; 505 | CLANG_WARN_COMMA = YES; 506 | CLANG_WARN_CONSTANT_CONVERSION = YES; 507 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 508 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 509 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 510 | CLANG_WARN_EMPTY_BODY = YES; 511 | CLANG_WARN_ENUM_CONVERSION = YES; 512 | CLANG_WARN_INFINITE_RECURSION = YES; 513 | CLANG_WARN_INT_CONVERSION = YES; 514 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 515 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 516 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 517 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 518 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 519 | CLANG_WARN_STRICT_PROTOTYPES = YES; 520 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 521 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 522 | CLANG_WARN_UNREACHABLE_CODE = YES; 523 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 524 | CODE_SIGN_IDENTITY = "iPhone Developer"; 525 | COPY_PHASE_STRIP = NO; 526 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 527 | ENABLE_NS_ASSERTIONS = NO; 528 | ENABLE_STRICT_OBJC_MSGSEND = YES; 529 | GCC_C_LANGUAGE_STANDARD = gnu11; 530 | GCC_NO_COMMON_BLOCKS = YES; 531 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 532 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 533 | GCC_WARN_UNDECLARED_SELECTOR = YES; 534 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 535 | GCC_WARN_UNUSED_FUNCTION = YES; 536 | GCC_WARN_UNUSED_VARIABLE = YES; 537 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 538 | MTL_ENABLE_DEBUG_INFO = NO; 539 | MTL_FAST_MATH = YES; 540 | SDKROOT = iphoneos; 541 | VALIDATE_PRODUCT = YES; 542 | }; 543 | name = Release; 544 | }; 545 | E3E35AFA233E0BFC00075B23 /* Debug */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 549 | CODE_SIGN_STYLE = Manual; 550 | DEVELOPMENT_TEAM = B2TK8ZNGUG; 551 | INFOPLIST_FILE = "iOS Example/Info.plist"; 552 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 553 | LD_RUNPATH_SEARCH_PATHS = ( 554 | "$(inherited)", 555 | "@executable_path/Frameworks", 556 | ); 557 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-Example"; 558 | PRODUCT_NAME = "$(TARGET_NAME)"; 559 | PROVISIONING_PROFILE_SPECIFIER = "BotsDevelopmentPP***"; 560 | TARGETED_DEVICE_FAMILY = "1,2"; 561 | }; 562 | name = Debug; 563 | }; 564 | E3E35AFB233E0BFC00075B23 /* Release */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 568 | CODE_SIGN_STYLE = Manual; 569 | DEVELOPMENT_TEAM = B2TK8ZNGUG; 570 | INFOPLIST_FILE = "iOS Example/Info.plist"; 571 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 572 | LD_RUNPATH_SEARCH_PATHS = ( 573 | "$(inherited)", 574 | "@executable_path/Frameworks", 575 | ); 576 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-Example"; 577 | PRODUCT_NAME = "$(TARGET_NAME)"; 578 | PROVISIONING_PROFILE_SPECIFIER = "BotsDevelopmentPP***"; 579 | TARGETED_DEVICE_FAMILY = "1,2"; 580 | }; 581 | name = Release; 582 | }; 583 | E3E35AFD233E0BFC00075B23 /* Debug */ = { 584 | isa = XCBuildConfiguration; 585 | buildSettings = { 586 | BUNDLE_LOADER = "$(TEST_HOST)"; 587 | CODE_SIGN_STYLE = Automatic; 588 | DEVELOPMENT_TEAM = L3JRZS7A28; 589 | INFOPLIST_FILE = "iOS ExampleTests/Info.plist"; 590 | LD_RUNPATH_SEARCH_PATHS = ( 591 | "$(inherited)", 592 | "@executable_path/Frameworks", 593 | "@loader_path/Frameworks", 594 | ); 595 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-ExampleTests"; 596 | PRODUCT_NAME = "$(TARGET_NAME)"; 597 | TARGETED_DEVICE_FAMILY = "1,2"; 598 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOS Example.app/iOS Example"; 599 | }; 600 | name = Debug; 601 | }; 602 | E3E35AFE233E0BFC00075B23 /* Release */ = { 603 | isa = XCBuildConfiguration; 604 | buildSettings = { 605 | BUNDLE_LOADER = "$(TEST_HOST)"; 606 | CODE_SIGN_STYLE = Automatic; 607 | DEVELOPMENT_TEAM = L3JRZS7A28; 608 | INFOPLIST_FILE = "iOS ExampleTests/Info.plist"; 609 | LD_RUNPATH_SEARCH_PATHS = ( 610 | "$(inherited)", 611 | "@executable_path/Frameworks", 612 | "@loader_path/Frameworks", 613 | ); 614 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-ExampleTests"; 615 | PRODUCT_NAME = "$(TARGET_NAME)"; 616 | TARGETED_DEVICE_FAMILY = "1,2"; 617 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOS Example.app/iOS Example"; 618 | }; 619 | name = Release; 620 | }; 621 | E3E35B00233E0BFC00075B23 /* Debug */ = { 622 | isa = XCBuildConfiguration; 623 | buildSettings = { 624 | CODE_SIGN_STYLE = Automatic; 625 | DEVELOPMENT_TEAM = L3JRZS7A28; 626 | INFOPLIST_FILE = "iOS ExampleUITests/Info.plist"; 627 | LD_RUNPATH_SEARCH_PATHS = ( 628 | "$(inherited)", 629 | "@executable_path/Frameworks", 630 | "@loader_path/Frameworks", 631 | ); 632 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-ExampleUITests"; 633 | PRODUCT_NAME = "$(TARGET_NAME)"; 634 | TARGETED_DEVICE_FAMILY = "1,2"; 635 | TEST_TARGET_NAME = "iOS Example"; 636 | }; 637 | name = Debug; 638 | }; 639 | E3E35B01233E0BFC00075B23 /* Release */ = { 640 | isa = XCBuildConfiguration; 641 | buildSettings = { 642 | CODE_SIGN_STYLE = Automatic; 643 | DEVELOPMENT_TEAM = L3JRZS7A28; 644 | INFOPLIST_FILE = "iOS ExampleUITests/Info.plist"; 645 | LD_RUNPATH_SEARCH_PATHS = ( 646 | "$(inherited)", 647 | "@executable_path/Frameworks", 648 | "@loader_path/Frameworks", 649 | ); 650 | PRODUCT_BUNDLE_IDENTIFIER = "com.lhc.iOS-ExampleUITests"; 651 | PRODUCT_NAME = "$(TARGET_NAME)"; 652 | TARGETED_DEVICE_FAMILY = "1,2"; 653 | TEST_TARGET_NAME = "iOS Example"; 654 | }; 655 | name = Release; 656 | }; 657 | /* End XCBuildConfiguration section */ 658 | 659 | /* Begin XCConfigurationList section */ 660 | E3E35AC8233E0BFB00075B23 /* Build configuration list for PBXProject "iOS Example" */ = { 661 | isa = XCConfigurationList; 662 | buildConfigurations = ( 663 | E3E35AF7233E0BFC00075B23 /* Debug */, 664 | E3E35AF8233E0BFC00075B23 /* Release */, 665 | ); 666 | defaultConfigurationIsVisible = 0; 667 | defaultConfigurationName = Release; 668 | }; 669 | E3E35AF9233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS Example" */ = { 670 | isa = XCConfigurationList; 671 | buildConfigurations = ( 672 | E3E35AFA233E0BFC00075B23 /* Debug */, 673 | E3E35AFB233E0BFC00075B23 /* Release */, 674 | ); 675 | defaultConfigurationIsVisible = 0; 676 | defaultConfigurationName = Release; 677 | }; 678 | E3E35AFC233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS ExampleTests" */ = { 679 | isa = XCConfigurationList; 680 | buildConfigurations = ( 681 | E3E35AFD233E0BFC00075B23 /* Debug */, 682 | E3E35AFE233E0BFC00075B23 /* Release */, 683 | ); 684 | defaultConfigurationIsVisible = 0; 685 | defaultConfigurationName = Release; 686 | }; 687 | E3E35AFF233E0BFC00075B23 /* Build configuration list for PBXNativeTarget "iOS ExampleUITests" */ = { 688 | isa = XCConfigurationList; 689 | buildConfigurations = ( 690 | E3E35B00233E0BFC00075B23 /* Debug */, 691 | E3E35B01233E0BFC00075B23 /* Release */, 692 | ); 693 | defaultConfigurationIsVisible = 0; 694 | defaultConfigurationName = Release; 695 | }; 696 | /* End XCConfigurationList section */ 697 | }; 698 | rootObject = E3E35AC5233E0BFB00075B23 /* Project object */; 699 | } 700 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example.xcodeproj/xcuserdata/lhc.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS Example.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 43 | 56 | 69 | 75 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 145 | 159 | 173 | 187 | 193 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/H5/hcJsBridge.js: -------------------------------------------------------------------------------- 1 | ;(function() { 2 | 3 | if (window.hcJsBridge) { 4 | return; 5 | } 6 | 7 | window.hcJsBridge = { 8 | callHandler: callHandler, 9 | registerHandler: registerHandler, 10 | handleMessageFromNative: handleMessageFromNative, 11 | messageHandlers: {}, 12 | messageCallbacks: {} 13 | }; 14 | var uniqueId = 1; 15 | 16 | function callHandler(name, data, responseCallback) { 17 | if (arguments.length == 2 && typeof data == 'function') { 18 | responseCallback = data; 19 | data = null; 20 | } 21 | var message = {name:name, data:data}; 22 | if (responseCallback) { 23 | var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime(); 24 | message["callbackId"] = callbackId; 25 | hcJsBridge.messageCallbacks[callbackId] = responseCallback; 26 | } 27 | var messageJson = JSON.stringify(message); 28 | if (typeof nativeBridgeHead === "undefined") { 29 | window.webkit.messageHandlers.handleMessage.postMessage(messageJson); 30 | } else { 31 | nativeBridgeHead.handleMessage(messageJson); 32 | } 33 | } 34 | 35 | function registerHandler(name, handler) { 36 | hcJsBridge.messageHandlers[name] = handler; 37 | } 38 | 39 | function handleMessageFromNative(messageJSON) { 40 | 41 | var message = messageJSON; 42 | if (typeof message != "object") { 43 | message = JSON.parse(unescape(messageJSON)); 44 | } 45 | var responseId = message["responseId"]; 46 | if (responseId) { 47 | var responseData = message["responseData"]; 48 | var callback = hcJsBridge.messageCallbacks[responseId]; 49 | callback(responseData); 50 | } else { 51 | var messageName = message["name"]; 52 | var messageData = message["data"]; 53 | var messageCallbackId = message["callbackId"]; 54 | 55 | var handler = hcJsBridge.messageHandlers[messageName]; 56 | var responseCallback = function(data) { 57 | var responseMessage = { 58 | responseId: messageCallbackId, 59 | responseData: data 60 | }; 61 | var responseMessageJson = JSON.stringify(responseMessage); 62 | if (typeof nativeBridgeHead === "undefined") { 63 | window.webkit.messageHandlers.handleResponseMessage.postMessage(responseMessageJson); 64 | } else { 65 | nativeBridgeHead.handleResponseMessage(responseMessageJson); 66 | } 67 | }; 68 | handler(messageData, responseCallback); 69 | } 70 | } 71 | 72 | setTimeout(function () { 73 | if (typeof nativeBridgeHead === "undefined") { 74 | window.webkit.messageHandlers.handleStartupMessage.postMessage(""); 75 | } else { 76 | nativeBridgeHead.handleStartupMessage(); 77 | } 78 | }, 0); 79 | })(); 80 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/H5/hcJsBridge.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Powered by uglifiyJS v2.6.1, Build by http://tool.uis.cc/jsmin/ 3 | * build time: Tue May 12 2020 14:57:56 GMT+0800 (中国标准时间) 4 | */ 5 | !function(){function e(e,a,s){2==arguments.length&&"function"==typeof a&&(s=a,a=null);var d={name:e,data:a};if(s){var i="cb_"+n++ +"_"+(new Date).getTime();d.callbackId=i,hcJsBridge.messageCallbacks[i]=s}var t=JSON.stringify(d);"undefined"==typeof nativeBridgeHead?window.webkit.messageHandlers.handleMessage.postMessage(t):nativeBridgeHead.handleMessage(t)}function a(e,a){hcJsBridge.messageHandlers[e]=a}function s(e){var a=e;"object"!=typeof a&&(a=JSON.parse(unescape(e)));var s=a.responseId;if(s){var n=a.responseData,d=hcJsBridge.messageCallbacks[s];d(n)}else{var i=a.name,t=a.data,r=a.callbackId,g=hcJsBridge.messageHandlers[i],l=function(e){var a={responseId:r,responseData:e},s=JSON.stringify(a);"undefined"==typeof nativeBridgeHead?window.webkit.messageHandlers.handleResponseMessage.postMessage(s):nativeBridgeHead.handleResponseMessage(s)};g(t,l)}}if(!window.hcJsBridge){window.hcJsBridge={callHandler:e,registerHandler:a,handleMessageFromNative:s,messageHandlers:{},messageCallbacks:{}};var n=1;setTimeout(function(){"undefined"==typeof nativeBridgeHead?window.webkit.messageHandlers.handleStartupMessage.postMessage(""):nativeBridgeHead.handleStartupMessage()},0)}}(); 6 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/H5/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HCJsBridge Test 7 | 11 | 12 | 13 | 14 | 15 | 16 |

HCJsBridge Demo

17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 | 27 |
28 |
29 |

Log:

30 |
31 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/H5/testWithNoJsFile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HCJsBridge Test With No hcJsBridge.js 7 | 11 | 12 | 13 | 14 | 15 |

HCJsBridge Demo With No hcJsBridge.js

16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 | 26 |
27 |
28 |

Log:

29 |
30 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/H5/vconsole.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vConsole v3.2.0 (https://github.com/Tencent/vConsole) 3 | * 4 | * Tencent is pleased to support the open source community by making vConsole available. 5 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. 6 | * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 7 | * http://opensource.org/licenses/MIT 8 | * 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. 9 | */ 10 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.VConsole=t():e.VConsole=t()}(this,function(){return function(e){function t(n){if(o[n])return o[n].exports;var i=o[n]={exports:{},id:n,loaded:!1};return e[n].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var o={};return t.m=e,t.c=o,t.p="",t(0)}([function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),o(1);var i=o(2),a=n(i),r=o(18),l=n(r);a["default"].VConsolePlugin=l["default"],t["default"]=a["default"],e.exports=t["default"]},function(e,t){"use strict";if("undefined"==typeof Symbol){window.Symbol=function(){};var o="__symbol_iterator_key";window.Symbol.iterator=o,Array.prototype[o]=function(){var e=this,t=0;return{next:function(){return{done:e.length===t,value:e.length===t?void 0:e[t++]}}}}}},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var r=function(){function e(e,t){for(var o=0;odocument.documentElement.offsetWidth&&(o=document.documentElement.offsetWidth-t.offsetWidth),n+t.offsetHeight>document.documentElement.offsetHeight&&(n=document.documentElement.offsetHeight-t.offsetHeight),0>o&&(o=0),0>n&&(n=0),this.switchPos.x=o,this.switchPos.y=n,v["default"].one(".vc-switch").style.right=o+"px",v["default"].one(".vc-switch").style.bottom=n+"px");var i=window.devicePixelRatio||1,a=document.querySelector('[name="viewport"]');if(a&&a.content){var r=a.content.match(/initial\-scale\=\d+(\.\d+)?/),l=r?parseFloat(r[0].split("=")[1]):1;1>l&&(this.$dom.style.fontSize=13*i+"px")}v["default"].one(".vc-mask",this.$dom).style.display="none"}},{key:"_mockTap",value:function(){var e=700,t=10,o=void 0,n=void 0,i=void 0,a=!1,r=null;this.$dom.addEventListener("touchstart",function(e){if(void 0===o){var t=e.targetTouches[0];n=t.pageX,i=t.pageY,o=e.timeStamp,r=e.target.nodeType===Node.TEXT_NODE?e.target.parentNode:e.target}},!1),this.$dom.addEventListener("touchmove",function(e){var o=e.changedTouches[0];(Math.abs(o.pageX-n)>t||Math.abs(o.pageY-i)>t)&&(a=!0)}),this.$dom.addEventListener("touchend",function(t){if(a===!1&&t.timeStamp-o0){var n=o.touches[0].pageX-e.switchPos.startX,i=o.touches[0].pageY-e.switchPos.startY,a=e.switchPos.x-n,r=e.switchPos.y-i;a+t.offsetWidth>document.documentElement.offsetWidth&&(a=document.documentElement.offsetWidth-t.offsetWidth),r+t.offsetHeight>document.documentElement.offsetHeight&&(r=document.documentElement.offsetHeight-t.offsetHeight),0>a&&(a=0),0>r&&(r=0),t.style.right=a+"px",t.style.bottom=r+"px",e.switchPos.endX=a,e.switchPos.endY=r,o.preventDefault()}}),v["default"].bind(v["default"].one(".vc-switch",e.$dom),"click",function(){e.show()}),v["default"].bind(v["default"].one(".vc-hide",e.$dom),"click",function(){e.hide()}),v["default"].bind(v["default"].one(".vc-mask",e.$dom),"click",function(t){return t.target!=v["default"].one(".vc-mask")?!1:void e.hide()}),v["default"].delegate(v["default"].one(".vc-tabbar",e.$dom),"click",".vc-tab",function(t){var o=this.dataset.tab;o!=e.activedTab&&e.showTab(o)}),v["default"].bind(v["default"].one(".vc-panel",e.$dom),"transitionend webkitTransitionEnd oTransitionEnd otransitionend",function(t){return t.target!=v["default"].one(".vc-panel")?!1:void(v["default"].hasClass(e.$dom,"vc-toggle")||(t.target.style.display="none"))});var o=v["default"].one(".vc-content",e.$dom),n=!1;v["default"].bind(o,"touchstart",function(e){var t=o.scrollTop,i=o.scrollHeight,a=t+o.offsetHeight;0===t?(o.scrollTop=1,0===o.scrollTop&&(v["default"].hasClass(e.target,"vc-cmd-input")||(n=!0))):a===i&&(o.scrollTop=t-1,o.scrollTop===t&&(v["default"].hasClass(e.target,"vc-cmd-input")||(n=!0)))}),v["default"].bind(o,"touchmove",function(e){n&&e.preventDefault()}),v["default"].bind(o,"touchend",function(e){n=!1})}},{key:"_autoRun",value:function(){this.isInited=!0;for(var e in this.pluginList)this._initPlugin(this.pluginList[e]);this.tabList.length>0&&this.showTab(this.tabList[0]),this.triggerEvent("ready")}},{key:"triggerEvent",value:function(e,t){e="on"+e.charAt(0).toUpperCase()+e.slice(1),d.isFunction(this.option[e])&&this.option[e].apply(this,t)}},{key:"_initPlugin",value:function(e){var t=this;e.vConsole=this,e.trigger("init"),e.trigger("renderTab",function(o){t.tabList.push(e.id);var n=v["default"].render(g["default"],{id:e.id,name:e.name});v["default"].one(".vc-tabbar",t.$dom).insertAdjacentElement("beforeend",n);var i=v["default"].render(m["default"],{id:e.id});o&&(d.isString(o)?i.innerHTML+=o:d.isFunction(o.appendTo)?o.appendTo(i):d.isElement(o)&&i.insertAdjacentElement("beforeend",o)),v["default"].one(".vc-content",t.$dom).insertAdjacentElement("beforeend",i)}),e.trigger("addTopBar",function(o){if(o)for(var n=v["default"].one(".vc-topbar",t.$dom),i=function(t){var i=o[t],a=v["default"].render(_["default"],{name:i.name||"Undefined",className:i.className||"",pluginID:e.id});if(i.data)for(var r in i.data)a.dataset[r]=i.data[r];d.isFunction(i.onClick)&&v["default"].bind(a,"click",function(t){var o=i.onClick.call(a);o===!1||(v["default"].removeClass(v["default"].all(".vc-topbar-"+e.id),"vc-actived"),v["default"].addClass(a,"vc-actived"))}),n.insertAdjacentElement("beforeend",a)},a=0;a-1&&this.tabList.splice(c,1);try{delete this.pluginList[e]}catch(s){this.pluginList[e]=void 0}return this.activedTab==e&&this.tabList.length>0&&this.showTab(this.tabList[0]),!0}},{key:"show",value:function(){if(this.isInited){var e=this,t=v["default"].one(".vc-panel",this.$dom);t.style.display="block",setTimeout(function(){v["default"].addClass(e.$dom,"vc-toggle"),e._triggerPluginsEvent("showConsole");var t=v["default"].one(".vc-mask",e.$dom);t.style.display="block"},10)}}},{key:"hide",value:function(){if(this.isInited){v["default"].removeClass(this.$dom,"vc-toggle"),this._triggerPluginsEvent("hideConsole");var e=v["default"].one(".vc-mask",this.$dom),t=v["default"].one(".vc-panel",this.$dom);v["default"].bind(e,"transitionend",function(o){e.style.display="none",t.style.display="none"})}}},{key:"showSwitch",value:function(){if(this.isInited){var e=v["default"].one(".vc-switch",this.$dom);e.style.display="block"}}},{key:"hideSwitch",value:function(){if(this.isInited){var e=v["default"].one(".vc-switch",this.$dom);e.style.display="none"}}},{key:"showTab",value:function(e){if(this.isInited){var t=v["default"].one("#__vc_log_"+e);v["default"].removeClass(v["default"].all(".vc-tab",this.$dom),"vc-actived"),v["default"].addClass(v["default"].one("#__vc_tab_"+e),"vc-actived"),v["default"].removeClass(v["default"].all(".vc-logbox",this.$dom),"vc-actived"),v["default"].addClass(t,"vc-actived");var o=v["default"].all(".vc-topbar-"+e,this.$dom);v["default"].removeClass(v["default"].all(".vc-toptab",this.$dom),"vc-toggle"),v["default"].addClass(o,"vc-toggle"),o.length>0?v["default"].addClass(v["default"].one(".vc-content",this.$dom),"vc-has-topbar"):v["default"].removeClass(v["default"].one(".vc-content",this.$dom),"vc-has-topbar"),v["default"].removeClass(v["default"].all(".vc-tool",this.$dom),"vc-toggle"),v["default"].addClass(v["default"].all(".vc-tool-"+e,this.$dom),"vc-toggle"),this.activedTab&&this._triggerPluginEvent(this.activedTab,"hide"),this.activedTab=e,this._triggerPluginEvent(this.activedTab,"show")}}},{key:"setOption",value:function(e,t){if(d.isString(e))this.option[e]=t,this._triggerPluginsEvent("updateOption");else if(d.isObject(e)){for(var o in e)this.option[o]=e[o];this._triggerPluginsEvent("updateOption")}else console.debug("The first parameter of vConsole.setOption() must be a string or an object.")}},{key:"destroy",value:function(){if(this.isInited){for(var e=Object.keys(this.pluginList),t=e.length-1;t>=0;t--)this.removePlugin(e[t]);this.$dom.parentNode.removeChild(this.$dom)}}}]),e}();t["default"]=A,e.exports=t["default"]},function(e,t){e.exports={name:"vconsole",version:"3.2.0",description:"A lightweight, extendable front-end developer tool for mobile web page.",homepage:"https://github.com/Tencent/vConsole",main:"dist/vconsole.min.js",scripts:{test:"mocha",dist:"webpack"},keywords:["console","debug","mobile"],repository:{type:"git",url:"git+https://github.com/Tencent/vConsole.git"},dependencies:{},devDependencies:{"babel-core":"^6.7.7","babel-loader":"^6.2.4","babel-plugin-add-module-exports":"^0.1.4","babel-preset-es2015":"^6.6.0","babel-preset-stage-3":"^6.5.0",chai:"^3.5.0","css-loader":"^0.23.1","extract-text-webpack-plugin":"^1.0.1","html-loader":"^0.4.3",jsdom:"^9.2.1","json-loader":"^0.5.4",less:"^2.5.3","less-loader":"^2.2.3",mocha:"^2.5.3","style-loader":"^0.13.1",webpack:"~1.12.11"},author:"Tencent",license:"MIT"}},function(e,t){"use strict";function o(e){var t=e>0?new Date(e):new Date,o=t.getDate()<10?"0"+t.getDate():t.getDate(),n=t.getMonth()<9?"0"+(t.getMonth()+1):t.getMonth()+1,i=t.getFullYear(),a=t.getHours()<10?"0"+t.getHours():t.getHours(),r=t.getMinutes()<10?"0"+t.getMinutes():t.getMinutes(),l=t.getSeconds()<10?"0"+t.getSeconds():t.getSeconds(),c=t.getMilliseconds()<10?"0"+t.getMilliseconds():t.getMilliseconds();return 100>c&&(c="0"+c),{time:+t,year:i,month:n,day:o,hour:a,minute:r,second:l,millisecond:c}}function n(e){return"[object Number]"==Object.prototype.toString.call(e)}function i(e){return"[object String]"==Object.prototype.toString.call(e)}function a(e){return"[object Array]"==Object.prototype.toString.call(e)}function r(e){return"[object Boolean]"==Object.prototype.toString.call(e)}function l(e){return"[object Undefined]"==Object.prototype.toString.call(e)}function c(e){return"[object Null]"==Object.prototype.toString.call(e)}function s(e){return"[object Symbol]"==Object.prototype.toString.call(e)}function d(e){return!("[object Object]"!=Object.prototype.toString.call(e)&&(n(e)||i(e)||r(e)||a(e)||c(e)||u(e)||l(e)||s(e)))}function u(e){return"[object Function]"==Object.prototype.toString.call(e)}function v(e){return"object"===("undefined"==typeof HTMLElement?"undefined":w(HTMLElement))?e instanceof HTMLElement:e&&"object"===("undefined"==typeof e?"undefined":w(e))&&null!==e&&1===e.nodeType&&"string"==typeof e.nodeName}function f(e){var t=Object.prototype.toString.call(e);return"[object global]"==t||"[object Window]"==t||"[object DOMWindow]"==t}function p(e){var t=Object.prototype.hasOwnProperty;if(!e||"object"!==("undefined"==typeof e?"undefined":w(e))||e.nodeType||f(e))return!1;try{if(e.constructor&&!t.call(e,"constructor")&&!t.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(o){return!1}var n=void 0;for(n in e);return void 0===n||t.call(e,n)}function h(e){return document.createElement("a").appendChild(document.createTextNode(e)).parentNode.innerHTML}function g(e){var t=arguments.length<=1||void 0===arguments[1]?" ":arguments[1],o=arguments.length<=2||void 0===arguments[2]?"CIRCULAR_DEPENDECY_OBJECT":arguments[2],n=[],i=JSON.stringify(e,function(e,t){if("object"===("undefined"==typeof t?"undefined":w(t))&&null!==t){if(~n.indexOf(t))return o;n.push(t)}return t},t);return n=null,i}function b(e){if(!d(e)&&!a(e))return[];var t=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],o=[];for(var n in e)t.indexOf(n)<0&&o.push(n);return o=o.sort()}function m(e){return Object.prototype.toString.call(e).replace("[object ","").replace("]","")}function y(e,t){window.localStorage&&(e="vConsole_"+e,localStorage.setItem(e,t))}function _(e){return window.localStorage?(e="vConsole_"+e,localStorage.getItem(e)):void 0}Object.defineProperty(t,"__esModule",{value:!0});var w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};t.getDate=o,t.isNumber=n,t.isString=i,t.isArray=a,t.isBoolean=r,t.isUndefined=l,t.isNull=c,t.isSymbol=s,t.isObject=d,t.isFunction=u,t.isElement=v,t.isWindow=f,t.isPlainObject=p,t.htmlEncode=h,t.JSONStringify=g,t.getObjAllKeys=b,t.getObjName=m,t.setStorage=y,t.getStorage=_},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0});var i=o(4),a=o(6),r=n(a),l={};l.one=function(e,t){return t?t.querySelector(e):document.querySelector(e)},l.all=function(e,t){var o=void 0,n=[];return o=t?t.querySelectorAll(e):document.querySelectorAll(e),o&&o.length>0&&(n=Array.prototype.slice.call(o)),n},l.addClass=function(e,t){if(e){(0,i.isArray)(e)||(e=[e]);for(var o=0;o-1||(a.push(t),e[o].className=a.join(" "))}}},l.removeClass=function(e,t){if(e){(0,i.isArray)(e)||(e=[e]);for(var o=0;o0&&(d=s[0].getAttribute("nonce")||"");var u=document.createElement("SCRIPT");u.innerHTML=a,u.setAttribute("nonce",d),document.documentElement.appendChild(u);var v=__mito_result;if(document.documentElement.removeChild(u),!o){var f=document.createElement("DIV");f.innerHTML=v,v=f.children[0]}return v}Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=o,e.exports=t["default"]},function(e,t,o){var n=o(8);"string"==typeof n&&(n=[[e.id,n,""]]);o(10)(n,{});n.locals&&(e.exports=n.locals)},function(e,t,o){t=e.exports=o(9)(),t.push([e.id,'#__vconsole{color:#000;font-size:13px;font-family:Helvetica Neue,Helvetica,Arial,sans-serif}#__vconsole .vc-max-height{max-height:19.23076923em}#__vconsole .vc-max-height-line{max-height:3.38461538em}#__vconsole .vc-min-height{min-height:3.07692308em}#__vconsole dd,#__vconsole dl,#__vconsole pre{margin:0}#__vconsole .vc-switch{display:block;position:fixed;right:.76923077em;bottom:.76923077em;color:#fff;background-color:#04be02;line-height:1;font-size:1.07692308em;padding:.61538462em 1.23076923em;z-index:10000;border-radius:.30769231em;box-shadow:0 0 .61538462em rgba(0,0,0,.4)}#__vconsole .vc-mask{top:0;background:transparent;z-index:10001;transition:background .3s;-webkit-tap-highlight-color:transparent;overflow-y:scroll}#__vconsole .vc-mask,#__vconsole .vc-panel{display:none;position:fixed;left:0;right:0;bottom:0}#__vconsole .vc-panel{min-height:85%;z-index:10002;background-color:#efeff4;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:translateY(100%);transform:translateY(100%)}#__vconsole .vc-tabbar{border-bottom:1px solid #d9d9d9;overflow-x:auto;height:3em;width:auto;white-space:nowrap}#__vconsole .vc-tabbar .vc-tab{display:inline-block;line-height:3em;padding:0 1.15384615em;border-right:1px solid #d9d9d9;text-decoration:none;color:#000;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}#__vconsole .vc-tabbar .vc-tab:active{background-color:rgba(0,0,0,.15)}#__vconsole .vc-tabbar .vc-tab.vc-actived{background-color:#fff}#__vconsole .vc-content{background-color:#fff;overflow-x:hidden;overflow-y:auto;position:absolute;top:3.07692308em;left:0;right:0;bottom:3.07692308em;-webkit-overflow-scrolling:touch}#__vconsole .vc-content.vc-has-topbar{top:5.46153846em}#__vconsole .vc-topbar{background-color:#fbf9fe;display:flex;display:-webkit-box;flex-direction:row;flex-wrap:wrap;-webkit-box-direction:row;-webkit-flex-wrap:wrap;width:100%}#__vconsole .vc-topbar .vc-toptab{display:none;flex:1;-webkit-box-flex:1;line-height:2.30769231em;padding:0 1.15384615em;border-bottom:1px solid #d9d9d9;text-decoration:none;text-align:center;color:#000;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}#__vconsole .vc-topbar .vc-toptab.vc-toggle{display:block}#__vconsole .vc-topbar .vc-toptab:active{background-color:rgba(0,0,0,.15)}#__vconsole .vc-topbar .vc-toptab.vc-actived{border-bottom:1px solid #3e82f7}#__vconsole .vc-logbox{display:none;position:relative;min-height:100%}#__vconsole .vc-logbox i{font-style:normal}#__vconsole .vc-logbox .vc-log{padding-bottom:3em;-webkit-tap-highlight-color:transparent}#__vconsole .vc-logbox .vc-log:empty:before{content:"Empty";color:#999;position:absolute;top:45%;left:0;right:0;bottom:0;font-size:1.15384615em;text-align:center}#__vconsole .vc-logbox .vc-item{margin:0;padding:.46153846em .61538462em;overflow:hidden;line-height:1.3;border-bottom:1px solid #eee;word-break:break-word}#__vconsole .vc-logbox .vc-item-info{color:#6a5acd}#__vconsole .vc-logbox .vc-item-debug{color:#daa520}#__vconsole .vc-logbox .vc-item-warn{color:orange;border-color:#ffb930;background-color:#fffacd}#__vconsole .vc-logbox .vc-item-error{color:#dc143c;border-color:#f4a0ab;background-color:#ffe4e1}#__vconsole .vc-logbox .vc-log.vc-log-partly .vc-item{display:none}#__vconsole .vc-logbox .vc-log.vc-log-partly-error .vc-item-error,#__vconsole .vc-logbox .vc-log.vc-log-partly-info .vc-item-info,#__vconsole .vc-logbox .vc-log.vc-log-partly-log .vc-item-log,#__vconsole .vc-logbox .vc-log.vc-log-partly-warn .vc-item-warn{display:block}#__vconsole .vc-logbox .vc-item .vc-item-content{margin-right:4.61538462em;display:block}#__vconsole .vc-logbox .vc-item .vc-item-meta{color:#888;float:right;width:4.61538462em;text-align:right}#__vconsole .vc-logbox .vc-item.vc-item-nometa .vc-item-content{margin-right:0}#__vconsole .vc-logbox .vc-item.vc-item-nometa .vc-item-meta{display:none}#__vconsole .vc-logbox .vc-item .vc-item-code{display:block;white-space:pre-wrap;overflow:auto;position:relative}#__vconsole .vc-logbox .vc-item .vc-item-code.vc-item-code-input,#__vconsole .vc-logbox .vc-item .vc-item-code.vc-item-code-output{padding-left:.92307692em}#__vconsole .vc-logbox .vc-item .vc-item-code.vc-item-code-input:before,#__vconsole .vc-logbox .vc-item .vc-item-code.vc-item-code-output:before{content:"\\203A";position:absolute;top:-.23076923em;left:0;font-size:1.23076923em;color:#6a5acd}#__vconsole .vc-logbox .vc-item .vc-item-code.vc-item-code-output:before{content:"\\2039"}#__vconsole .vc-logbox .vc-item .vc-fold{display:block;overflow:auto;-webkit-overflow-scrolling:touch}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-outer{display:block;font-style:italic;padding-left:.76923077em;position:relative}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-outer:active{background-color:#e6e6e6}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-outer:before{content:"";position:absolute;top:.30769231em;left:.15384615em;width:0;height:0;border:.30769231em solid transparent;border-left-color:#000}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-outer.vc-toggle:before{top:.46153846em;left:0;border-top-color:#000;border-left-color:transparent}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-inner{display:none;margin-left:.76923077em}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-inner.vc-toggle{display:block}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-inner .vc-code-key{margin-left:.76923077em}#__vconsole .vc-logbox .vc-item .vc-fold .vc-fold-outer .vc-code-key{margin-left:0}#__vconsole .vc-logbox .vc-code-key{color:#905}#__vconsole .vc-logbox .vc-code-private-key{color:#d391b5}#__vconsole .vc-logbox .vc-code-function{color:#905;font-style:italic}#__vconsole .vc-logbox .vc-code-boolean,#__vconsole .vc-logbox .vc-code-number{color:#0086b3}#__vconsole .vc-logbox .vc-code-string{color:#183691}#__vconsole .vc-logbox .vc-code-null,#__vconsole .vc-logbox .vc-code-undefined{color:#666}#__vconsole .vc-logbox .vc-cmd{position:absolute;height:3.07692308em;left:0;right:0;bottom:0;border-top:1px solid #d9d9d9;display:block!important}#__vconsole .vc-logbox .vc-cmd .vc-cmd-input-wrap{display:block;height:2.15384615em;margin-right:3.07692308em;padding:.46153846em .61538462em}#__vconsole .vc-logbox .vc-cmd .vc-cmd-input{width:100%;border:none;resize:none;outline:none;padding:0;font-size:.92307692em}#__vconsole .vc-logbox .vc-cmd .vc-cmd-input::-webkit-input-placeholder{line-height:2.15384615em}#__vconsole .vc-logbox .vc-cmd .vc-cmd-btn{position:absolute;top:0;right:0;bottom:0;width:3.07692308em;border:none;background-color:#efeff4;outline:none;-webkit-touch-callout:none;font-size:1em}#__vconsole .vc-logbox .vc-cmd .vc-cmd-btn:active{background-color:rgba(0,0,0,.15)}#__vconsole .vc-logbox .vc-group .vc-group-preview{-webkit-touch-callout:none}#__vconsole .vc-logbox .vc-group .vc-group-preview:active{background-color:#e6e6e6}#__vconsole .vc-logbox .vc-group .vc-group-detail{display:none;padding:0 0 .76923077em 1.53846154em;border-bottom:1px solid #eee}#__vconsole .vc-logbox .vc-group.vc-actived .vc-group-detail{display:block;background-color:#fbf9fe}#__vconsole .vc-logbox .vc-group.vc-actived .vc-table-row{background-color:#fff}#__vconsole .vc-logbox .vc-group.vc-actived .vc-group-preview{background-color:#fbf9fe}#__vconsole .vc-logbox .vc-table .vc-table-row{display:flex;display:-webkit-flex;flex-direction:row;flex-wrap:wrap;-webkit-box-direction:row;-webkit-flex-wrap:wrap;overflow:hidden;border-bottom:1px solid #eee}#__vconsole .vc-logbox .vc-table .vc-table-row.vc-left-border{border-left:1px solid #eee}#__vconsole .vc-logbox .vc-table .vc-table-col{flex:1;-webkit-box-flex:1;padding:.23076923em .30769231em;border-left:1px solid #eee;overflow:auto;white-space:pre-wrap;word-break:break-word;-webkit-overflow-scrolling:touch}#__vconsole .vc-logbox .vc-table .vc-table-col:first-child{border:none}#__vconsole .vc-logbox .vc-table .vc-small .vc-table-col{padding:0 .30769231em;font-size:.92307692em}#__vconsole .vc-logbox .vc-table .vc-table-col-2{flex:2;-webkit-box-flex:2}#__vconsole .vc-logbox .vc-table .vc-table-col-3{flex:3;-webkit-box-flex:3}#__vconsole .vc-logbox .vc-table .vc-table-col-4{flex:4;-webkit-box-flex:4}#__vconsole .vc-logbox .vc-table .vc-table-col-5{flex:5;-webkit-box-flex:5}#__vconsole .vc-logbox .vc-table .vc-table-col-6{flex:6;-webkit-box-flex:6}#__vconsole .vc-logbox .vc-table .vc-table-row-error{border-color:#f4a0ab;background-color:#ffe4e1}#__vconsole .vc-logbox .vc-table .vc-table-row-error .vc-table-col{color:#dc143c;border-color:#f4a0ab}#__vconsole .vc-logbox .vc-table .vc-table-col-title{font-weight:700}#__vconsole .vc-logbox.vc-actived{display:block}#__vconsole .vc-toolbar{border-top:1px solid #d9d9d9;line-height:3em;position:absolute;left:0;right:0;bottom:0;display:flex;display:-webkit-box;flex-direction:row;-webkit-box-direction:row}#__vconsole .vc-toolbar .vc-tool{display:none;text-decoration:none;color:#000;width:50%;flex:1;-webkit-box-flex:1;text-align:center;position:relative;-webkit-touch-callout:none}#__vconsole .vc-toolbar .vc-tool.vc-global-tool,#__vconsole .vc-toolbar .vc-tool.vc-toggle{display:block}#__vconsole .vc-toolbar .vc-tool:active{background-color:rgba(0,0,0,.15)}#__vconsole .vc-toolbar .vc-tool:after{content:" ";position:absolute;top:.53846154em;bottom:.53846154em;right:0;border-left:1px solid #d9d9d9}#__vconsole .vc-toolbar .vc-tool-last:after{border:none}#__vconsole.vc-toggle .vc-switch{display:none}#__vconsole.vc-toggle .vc-mask{background:rgba(0,0,0,.6);display:block}#__vconsole.vc-toggle .vc-panel{-webkit-transform:translate(0);transform:translate(0)}',""])},function(e,t){"use strict";e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t=0&&y.splice(t,1)}function l(e){var t=document.createElement("style");return t.type="text/css",a(e,t),t}function c(e){var t=document.createElement("link");return t.rel="stylesheet",a(e,t),t}function s(e,t){var o,n,i;if(t.singleton){var a=m++;o=b||(b=l(t)),n=d.bind(null,o,a,!1),i=d.bind(null,o,a,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(o=c(t),n=v.bind(null,o),i=function(){r(o),o.href&&URL.revokeObjectURL(o.href)}):(o=l(t),n=u.bind(null,o),i=function(){r(o)});return n(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;n(e=t)}else i()}}function d(e,t,o,n){var i=o?"":n.css;if(e.styleSheet)e.styleSheet.cssText=_(t,i);else{var a=document.createTextNode(i),r=e.childNodes;r[t]&&e.removeChild(r[t]),r.length?e.insertBefore(a,r[t]):e.appendChild(a)}}function u(e,t){var o=t.css,n=t.media;if(n&&e.setAttribute("media",n),e.styleSheet)e.styleSheet.cssText=o;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(o))}}function v(e,t){var o=t.css,n=t.sourceMap;n&&(o+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(n))))+" */");var i=new Blob([o],{type:"text/css" 11 | }),a=e.href;e.href=URL.createObjectURL(i),a&&URL.revokeObjectURL(a)}var f={},p=function(e){var t;return function(){return"undefined"==typeof t&&(t=e.apply(this,arguments)),t}},h=p(function(){return/msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase())}),g=p(function(){return document.head||document.getElementsByTagName("head")[0]}),b=null,m=0,y=[];e.exports=function(e,t){t=t||{},"undefined"==typeof t.singleton&&(t.singleton=h()),"undefined"==typeof t.insertAt&&(t.insertAt="bottom");var o=i(e);return n(o,t),function(e){for(var a=[],r=0;r\n
vConsole
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n Hide\n
\n
\n'},function(e,t){e.exports='{{name}}'},function(e,t){e.exports='
\n \n
'},function(e,t){e.exports='{{name}}'},function(e,t){e.exports='{{name}}'},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n)));return l.tplTabbox=b["default"],l.windowOnError=null,l}return l(t,e),c(t,[{key:"onReady",value:function(){var e=this;s(Object.getPrototypeOf(t.prototype),"onReady",this).call(this),u["default"].bind(u["default"].one(".vc-cmd",this.$tabbox),"submit",function(t){t.preventDefault();var o=u["default"].one(".vc-cmd-input",t.target),n=o.value;o.value="",""!==n&&e.evalCommand(n)});var o="";o+="if (!!window) {",o+="window.__vConsole_cmd_result = undefined;",o+="window.__vConsole_cmd_error = false;",o+="}";var n=document.getElementsByTagName("script"),i="";n.length>0&&(i=n[0].getAttribute("nonce")||"");var a=document.createElement("SCRIPT");a.innerHTML=o,a.setAttribute("nonce",i),document.documentElement.appendChild(a),document.documentElement.removeChild(a)}},{key:"mockConsole",value:function(){s(Object.getPrototypeOf(t.prototype),"mockConsole",this).call(this);var e=this;f.isFunction(window.onerror)&&(this.windowOnError=window.onerror),window.onerror=function(t,o,n,i,a){var r=t;o&&(r+="\n"+o.replace(location.origin,"")),(n||i)&&(r+=":"+n+":"+i);var l=!!a&&!!a.stack,c=l&&a.stack.toString()||"";e.printLog({logType:"error",logs:[r,c],noOrigin:!0}),f.isFunction(e.windowOnError)&&e.windowOnError.call(window,t,o,n,i,a)}}},{key:"evalCommand",value:function(e){this.printLog({logType:"log",content:u["default"].render(y["default"],{content:e,type:"input"}),noMeta:!0,style:""});var t="";t+="try {\n",t+="window.__vConsole_cmd_result = (function() {\n",t+="return "+e+";\n",t+="})();\n",t+="window.__vConsole_cmd_error = false;\n",t+="} catch (e) {\n",t+="window.__vConsole_cmd_result = e.message;\n",t+="window.__vConsole_cmd_error = true;\n",t+="}";var o=document.getElementsByTagName("script"),n="";o.length>0&&(n=o[0].getAttribute("nonce")||"");var i=document.createElement("SCRIPT");i.innerHTML=t,i.setAttribute("nonce",n),document.documentElement.appendChild(i);var a=window.__vConsole_cmd_result,r=window.__vConsole_cmd_error;if(document.documentElement.removeChild(i),0==r){var l=void 0;f.isArray(a)||f.isObject(a)?l=this.getFoldedLine(a):(f.isNull(a)?a="null":f.isUndefined(a)?a="undefined":f.isFunction(a)?a="function()":f.isString(a)&&(a='"'+a+'"'),l=u["default"].render(y["default"],{content:a,type:"output"})),this.printLog({logType:"log",content:l,noMeta:!0,style:""})}else this.printLog({logType:"error",logs:[a],noMeta:!0,style:""})}}]),t}(h["default"]);t["default"]=_,e.exports=t["default"]},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function i(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},s=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n)));return l.tplTabbox="",l.allowUnformattedLog=!0,l.isReady=!1,l.isShow=!1,l.$tabbox=null,l.console={},l.logList=[],l.isInBottom=!0,l.maxLogNumber=x,l.logNumber=0,l.mockConsole(),l}return l(t,e),s(t,[{key:"onInit",value:function(){this.$tabbox=f["default"].render(this.tplTabbox,{}),this.updateMaxLogNumber()}},{key:"onRenderTab",value:function(e){e(this.$tabbox)}},{key:"onAddTopBar",value:function(e){for(var t=this,o=["All","Log","Info","Warn","Error"],n=[],i=0;i=o.scrollHeight?e.isInBottom=!0:e.isInBottom=!1)});for(var n=0;nthis.maxLogNumber;){var e=f["default"].one(".vc-item",this.$tabbox);if(!e)break;e.parentNode.removeChild(e),this.logNumber--}}},{key:"showLogType",value:function(e){var t=f["default"].one(".vc-log",this.$tabbox);f["default"].removeClass(t,"vc-log-partly-log"),f["default"].removeClass(t,"vc-log-partly-info"),f["default"].removeClass(t,"vc-log-partly-warn"),f["default"].removeClass(t,"vc-log-partly-error"),"all"==e?f["default"].removeClass(t,"vc-log-partly"):(f["default"].addClass(t,"vc-log-partly"),f["default"].addClass(t,"vc-log-partly-"+e))}},{key:"autoScrollToBottom",value:function(){this.vConsole.option.disableLogScrolling||this.scrollToBottom()}},{key:"scrollToBottom",value:function(){var e=f["default"].one(".vc-content");e&&(e.scrollTop=e.scrollHeight-e.offsetHeight)}},{key:"mockConsole",value:function(){var e=this,t=this,o=["log","info","warn","debug","error"];window.console?(o.map(function(e){t.console[e]=window.console[e]}),t.console.time=window.console.time,t.console.timeEnd=window.console.timeEnd,t.console.clear=window.console.clear):window.console={},o.map(function(t){window.console[t]=function(){for(var o=arguments.length,n=Array(o),i=0;o>i;i++)n[i]=arguments[i];e.printLog({logType:t,logs:n})}});var n={};window.console.time=function(e){n[e]=Date.now()},window.console.timeEnd=function(e){var t=n[e];t?(console.log(e+":",Date.now()-t+"ms"),delete n[e]):console.log(e+": 0ms")},window.console.clear=function(){for(var e=arguments.length,o=Array(e),n=0;e>n;n++)o[n]=arguments[n];t.clearLog(),t.console.clear.apply(window.console,o)}}},{key:"clearLog",value:function(){f["default"].one(".vc-log",this.$tabbox).innerHTML=""}},{key:"printOriginLog",value:function(e){"function"==typeof this.console[e.logType]&&this.console[e.logType].apply(window.console,e.logs)}},{key:"printLog",value:function(e){var t=e.logs||[];if(t.length||e.content){t=[].slice.call(t||[]);var o=!0,n=/^\[(\w+)\]$/i,i="";if(u.isString(t[0])){var a=t[0].match(n);null!==a&&a.length>0&&(i=a[1].toLowerCase())}if(i?o=i==this.id:0==this.allowUnformattedLog&&(o=!1),!o)return void(e.noOrigin||this.printOriginLog(e));if(e.date||(e.date=+new Date),!this.isReady)return void this.logList.push(e);if(u.isString(t[0])&&(t[0]=t[0].replace(n,""),""===t[0]&&t.shift()),!e.meta){var r=u.getDate(e.date);e.meta=r.hour+":"+r.minute+":"+r.second}for(var l=f["default"].render(b["default"],{logType:e.logType,noMeta:!!e.noMeta,meta:e.meta,style:e.style||""}),s=f["default"].one(".vc-item-content",l),d=0;d "+t[d].toString()+"":u.isObject(t[d])||u.isArray(t[d])?this.getFoldedLine(t[d]):" "+u.htmlEncode(t[d]).replace(/\n/g,"
")+"
"}catch(p){v=" ["+c(t[d])+"]"}v&&("string"==typeof v?s.insertAdjacentHTML("beforeend",v):s.insertAdjacentElement("beforeend",v))}u.isObject(e.content)&&s.insertAdjacentElement("beforeend",e.content),f["default"].one(".vc-log",this.$tabbox).insertAdjacentElement("beforeend",l),this.logNumber++,this.limitMaxLogs(),this.isInBottom&&this.autoScrollToBottom(),e.noOrigin||this.printOriginLog(e)}}},{key:"getFoldedLine",value:function(e,t){var o=this;if(!t){var n=u.JSONStringify(e),i=n.substr(0,26);t=u.getObjName(e),n.length>26&&(i+="..."),t+=" "+i}var a=f["default"].render(y["default"],{outer:t,lineType:"obj"});return f["default"].bind(f["default"].one(".vc-fold-outer",a),"click",function(t){t.preventDefault(),t.stopPropagation(),f["default"].hasClass(a,"vc-toggle")?(f["default"].removeClass(a,"vc-toggle"),f["default"].removeClass(f["default"].one(".vc-fold-inner",a),"vc-toggle"),f["default"].removeClass(f["default"].one(".vc-fold-outer",a),"vc-toggle")):(f["default"].addClass(a,"vc-toggle"),f["default"].addClass(f["default"].one(".vc-fold-inner",a),"vc-toggle"),f["default"].addClass(f["default"].one(".vc-fold-outer",a),"vc-toggle"));var n=f["default"].one(".vc-fold-inner",a);if(0==n.children.length&&e){for(var i=u.getObjAllKeys(e),r=0;r\n {{if (!noMeta)}}{{meta}}{{/if}}\n
\n'},function(e,t){e.exports='
\n {{if (lineType == \'obj\')}}\n {{outer}}\n
\n {{else if (lineType == \'value\')}}\n {{value}}\n {{else if (lineType == \'kv\')}}\n {{key}}: {{value}}\n {{/if}}\n
'},function(e,t){e.exports='\n {{key}}: {{value}}\n'},function(e,t){e.exports='
\n
\n
\n \n
\n \n
\n
\n
'},function(e,t){e.exports='
{{content}}
'},function(e,t,o){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function i(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n)));return l.tplTabbox=p["default"],l.allowUnformattedLog=!1,l}return l(t,e),c(t,[{key:"onInit",value:function(){s(Object.getPrototypeOf(t.prototype),"onInit",this).call(this),this.printSystemInfo()}},{key:"printSystemInfo",value:function(){var e=navigator.userAgent,t="",o=e.match(/(ipod).*\s([\d_]+)/i),n=e.match(/(ipad).*\s([\d_]+)/i),i=e.match(/(iphone)\sos\s([\d_]+)/i),a=e.match(/(android)\s([\d\.]+)/i);t="Unknown",a?t="Android "+a[2]:i?t="iPhone, iOS "+i[2].replace(/_/g,"."):n?t="iPad, iOS "+n[2].replace(/_/g,"."):o&&(t="iPod, iOS "+o[2].replace(/_/g,"."));var r=t,l=e.match(/MicroMessenger\/([\d\.]+)/i);t="Unknown",l&&l[1]?(t=l[1],r+=", WeChat "+t,console.info("[system]","System:",r)):console.info("[system]","System:",r),t="Unknown",t="https:"==location.protocol?"HTTPS":"http:"==location.protocol?"HTTP":location.protocol.replace(":",""),r=t;var c=e.toLowerCase().match(/ nettype\/([^ ]+)/g);t="Unknown",c&&c[0]?(c=c[0].split("/"),t=c[1],r+=", "+t,console.info("[system]","Network:",r)):console.info("[system]","Protocol:",r),console.info("[system]","UA:",e),setTimeout(function(){var e=window.performance||window.msPerformance||window.webkitPerformance;if(e&&e.timing){var t=e.timing;t.navigationStart&&console.info("[system]","navigationStart:",t.navigationStart),t.navigationStart&&t.domainLookupStart&&console.info("[system]","navigation:",t.domainLookupStart-t.navigationStart+"ms"),t.domainLookupEnd&&t.domainLookupStart&&console.info("[system]","dns:",t.domainLookupEnd-t.domainLookupStart+"ms"),t.connectEnd&&t.connectStart&&(t.connectEnd&&t.secureConnectionStart?console.info("[system]","tcp (ssl):",t.connectEnd-t.connectStart+"ms ("+(t.connectEnd-t.secureConnectionStart)+"ms)"):console.info("[system]","tcp:",t.connectEnd-t.connectStart+"ms")),t.responseStart&&t.requestStart&&console.info("[system]","request:",t.responseStart-t.requestStart+"ms"),t.responseEnd&&t.responseStart&&console.info("[system]","response:",t.responseEnd-t.responseStart+"ms"),t.domComplete&&t.domLoading&&(t.domContentLoadedEventStart&&t.domLoading?console.info("[system]","domComplete (domLoaded):",t.domComplete-t.domLoading+"ms ("+(t.domContentLoadedEventStart-t.domLoading)+"ms)"):console.info("[system]","domComplete:",t.domComplete-t.domLoading+"ms")),t.loadEventEnd&&t.loadEventStart&&console.info("[system]","loadEvent:",t.loadEventEnd-t.loadEventStart+"ms"),t.navigationStart&&t.loadEventEnd&&console.info("[system]","total (DOM):",t.loadEventEnd-t.navigationStart+"ms ("+(t.domComplete-t.navigationStart)+"ms)")}},0)}}]),t}(v["default"]);t["default"]=h,e.exports=t["default"]},function(e,t){e.exports='
\n
\n
'},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n)));return l.$tabbox=d["default"].render(g["default"],{}),l.$header=null,l.reqList={},l.domList={},l.isReady=!1,l.isShow=!1,l.isInBottom=!0,l._open=void 0,l._send=void 0,l.mockAjax(),l}return l(t,e),c(t,[{key:"onRenderTab",value:function(e){e(this.$tabbox)}},{key:"onAddTool",value:function(e){var t=this,o=[{name:"Clear",global:!1,onClick:function(e){t.clearLog()}}];e(o)}},{key:"onReady",value:function(){var e=this;e.isReady=!0,this.renderHeader(),d["default"].delegate(d["default"].one(".vc-log",this.$tabbox),"click",".vc-group-preview",function(t){var o=this.dataset.reqid,n=this.parentNode;d["default"].hasClass(n,"vc-actived")?(d["default"].removeClass(n,"vc-actived"),e.updateRequest(o,{actived:!1})):(d["default"].addClass(n,"vc-actived"),e.updateRequest(o,{actived:!0})),t.preventDefault()});var t=d["default"].one(".vc-content");d["default"].bind(t,"scroll",function(o){e.isShow&&(t.scrollTop+t.offsetHeight>=t.scrollHeight?e.isInBottom=!0:e.isInBottom=!1)});for(var o in e.reqList)e.updateRequest(o,{})}},{key:"onRemove",value:function(){window.XMLHttpRequest&&(window.XMLHttpRequest.prototype.open=this._open,window.XMLHttpRequest.prototype.send=this._send,this._open=void 0,this._send=void 0)}},{key:"onShow",value:function(){this.isShow=!0,1==this.isInBottom&&this.scrollToBottom()}},{key:"onHide",value:function(){this.isShow=!1}},{key:"onShowConsole",value:function(){1==this.isInBottom&&this.scrollToBottom()}},{key:"scrollToBottom",value:function(){var e=d["default"].one(".vc-content");e.scrollTop=e.scrollHeight-e.offsetHeight}},{key:"clearLog",value:function(){this.reqList={};for(var e in this.domList)this.domList[e].remove(),this.domList[e]=void 0;this.domList={},this.renderHeader()}},{key:"renderHeader",value:function(){var e=Object.keys(this.reqList).length,t=d["default"].render(m["default"],{count:e}),o=d["default"].one(".vc-log",this.$tabbox);this.$header?this.$header.parentNode.replaceChild(t,this.$header):o.parentNode.insertBefore(t,o),this.$header=t}},{key:"updateRequest",value:function(e,t){var o=Object.keys(this.reqList).length,n=this.reqList[e]||{};for(var i in t)n[i]=t[i];if(this.reqList[e]=n,this.isReady){var a={id:e,url:n.url,status:n.status,method:n.method||"-",costTime:n.costTime>0?n.costTime+"ms":"-",header:n.header||null,getData:n.getData||null,postData:n.postData||null,response:null,actived:!!n.actived};switch(n.responseType){case"":case"text":if(v.isString(n.response))try{a.response=JSON.parse(n.response),a.response=JSON.stringify(a.response,null,1),a.response=v.htmlEncode(a.response)}catch(r){a.response=v.htmlEncode(n.response)}else"undefined"!=typeof n.response&&(a.response=Object.prototype.toString.call(n.response));break;case"json":"undefined"!=typeof n.response&&(a.response=JSON.stringify(n.response,null,1));break;case"blob":case"document":case"arraybuffer":default:"undefined"!=typeof n.response&&(a.response=Object.prototype.toString.call(n.response))}0==n.readyState||1==n.readyState?a.status="Pending":2==n.readyState||3==n.readyState?a.status="Loading":4==n.readyState||(a.status="Unknown");var l=d["default"].render(_["default"],a),c=this.domList[e];n.status>=400&&d["default"].addClass(d["default"].one(".vc-group-preview",l),"vc-table-row-error"),c?c.parentNode.replaceChild(l,c):d["default"].one(".vc-log",this.$tabbox).insertAdjacentElement("beforeend",l),this.domList[e]=l;var s=Object.keys(this.reqList).length;s!=o&&this.renderHeader(),this.isInBottom&&this.scrollToBottom()}}},{key:"mockAjax",value:function(){var e=window.XMLHttpRequest;if(e){var t=this,o=window.XMLHttpRequest.prototype.open,n=window.XMLHttpRequest.prototype.send;t._open=o,t._send=n,window.XMLHttpRequest.prototype.open=function(){var e=this,n=[].slice.call(arguments),i=n[0],a=n[1],r=t.getUniqueID(),l=null;e._requestID=r,e._method=i,e._url=a;var c=e.onreadystatechange||function(){},s=function(){var o=t.reqList[r]||{};if(o.readyState=e.readyState,o.status=0,e.readyState>1&&(o.status=e.status),o.responseType=e.responseType,0==e.readyState)o.startTime||(o.startTime=+new Date);else if(1==e.readyState)o.startTime||(o.startTime=+new Date);else if(2==e.readyState){o.header={};for(var n=e.getAllResponseHeaders()||"",i=n.split("\n"),a=0;a0){a.getData={},r=r.join("?"),r=r.split("&");var l=!0,c=!1,s=void 0;try{for(var d,u=r[Symbol.iterator]();!(l=(d=u.next()).done);l=!0){var f=d.value;f=f.split("="),a.getData[f[0]]=f[1]}}catch(p){c=!0,s=p}finally{try{!l&&u["return"]&&u["return"]()}finally{if(c)throw s}}}if("POST"==a.method)if(v.isString(i)){var h=i.split("&");a.postData={};var g=!0,b=!1,m=void 0;try{for(var y,_=h[Symbol.iterator]();!(g=(y=_.next()).done);g=!0){var w=y.value;w=w.split("="),a.postData[w[0]]=w[1]}}catch(p){b=!0,m=p}finally{try{!g&&_["return"]&&_["return"]()}finally{if(b)throw m}}}else v.isPlainObject(i)&&(a.postData=i);return e._noVConsole||t.updateRequest(e._requestID,a),n.apply(e,o)}}}},{key:"getUniqueID",value:function(){var e="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0,o="x"==e?t:3&t|8;return o.toString(16)});return e}}]),t}(p["default"]);t["default"]=w,e.exports=t["default"]},function(e,t){e.exports='
\n
\n
'},function(e,t){e.exports='
\n
Name {{if (count > 0)}}({{count}}){{/if}}
\n
Method
\n
Status
\n
Time
\n
'},function(e,t){e.exports='
\n
\n
{{url}}
\n
{{method}}
\n
{{status}}
\n
{{costTime}}
\n
\n
\n {{if (header !== null)}}\n
\n
\n
Headers
\n
\n {{for (var key in header)}}\n
\n
{{key}}
\n
{{header[key]}}
\n
\n {{/for}}\n
\n {{/if}}\n {{if (getData !== null)}}\n
\n
\n
Query String Parameters
\n
\n {{for (var key in getData)}}\n
\n
{{key}}
\n
{{getData[key]}}
\n
\n {{/for}}\n
\n {{/if}}\n {{if (postData !== null)}}\n
\n
\n
Form Data
\n
\n {{for (var key in postData)}}\n
\n
{{key}}
\n
{{postData[key]}}
\n
\n {{/for}}\n
\n {{/if}}\n
\n
\n
Response
\n
\n
\n
{{response || \'\'}}
\n
\n
\n
\n
'},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function"); 12 | }function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n))),c=l;c.isInited=!1,c.node={},c.$tabbox=b["default"].render(v["default"],{}),c.nodes=[],c.activedElem={};var s=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;return c.observer=new s(function(e){for(var t=0;t0&&this.onChildRemove(e),e.addedNodes.length>0&&this.onChildAdd(e);break;case"attributes":this.onAttributesChange(e);break;case"characterData":this.onCharacterDataChange(e)}}},{key:"onChildRemove",value:function(e){var t=e.target,o=t.__vconsole_node;if(o){for(var n=0;n0||(e.childNodes[i]?n.renderView(e.childNodes[i],r,"replace"):r.style.display="none"))}}}),o){case"replace":t.parentNode.replaceChild(i,t);break;case"insertBefore":t.parentNode.insertBefore(i,t);break;default:t.appendChild(i)}return i}},{key:"getNode",value:function(e){if(!this._isIgnoredElement(e)){var t=e.__vconsole_node||{};if(t.nodeType=e.nodeType,t.nodeName=e.nodeName,t.tagName=e.tagName||"",t.textContent="",t.nodeType!=e.TEXT_NODE&&t.nodeType!=e.DOCUMENT_TYPE_NODE||(t.textContent=e.textContent),t.id=e.id||"",t.className=e.className||"",t.attributes=[],e.hasAttributes&&e.hasAttributes())for(var o=0;o0)for(var n=0;n.vcelm-node{display:block}.vcelm-l .vcelm-node:active{background-color:rgba(0,0,0,.15)}.vcelm-l.vcelm-noc .vcelm-node:active{background-color:transparent}.vcelm-t{white-space:pre-wrap;word-wrap:break-word}.vcelm-l .vcelm-l{display:none}.vcelm-l.vc-toggle>.vcelm-l{margin-left:4px;display:block}.vcelm-l:before{content:"";display:block;position:absolute;top:6px;left:3px;width:0;height:0;border:3px solid transparent;border-left-color:#000}.vcelm-l.vc-toggle:before{display:block;top:6px;left:0;border-top-color:#000;border-left-color:transparent}.vcelm-l.vcelm-noc:before{display:none}',""])},function(e,t){e.exports='
\n
\n
'},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e){var t=["br","hr","img","input","link","meta"];return e=e?e.toLowerCase():"",t.indexOf(e)>-1}function l(e){return document.createTextNode(e)}function c(e){return e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var o=0;o<{{node.tagName.toLowerCase()}}{{if (node.className || node.attributes.length)}}\n \n {{for (var i = 0; i < node.attributes.length; i++)}}\n {{if (node.attributes[i].value !== \'\')}}\n {{node.attributes[i].name}}="{{node.attributes[i].value}}"{{else}}\n {{node.attributes[i].name}}{{/if}}{{/for}}{{/if}}>'},function(e,t){e.exports='</{{node.tagName.toLowerCase()}}>'},function(e,t,o){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t["default"]=e,t}function i(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function l(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var c=function(){function e(e,t){for(var o=0;oi;i++)n[i]=arguments[i];var l=r(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(n)));return l.$tabbox=m["default"].render(v["default"],{}),l.currentType="",l.typeNameMap={cookies:"Cookies",localstorage:"LocalStorage"},l}return l(t,e),c(t,[{key:"onRenderTab",value:function(e){e(this.$tabbox)}},{key:"onAddTopBar",value:function(e){for(var t=this,o=["Cookies","LocalStorage"],n=[],i=0;i\n
\n'},function(e,t){e.exports='
\n
\n
Name
\n
Value
\n
\n {{for (var i = 0; i < list.length; i++)}}\n
\n
{{list[i].name}}
\n
{{list[i].value}}
\n
\n {{/for}}\n
'}])}); -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | NSCameraUsageDescription 45 | 若不允许,您将无法使用相机拍照测试 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/JsApi/DemoJsApi.h: -------------------------------------------------------------------------------- 1 | // 2 | // DemoJsApi.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/19. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface DemoJsApi : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/JsApi/DemoJsApi.m: -------------------------------------------------------------------------------- 1 | // 2 | // DemoJsApi.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/19. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "DemoJsApi.h" 10 | #import "HCWKWebViewJsBridge.h" 11 | 12 | @implementation DemoJsApi 13 | 14 | - (void)test1:(NSString *)data callback:(HCJBResponseCallback)callback { 15 | NSLog(@"Js call native api test1, data is:%@", data); 16 | callback(@"native api test1’callback.(备注:汉字测试)"); 17 | } 18 | 19 | - (void)test2:(NSDictionary *)data { 20 | NSLog(@"Js native api:test2, data is:%@", data); 21 | } 22 | 23 | - (void)test3 { 24 | NSLog(@"Js native api:test3"); 25 | } 26 | 27 | - (void)test4:(HCJBResponseCallback)callback { 28 | NSLog(@"Js native api:test4"); 29 | callback(@"native api test4'callback.(备注:汉字测试)"); 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/JsApi/TestJsApi.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestJsApi.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/29. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol TestJsApiDelegate 15 | 16 | @optional 17 | - (NSString *)alertCancelResponseData; 18 | 19 | @end 20 | 21 | @interface TestJsApi : NSObject 22 | 23 | @property (nonatomic, weak) UIViewController *context; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/JsApi/TestJsApi.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestJsApi.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/29. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "TestJsApi.h" 10 | #import "HCWKWebViewJsBridge.h" 11 | 12 | @interface TestJsApi () 13 | 14 | @property (nonatomic, copy) HCJBResponseCallback selectPhotoCB; 15 | 16 | @end 17 | 18 | @implementation TestJsApi 19 | 20 | - (void)alert:(NSDictionary *)data callback:(HCJBResponseCallback)callback { 21 | NSString *title = data[@"title"]; 22 | NSString *description = data[@"desc"]; 23 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title 24 | message:description 25 | preferredStyle:UIAlertControllerStyleAlert]; 26 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel 27 | handler:^(UIAlertAction * _Nonnull action) { 28 | if (self.context && [self.context respondsToSelector:@selector(alertCancelResponseData)]) { 29 | callback([self.context alertCancelResponseData]); 30 | } else { 31 | callback(@"cancel action finished."); 32 | } 33 | }]; 34 | [alertController addAction:cancelAction]; 35 | [self.context presentViewController:alertController animated:YES completion:nil]; 36 | } 37 | 38 | - (void)selectPhoto:(HCJBResponseCallback)callback { 39 | UIImagePickerController * imagePicker = [[UIImagePickerController alloc] init]; 40 | imagePicker.editing = YES; 41 | imagePicker.delegate = self; 42 | imagePicker.allowsEditing = YES; 43 | 44 | UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Select Image" message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 45 | 46 | UIAlertAction * camera = [UIAlertAction actionWithTitle:@"Camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 47 | imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; 48 | imagePicker.modalPresentationStyle = UIModalPresentationFullScreen; 49 | imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; 50 | [self.context presentViewController:imagePicker animated:YES completion:nil]; 51 | }]; 52 | 53 | UIAlertAction * photo = [UIAlertAction actionWithTitle:@"Album" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 54 | imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 55 | [self.context presentViewController:imagePicker animated:YES completion:nil]; 56 | }]; 57 | 58 | UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 59 | }]; 60 | 61 | [alert addAction:camera]; 62 | [alert addAction:photo]; 63 | [alert addAction:cancel]; 64 | 65 | [self.context presentViewController:alert animated:YES completion:nil]; 66 | self.selectPhotoCB = callback; 67 | } 68 | 69 | - (void)getRequest:(NSDictionary *)data callback:(HCJBResponseCallback)callback { 70 | NSString *url = data[@"url"]; 71 | NSDictionary *params = data[@"params"]; 72 | NSMutableString *parameterString = [[NSMutableString alloc] initWithString:url]; 73 | if (params && params.allKeys.count > 0) { 74 | [parameterString appendString:@"?"]; 75 | int pos =0; 76 | for (NSString *key in params.allKeys) { 77 | [parameterString appendFormat:@"%@=%@", key, params[key]]; 78 | if(pos < params.allKeys.count - 1){ 79 | [parameterString appendString:@"&"]; 80 | } 81 | pos++; 82 | } 83 | } 84 | NSString * encodingString = [[parameterString copy] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; 85 | NSURL *_url = [NSURL URLWithString:encodingString]; 86 | NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:_url]; 87 | [urlRequest setTimeoutInterval:15.0]; 88 | [urlRequest setHTTPMethod:@"GET"]; 89 | 90 | NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 91 | NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:sessionConfiguration]; 92 | NSURLSessionDataTask *task = [urlSession dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 93 | if (error) { 94 | NSLog(@"error description: %@", [error description]); 95 | callback([error description]); 96 | } else { 97 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 98 | callback(responseString); 99 | } 100 | }]; 101 | [task resume]; 102 | } 103 | 104 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 105 | 106 | [picker dismissViewControllerAnimated:YES completion:nil]; 107 | UIImage * image = [info valueForKey:UIImagePickerControllerEditedImage]; 108 | NSData *imageData = UIImagePNGRepresentation(image); 109 | NSString *imageBase64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; 110 | NSDictionary *dict = @{@"image": imageBase64}; 111 | self.selectPhotoCB(dict); 112 | } 113 | 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import 11 | #import "HCWKWebViewJsBridge.h" 12 | #import "DemoJsApi.h" 13 | #import "TestJsApi.h" 14 | 15 | @interface ViewController () { 16 | HCWKWebViewJsBridge *_bridge; 17 | } 18 | @property (weak, nonatomic) IBOutlet WKWebView *wkWebView; 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"]; 26 | // Test does not introduce hcJsBridge.js in H5, you need to load testWithNoJsFile.html. 27 | // NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"testWithNoJsFile" ofType:@"html"]; 28 | NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; 29 | NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; 30 | [self.wkWebView loadHTMLString:appHtml baseURL:baseURL]; 31 | 32 | _bridge = [HCWKWebViewJsBridge bridgeWithWebView:self.wkWebView]; 33 | // Test does not introduce hcJsBridge.js in H5, you need to use 'bridgeWithWebView:injectJS:YES' method. 34 | // _bridge = [HCWKWebViewJsBridge bridgeWithWebView:self.wkWebView injectJS:YES]; 35 | [_bridge enableDebugLogging:YES]; 36 | DemoJsApi *defaultApi = [DemoJsApi new]; 37 | [_bridge addJsBridgeApiObject:defaultApi namespace:@"ui"]; 38 | TestJsApi *testApi = [TestJsApi new]; 39 | testApi.context = self; 40 | [_bridge addJsBridgeApiObject:testApi namespace:@"test"]; 41 | 42 | [_bridge callHandler:@"test1" data:@"test1 data" responseCallback:^(id _Nonnull responseData) { 43 | NSLog(@"test1 callback data is:%@", responseData); 44 | }]; 45 | // Do any additional setup after loading the view. 46 | } 47 | - (IBAction)test1:(id)sender { 48 | [_bridge callHandler:@"test1" data:@"test1 data" responseCallback:^(id _Nonnull responseData) { 49 | NSLog(@"test1 callback data is:%@", responseData); 50 | }]; 51 | } 52 | - (IBAction)test2:(id)sender { 53 | [_bridge callHandler:@"test2" data:@{@"hello":@"world"}]; 54 | } 55 | - (IBAction)test3:(id)sender { 56 | [_bridge callHandler:@"test3"]; 57 | } 58 | - (IBAction)test4:(id)sender { 59 | [_bridge callHandler:@"test1" responseCallback:^(id _Nullable responseData) { 60 | NSLog(@"test1 callback data is:%@", responseData); 61 | }]; 62 | } 63 | 64 | #pragma mark - TestJsApiDelegate 65 | - (NSString *)alertCancelResponseData { 66 | return @"Good blessings from HCWebViewJsBridge."; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS ExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS ExampleTests/iOS_ExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // iOS_ExampleTests.m 3 | // iOS ExampleTests 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iOS_ExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation iOS_ExampleTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS ExampleUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/iOS Example/iOS ExampleUITests/iOS_ExampleUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // iOS_ExampleUITests.m 3 | // iOS ExampleUITests 4 | // 5 | // Created by 刘海川 on 2019/9/27. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface iOS_ExampleUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation iOS_ExampleUITests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | 20 | // In UI tests it is usually best to stop immediately when a failure occurs. 21 | self.continueAfterFailure = NO; 22 | 23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 24 | [[[XCUIApplication alloc] init] launch]; 25 | 26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testExample { 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /HCWebViewJsBridge.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint HCWebViewJsBridge.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |spec| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | spec.name = "HCWebViewJsBridge" 19 | spec.version = "1.2.0" 20 | spec.summary = "HCWebViewJsBridge is used to implement communication between H5 and WKWebView/UIWebView. 21 | " 22 | 23 | # This description is used to generate tags and improve search results. 24 | # * Think: What does it do? Why did you write it? What is the focus? 25 | # * Try to keep it short, snappy and to the point. 26 | # * Write the description between the DESC delimiters below. 27 | # * Finally, don't worry about the indent, CocoaPods strips it! 28 | spec.description = <<-DESC 29 | HCWebViewJsBridge is used to implement communication between H5 and WKWebView/UIWebView. 30 | It's simple, easy to use, non-invasive for WebView. 31 | DESC 32 | 33 | spec.homepage = "https://github.com/al-liu/WebViewJsBridge-iOS" 34 | # spec.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 35 | 36 | 37 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 38 | # 39 | # Licensing your code is important. See https://choosealicense.com for more info. 40 | # CocoaPods will detect a license file if there is a named LICENSE* 41 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 42 | # 43 | 44 | spec.license = "MIT" 45 | # spec.license = { :type => "MIT", :file => "FILE_LICENSE" } 46 | 47 | 48 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 49 | # 50 | # Specify the authors of the library, with email addresses. Email addresses 51 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 52 | # accepts just a name if you'd rather not provide an email address. 53 | # 54 | # Specify a social_media_url where others can refer to, for example a twitter 55 | # profile URL. 56 | # 57 | 58 | spec.author = { "刘海川" => "lhc.indie@gmail.com" } 59 | # Or just: spec.author = "刘海川" 60 | # spec.authors = { "刘海川" => "lhc.indie@gmail.com" } 61 | # spec.social_media_url = "https://twitter.com/刘海川" 62 | 63 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 64 | # 65 | # If this Pod runs only on iOS or OS X, then specify the platform and 66 | # the deployment target. You can optionally include the target after the platform. 67 | # 68 | 69 | # spec.platform = :ios 70 | spec.platform = :ios, "7.0" 71 | 72 | # When using multiple platforms 73 | spec.ios.deployment_target = "7.0" 74 | # spec.osx.deployment_target = "10.7" 75 | # spec.watchos.deployment_target = "2.0" 76 | # spec.tvos.deployment_target = "9.0" 77 | 78 | 79 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 80 | # 81 | # Specify the location from where the source should be retrieved. 82 | # Supports git, hg, bzr, svn and HTTP. 83 | # 84 | 85 | spec.source = { :git => "https://github.com/al-liu/WebViewJsBridge-iOS.git", :tag => "#{spec.version}" } 86 | 87 | 88 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 89 | # 90 | # CocoaPods is smart about how it includes source code. For source files 91 | # giving a folder will include any swift, h, m, mm, c & cpp files. 92 | # For header files it will include any header in the folder. 93 | # Not including the public_header_files will make all headers public. 94 | # 95 | 96 | spec.source_files = "HCWebViewJsBridge/**/*.{h,m}" 97 | spec.exclude_files = "Example" 98 | 99 | # spec.public_header_files = "Classes/**/*.h" 100 | 101 | 102 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 103 | # 104 | # A list of resources included with the Pod. These are copied into the 105 | # target bundle with a build phase script. Anything else will be cleaned. 106 | # You can preserve files from being cleaned, please don't preserve 107 | # non-essential files like tests, examples and documentation. 108 | # 109 | 110 | # spec.resource = "icon.png" 111 | # spec.resources = "Resources/*.png" 112 | 113 | # spec.preserve_paths = "FilesToSave", "MoreFilesToSave" 114 | 115 | 116 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 117 | # 118 | # Link your library with frameworks, or libraries. Libraries do not include 119 | # the lib prefix of their name. 120 | # 121 | 122 | # spec.framework = "SomeFramework" 123 | spec.frameworks = "Foundation", "UIKit", "WebKit" 124 | 125 | # spec.library = "iconv" 126 | # spec.libraries = "iconv", "xml2" 127 | 128 | 129 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 130 | # 131 | # If your library depends on compiler flags you can set them in the xcconfig hash 132 | # where they will only apply to your library. If you depend on other Podspecs 133 | # you can include multiple dependencies to ensure it works. 134 | 135 | # spec.requires_arc = true 136 | 137 | # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 138 | # spec.dependency "JSONKit", "~> 1.4" 139 | 140 | end 141 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCCoreJSExport.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCCoreJSExport.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/17. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol HCCoreJSExport 15 | 16 | JSExportAs(handleMessage, 17 | - (void)handleMessage:(NSString *)message 18 | ); 19 | 20 | JSExportAs(handleResponseMessage, 21 | - (void)handleResponseMessage:(NSString *)message 22 | ); 23 | 24 | JSExportAs(handleStartupMessage, 25 | - (void)handleStartupMessage:(NSString *)message 26 | ); 27 | 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCCoreJSExportImpl.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCCoreJSExportImpl.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/17. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HCCoreJSExport.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @protocol HCCoreJSExportDelegate 15 | 16 | - (void)handleMessage:(NSString *)message webThread:(nonnull NSThread *)webThread; 17 | 18 | - (void)handleResponseMessage:(NSString *)message webThread:(nonnull NSThread *)webThread; 19 | 20 | - (void)handleStartupMessageWithWebThread:(nonnull NSThread *)webThread; 21 | 22 | @end 23 | 24 | @interface HCCoreJSExportImpl : NSObject 25 | 26 | @property (nonatomic, weak) id delegate; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCCoreJSExportImpl.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCCoreJSExportImpl.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/17. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "HCCoreJSExportImpl.h" 10 | 11 | @implementation HCCoreJSExportImpl 12 | 13 | - (void)handleMessage:(NSString *)message { 14 | if (_delegate && [_delegate respondsToSelector:@selector(handleMessage:webThread:)]) { 15 | [_delegate handleMessage:message webThread:[NSThread currentThread]]; 16 | } 17 | } 18 | 19 | - (void)handleResponseMessage:(NSString *)message { 20 | if (_delegate && [_delegate respondsToSelector:@selector(handleResponseMessage:webThread:)]) { 21 | [_delegate handleResponseMessage:message webThread:[NSThread currentThread]]; 22 | } 23 | } 24 | 25 | - (void)handleStartupMessage:(NSString *)message { 26 | if (_delegate && [_delegate respondsToSelector:@selector(handleStartupMessageWithWebThread:)]) { 27 | [_delegate handleStartupMessageWithWebThread:[NSThread currentThread]]; 28 | } 29 | } 30 | 31 | @end 32 | 33 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCJsApiMethod.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCJsApiMethod.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/20. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HCJsApiMethod : NSObject 14 | 15 | @property (nonatomic, copy) NSString *name; 16 | @property (nonatomic, assign) SEL selector; 17 | @property (nonatomic, assign) NSUInteger numberOfParameter; 18 | 19 | - (instancetype)initWithName:(NSString *)name 20 | sel:(SEL)selector 21 | numberOfParameter:(NSUInteger)numberOfParameter; 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCJsApiMethod.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCJsApiMethod.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/20. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "HCJsApiMethod.h" 10 | 11 | @implementation HCJsApiMethod 12 | 13 | - (instancetype)initWithName:(NSString *)name 14 | sel:(SEL)selector 15 | numberOfParameter:(NSUInteger)numberOfParameter { 16 | self = [super init]; 17 | if (self) { 18 | _name = name; 19 | _selector = selector; 20 | _numberOfParameter = numberOfParameter; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCJsApiName.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCJsApiName.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/20. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface HCJsApiName : NSObject 14 | 15 | @property (nonatomic, copy) NSString *name; 16 | @property (nonatomic, copy) NSString *spacename; 17 | 18 | - (instancetype)initWithName:(NSString *)name 19 | spacename:(NSString *)spacename; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCJsApiName.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCJsApiName.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/20. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "HCJsApiName.h" 10 | 11 | @implementation HCJsApiName 12 | 13 | - (instancetype)initWithName:(NSString *)name 14 | spacename:(NSString *)spacename { 15 | self = [super init]; 16 | if (self) { 17 | _name = name; 18 | _spacename = spacename; 19 | } 20 | return self; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWKWebViewJsBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCWKJsBridge.h 3 | // Demo 4 | // 5 | // Created by lhc on 2019/9/20. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "HCWebViewJsBridgeUtil.h" 12 | 13 | /** 14 | HCWKWebViewJsBridge is used to implement communication between H5 and WKWebView. 15 | Please refer to the README.md for detailed usage. 16 | 17 | js code example, hcJsBridge is a global object: 18 | 1. H5 register an api for native calls 19 | hcJsBridge.registerHandler("test", function(data, callback) { 20 | callback(responseData); 21 | }) 22 | 23 | 2. H5 call a native api, api name is 'ui.alert' 24 | hcJsBridge.callHandler("ui.alert", data, function (responseData) { 25 | 26 | }) 27 | */ 28 | @interface HCWKWebViewJsBridge : NSObject 29 | /** 30 | Static constructor 31 | 32 | @param webView specified a WKWebView object 33 | @return HCWKWebViewJsBridge 34 | */ 35 | + (instancetype _Nonnull)bridgeWithWebView:(WKWebView * _Nonnull)webView; 36 | 37 | /// If hcJsBridge.js is not introduced in H5, you need to call the static constructor and enable is YES. 38 | /// 39 | /// @param webView specified a WKWebView object 40 | /// @param enable Default NO, If YES, the native will inject js into H5 and initialize hcjsbridge object. 41 | + (instancetype _Nonnull)bridgeWithWebView:(WKWebView * _Nonnull)webView injectJS:(BOOL)enable; 42 | 43 | /** 44 | Add an class object to HCWKWebViewJsBridge with default namespace. 45 | This class object is used to implement the handler method of H5 calling native. 46 | 47 | @param apiObject implementation object of the H5 call native. 48 | */ 49 | - (void)addJsBridgeApiObject:(id _Nonnull)apiObject; 50 | 51 | /** 52 | Add an class object to HCWKWebViewJsBridge with specified namespace. 53 | 54 | @param apiObject implementation object of the H5 call native. 55 | @param name namespace 56 | */ 57 | - (void)addJsBridgeApiObject:(id _Nonnull)apiObject namespace:(NSString * _Nullable)name; 58 | 59 | /** 60 | Native call H5's already registered handler 61 | 62 | @param handlerName specified handler name 63 | @param data send data 64 | @param responseCallback callback block 65 | */ 66 | - (void)callHandler:(NSString * _Nonnull)handlerName 67 | data:(id _Nullable)data 68 | responseCallback:(HCJBResponseCallback _Nullable)responseCallback; 69 | 70 | /** 71 | Native call H5's already registered handler 72 | 73 | @param handlerName specified handler name 74 | */ 75 | - (void)callHandler:(NSString * _Nonnull)handlerName; 76 | 77 | /** 78 | Native call H5's already registered handler 79 | 80 | @param handlerName specified handler name 81 | @param data send data 82 | */ 83 | - (void)callHandler:(NSString * _Nonnull)handlerName 84 | data:(id _Nullable )data; 85 | 86 | /** 87 | Native call H5's already registered handler 88 | 89 | @param handlerName specified handler name 90 | @param responseCallback callback block 91 | */ 92 | - (void)callHandler:(NSString * _Nonnull)handlerName 93 | responseCallback:(HCJBResponseCallback _Nullable)responseCallback; 94 | 95 | /** 96 | Whether to enable the debug log mode. 97 | If it is YES, it will print some call process logs, but only print in DEBUG mode. 98 | 99 | @param debug Debug log switch 100 | */ 101 | - (void)enableDebugLogging:(BOOL)debug; 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWKWebViewJsBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCWKJsBridge.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/20. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "HCWKWebViewJsBridge.h" 10 | #import "HCWebViewJavaScript.h" 11 | 12 | static NSString * const kWKHandleMessageFunction = @"handleMessage"; 13 | static NSString * const kWKHandleResponseMessageFunction = @"handleResponseMessage"; 14 | static NSString * const kWKHandleStartupMessageFunction = @"handleStartupMessage"; 15 | static NSString * const kWKMessageName = @"name"; 16 | static NSString * const kWKMessageData = @"data"; 17 | static NSString * const kWKMessageCallback = @"callbackId"; 18 | static NSString * const kWKMessageResponseId = @"responseId"; 19 | static NSString * const kWKMessageResponseData = @"responseData"; 20 | static NSString * const kWKResponseCallbackJsScript = @"hcJsBridge.handleMessageFromNative('%@');"; 21 | 22 | static NSString * const kJsBridgeApiSpacenameDefault = @"default"; 23 | 24 | @interface HCWKWebViewJsBridge () { 25 | __weak WKWebView* _webView; 26 | 27 | NSMutableDictionary *_apiDictionary; 28 | NSMutableDictionary *> *_cacheApiMethodDictionary; 29 | NSMutableDictionary *_responseCallbackDictionary; 30 | NSMutableArray *_startupMessageQueue; 31 | BOOL _isDebug; 32 | BOOL _enableAutoInjectJs; 33 | } 34 | 35 | @end 36 | 37 | @implementation HCWKWebViewJsBridge 38 | 39 | #pragma mark - 构造器 40 | + (instancetype _Nonnull)bridgeWithWebView:(WKWebView * _Nonnull)webView { 41 | return [HCWKWebViewJsBridge bridgeWithWebView:webView injectJS:NO]; 42 | } 43 | 44 | + (instancetype _Nonnull)bridgeWithWebView:(WKWebView * _Nonnull)webView injectJS:(BOOL)enable { 45 | HCWKWebViewJsBridge *bridge = [[self alloc] init]; 46 | [bridge hc_initSetup:webView injectJs:enable]; 47 | return bridge; 48 | } 49 | 50 | - (instancetype)init 51 | { 52 | self = [super init]; 53 | if (self) { 54 | _responseCallbackDictionary = [[NSMutableDictionary alloc] init]; 55 | _startupMessageQueue = [[NSMutableArray alloc] init]; 56 | 57 | _apiDictionary = [[NSMutableDictionary alloc] init]; 58 | _cacheApiMethodDictionary = [[NSMutableDictionary alloc] init]; 59 | } 60 | return self; 61 | } 62 | 63 | - (void)dealloc { 64 | WKUserContentController *userContentController = [[_webView configuration] userContentController]; 65 | [userContentController removeScriptMessageHandlerForName:kWKHandleMessageFunction]; 66 | [userContentController removeScriptMessageHandlerForName:kWKHandleResponseMessageFunction]; 67 | [userContentController removeScriptMessageHandlerForName:kWKHandleStartupMessageFunction]; 68 | } 69 | 70 | #pragma mark - Private Method 71 | - (void)hc_initSetup:(WKWebView *)webView injectJs:(BOOL)enable { 72 | _webView = webView; 73 | _enableAutoInjectJs = enable; 74 | WKUserContentController *userContentController = [[_webView configuration] userContentController]; 75 | [userContentController addScriptMessageHandler:self name:kWKHandleMessageFunction]; 76 | [userContentController addScriptMessageHandler:self name:kWKHandleResponseMessageFunction]; 77 | [userContentController addScriptMessageHandler:self name:kWKHandleStartupMessageFunction]; 78 | if (_enableAutoInjectJs) { 79 | WKUserScript *script = [[WKUserScript alloc] initWithSource:hcJsBridgeJavaScript() 80 | injectionTime:WKUserScriptInjectionTimeAtDocumentEnd 81 | forMainFrameOnly:YES]; 82 | [userContentController addUserScript:script]; 83 | } 84 | } 85 | 86 | #pragma mark - Public Api 87 | - (void)addJsBridgeApiObject:(id _Nonnull)apiObject { 88 | [self addJsBridgeApiObject:apiObject namespace:nil]; 89 | } 90 | 91 | - (void)addJsBridgeApiObject:(id _Nonnull)apiObject namespace:(NSString * _Nullable)name { 92 | if ([HCWebViewJsBridgeUtil isNull:apiObject]) { 93 | HCJBLog(@"Method(AddJsBridgeApiObject) call failed, api object cannot be null"); 94 | return; 95 | } 96 | NSString *namespace = name; 97 | if ([HCWebViewJsBridgeUtil isNull:namespace] || [@"" isEqualToString:namespace]) { 98 | namespace = kJsBridgeApiSpacenameDefault; 99 | } 100 | [_apiDictionary setObject:apiObject forKey:namespace]; 101 | if (_isDebug) { 102 | HCJBDebugLog(@"Already added the api object(%@.m) to HCWKWebViewJsBridge, namespace is %@", NSStringFromClass([apiObject class]), namespace); 103 | } 104 | } 105 | 106 | - (void)callHandler:(NSString * _Nonnull)handlerName { 107 | [self callHandler:handlerName data:nil responseCallback:nil]; 108 | } 109 | 110 | - (void)callHandler:(NSString * _Nonnull)handlerName 111 | data:(id _Nullable )data { 112 | [self callHandler:handlerName data:data responseCallback:nil]; 113 | } 114 | 115 | - (void)callHandler:(NSString * _Nonnull)handlerName 116 | responseCallback:(HCJBResponseCallback _Nullable)responseCallback { 117 | [self callHandler:handlerName data:nil responseCallback:responseCallback]; 118 | } 119 | 120 | - (void)callHandler:(NSString * _Nonnull)handlerName 121 | data:(id _Nullable)data 122 | responseCallback:(HCJBResponseCallback _Nullable)responseCallback { 123 | if ([HCWebViewJsBridgeUtil isNull:handlerName]) { 124 | HCJBLog(@"Method(AcallHandler:data:responseCallback) call failed, handlerName cannot be null"); 125 | return; 126 | } 127 | NSMutableDictionary *message = [[NSMutableDictionary alloc] init]; 128 | message[kWKMessageName] = handlerName; 129 | if ([HCWebViewJsBridgeUtil nonNull:data]) { 130 | message[kWKMessageData] = data; 131 | } 132 | if ([HCWebViewJsBridgeUtil nonNull:responseCallback]) { 133 | NSString *callbackId = [HCWebViewJsBridgeUtil generateCallbackId]; 134 | message[kWKMessageCallback] = callbackId; 135 | _responseCallbackDictionary[callbackId] = [responseCallback copy]; 136 | } 137 | if (_startupMessageQueue) { 138 | [_startupMessageQueue addObject:message]; 139 | } else { 140 | [self sendMessage:message]; 141 | } 142 | if (_isDebug) { 143 | HCJBDebugLog(@"Native calling api of js(%@), data is %@, responseCallback is %@", handlerName, data, responseCallback); 144 | } 145 | } 146 | 147 | - (void)enableDebugLogging:(BOOL)debug { 148 | _isDebug = debug; 149 | } 150 | 151 | #pragma mark - delegate WKScriptMessageHandler 152 | - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { 153 | 154 | NSString *scriptMessageName = message.name; 155 | if ([kWKHandleMessageFunction isEqualToString:scriptMessageName]) { 156 | NSString *messageJson = message.body; 157 | NSError *jsonError; 158 | NSData *msgData = [messageJson dataUsingEncoding:NSUTF8StringEncoding]; 159 | NSDictionary *message = [NSJSONSerialization JSONObjectWithData:msgData options:0 error:&jsonError]; 160 | if (jsonError) { 161 | HCJBLog(@"Method(handleMessage) call failed, json(messageJson) parsing error:%@", [jsonError description]); 162 | return; 163 | } 164 | if ([HCWebViewJsBridgeUtil isNull:message]) { 165 | HCJBLog(@"Method(handleMessage) call failed, message body cannot be null"); 166 | return; 167 | } 168 | if (![message isKindOfClass:[NSDictionary class]]) { 169 | HCJBLog(@"Method(handleMessage) call failed, message body should be NSDictionary"); 170 | return; 171 | } 172 | NSString *messageName = message[kWKMessageName]; 173 | if ([HCWebViewJsBridgeUtil isNull:messageName]) { 174 | HCJBLog(@"Method(handleMessage) call failed, message name cannot be null"); 175 | return; 176 | } 177 | id messageData = message[kWKMessageData]; 178 | if ([HCWebViewJsBridgeUtil isNull:messageData]) { 179 | messageData = nil; 180 | } 181 | if (_isDebug) { 182 | HCJBDebugLog(@"Js calling api of native(%@), data is %@", messageName, messageData); 183 | } 184 | NSString *responseId = message[kWKMessageCallback]; 185 | HCJBResponseCallback responseCallback; 186 | if ([HCWebViewJsBridgeUtil nonNull:responseId]) { 187 | responseCallback = ^(id responseData) { 188 | if (responseData == nil) { 189 | responseData = [NSNull null]; 190 | } 191 | [self sendMessage:@{kWKMessageResponseData: responseData, kWKMessageResponseId: responseId}]; 192 | }; 193 | } 194 | 195 | HCJsApiName *apiName = [HCWebViewJsBridgeUtil resolveMessageName:messageName]; 196 | if (apiName) { 197 | HCJsBridgeHandleApiResultType result = [HCWebViewJsBridgeUtil handleApiWithName:apiName 198 | data:messageData 199 | callback:responseCallback 200 | apiDict:_apiDictionary 201 | cacheDict:_cacheApiMethodDictionary]; 202 | if (result == HCJsBridgeHandleApiResultTypeNotFoundTarget) { 203 | HCJBLog(@"Api Method call failed, because api object not found, please check the message name(%@).", messageName); 204 | } else if (result == HCJsBridgeHandleApiResultTypeNotFoundMethod) { 205 | HCJBLog(@"Api Method call failed, because method not found, please check the message name(%@).", messageName); 206 | } else if (result == HCJsBridgeHandleApiResultTypeSuccess){ 207 | if (_isDebug) { 208 | HCJBDebugLog(@"Js call api of native(%@) succeeded", messageName); 209 | } 210 | } 211 | } else { 212 | HCJBLog(@"Error parsing namespace, please check the message name(%@).", messageName); 213 | } 214 | } else if ([kWKHandleStartupMessageFunction isEqualToString:scriptMessageName]) { 215 | if (_startupMessageQueue) { 216 | [_startupMessageQueue enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 217 | [self sendMessage:obj]; 218 | }]; 219 | if (_isDebug) { 220 | HCJBDebugLog(@"Already called all handler of startup"); 221 | } 222 | _startupMessageQueue = nil; 223 | } 224 | } else if ([kWKHandleResponseMessageFunction isEqualToString:scriptMessageName]) { 225 | NSString *messageJson = message.body; 226 | NSError *jsonError; 227 | NSData *msgData = [messageJson dataUsingEncoding:NSUTF8StringEncoding]; 228 | NSDictionary *message = [NSJSONSerialization JSONObjectWithData:msgData options:0 error:&jsonError]; 229 | if (jsonError) { 230 | HCJBLog(@"Method(handleResponseMessage) call failed, json(messageJson) parsing error:%@", [jsonError description]); 231 | return; 232 | } 233 | NSDictionary *scriptMessageBody = message; 234 | NSString *responseId = scriptMessageBody[kWKMessageResponseId]; 235 | if ([HCWebViewJsBridgeUtil isNull:responseId]) { 236 | HCJBLog(@"Method(handleResponseMessage) call failed, responseId cannot be null, Note:Native may not require a callback"); 237 | return; 238 | } 239 | id messageData = scriptMessageBody[kWKMessageResponseData]; 240 | HCJBResponseCallback callback = _responseCallbackDictionary[responseId]; 241 | if ([HCWebViewJsBridgeUtil isNull:messageData]) { 242 | messageData = nil; 243 | } 244 | callback(messageData); 245 | } 246 | 247 | } 248 | 249 | - (void)sendMessage:(NSDictionary *)message { 250 | NSError *error; 251 | NSString *messageJson = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:0 error:&error] encoding:NSUTF8StringEncoding]; 252 | if (error) { 253 | HCJBLog(@"Method(sendMessage) call failed, an error occurred when the object(message) was converted to json:%@", [error description]); 254 | return; 255 | } 256 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; 257 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; 258 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; 259 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; 260 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; 261 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; 262 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; 263 | messageJson = [messageJson stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; 264 | NSString* javascriptCommand = [NSString stringWithFormat:kWKResponseCallbackJsScript, messageJson]; 265 | dispatch_async(dispatch_get_main_queue(), ^{ 266 | [self->_webView evaluateJavaScript:javascriptCommand completionHandler:^(id _Nullable result, NSError * _Nullable error) { 267 | if (error) { 268 | HCJBLog(@"Method(sendMessage) call failed, evaluateJavaScript error:%@", [error description]); 269 | } 270 | }]; 271 | }); 272 | } 273 | 274 | @end 275 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWebViewJavaScript.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCWebViewJavaScript.h 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/10/21. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NSString * hcJsBridgeJavaScript(void); 12 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWebViewJavaScript.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCWebViewJavaScript.m 3 | // iOS Example 4 | // 5 | // Created by 刘海川 on 2019/10/21. 6 | // Copyright © 2019 lhc. All rights reserved. 7 | // 8 | 9 | #import "HCWebViewJavaScript.h" 10 | 11 | NSString * hcJsBridgeJavaScript() { 12 | #define __wvjb_js_func__(x) #x 13 | 14 | // BEGIN preprocessorJSCode 15 | static NSString * preprocessorJSCode = @__wvjb_js_func__( 16 | ;(function() { 17 | 18 | if (window.hcJsBridge) { 19 | return; 20 | } 21 | 22 | window.hcJsBridge = { 23 | callHandler: callHandler, 24 | registerHandler: registerHandler, 25 | handleMessageFromNative: handleMessageFromNative, 26 | messageHandlers: {}, 27 | messageCallbacks: {} 28 | }; 29 | var uniqueId = 1; 30 | 31 | function callHandler(name, data, responseCallback) { 32 | if (arguments.length == 2 && typeof data == 'function') { 33 | responseCallback = data; 34 | data = null; 35 | } 36 | var message = {name:name, data:data}; 37 | if (responseCallback) { 38 | var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime(); 39 | message["callbackId"] = callbackId; 40 | hcJsBridge.messageCallbacks[callbackId] = responseCallback; 41 | } 42 | var messageJson = JSON.stringify(message); 43 | if (typeof nativeBridgeHead === "undefined") { 44 | window.webkit.messageHandlers.handleMessage.postMessage(messageJson); 45 | } else { 46 | nativeBridgeHead.handleMessage(messageJson); 47 | } 48 | } 49 | 50 | function registerHandler(name, handler) { 51 | hcJsBridge.messageHandlers[name] = handler; 52 | } 53 | 54 | function handleMessageFromNative(messageJSON) { 55 | 56 | var message = messageJSON; 57 | if (typeof message != "object") { 58 | message = JSON.parse(unescape(messageJSON)); 59 | } 60 | var responseId = message["responseId"]; 61 | if (responseId) { 62 | var responseData = message["responseData"]; 63 | var callback = hcJsBridge.messageCallbacks[responseId]; 64 | callback(responseData); 65 | } else { 66 | var messageName = message["name"]; 67 | var messageData = message["data"]; 68 | var messageCallbackId = message["callbackId"]; 69 | 70 | var handler = hcJsBridge.messageHandlers[messageName]; 71 | var responseCallback = function(data) { 72 | var responseMessage = { 73 | responseId: messageCallbackId, 74 | responseData: data 75 | }; 76 | var responseMessageJson = JSON.stringify(responseMessage); 77 | if (typeof nativeBridgeHead === "undefined") { 78 | window.webkit.messageHandlers.handleResponseMessage.postMessage(responseMessageJson); 79 | } else { 80 | nativeBridgeHead.handleResponseMessage(responseMessageJson); 81 | } 82 | }; 83 | handler(messageData, responseCallback); 84 | } 85 | } 86 | 87 | setTimeout(function () { 88 | if (typeof window._hcJsBridgeInitFinished === "function") { 89 | window._hcJsBridgeInitFinished(window.hcJsBridge); 90 | } 91 | if (typeof nativeBridgeHead === "undefined") { 92 | window.webkit.messageHandlers.handleStartupMessage.postMessage(""); 93 | } else { 94 | nativeBridgeHead.handleStartupMessage(); 95 | } 96 | }, 0); 97 | })(); 98 | ); // END preprocessorJSCode 99 | 100 | #undef __wvjb_js_func__ 101 | return preprocessorJSCode; 102 | }; 103 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWebViewJsBridgeUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // HCWebViewJsBridgeUtil.h 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/21. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HCJsApiName.h" 11 | #import "HCJsApiMethod.h" 12 | 13 | 14 | #ifdef DEBUG 15 | #define HCJBDebugLog(fmt, ...) NSLog((@"debug %s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 16 | #else 17 | #define HCJBDebugLog(...) 18 | #endif 19 | #define HCJBLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) 20 | 21 | typedef void (^HCJBResponseCallback)(id _Nullable responseData); 22 | typedef void (^HCJBHandler)(id _Nullable data, HCJBResponseCallback _Nullable responseCallback); 23 | 24 | NS_ASSUME_NONNULL_BEGIN 25 | typedef NS_ENUM(NSUInteger, HCJsBridgeHandleApiResultType) { 26 | HCJsBridgeHandleApiResultTypeSuccess = 0, 27 | HCJsBridgeHandleApiResultTypeNotFoundTarget, 28 | HCJsBridgeHandleApiResultTypeNotFoundMethod, 29 | HCJsBridgeHandleApiResultTypeErrorArgument 30 | }; 31 | 32 | typedef NS_ENUM(NSUInteger, HCJsBridgeMessageType) { 33 | HCJsBridgeMessageTypeDataAndCallback = 0, 34 | HCJsBridgeMessageTypeOnlyData, 35 | HCJsBridgeMessageTypeOnlyCallback, 36 | HCJsBridgeMessageTypeNoArgument 37 | }; 38 | 39 | @interface HCWebViewJsBridgeUtil : NSObject 40 | 41 | + (BOOL)nonNull:(id)value; 42 | + (BOOL)isNull:(id)value; 43 | 44 | + (HCJsApiName *)resolveMessageName:(NSString *)name; 45 | + (HCJsBridgeHandleApiResultType)handleApiWithName:(HCJsApiName *)apiName 46 | data:(id)data 47 | callback:(HCJBResponseCallback)responseCallback 48 | apiDict:(NSDictionary *)apiDict 49 | cacheDict:(NSMutableDictionary *)cacheDict; 50 | 51 | + (NSString *)generateCallbackId; 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /HCWebViewJsBridge/HCWebViewJsBridgeUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // HCWebViewJsBridgeUtil.m 3 | // Demo 4 | // 5 | // Created by 刘海川 on 2019/9/21. 6 | // Copyright © 2019 刘海川. All rights reserved. 7 | // 8 | 9 | #import "HCWebViewJsBridgeUtil.h" 10 | #import 11 | #import 12 | 13 | static NSString * const kJsBridgeApiSpacenameDefault = @"default"; 14 | static NSString * const kJsBridgeApiSpacenameSeparateSymbol = @"."; 15 | static NSString * const kJsBridgeApiSelArgCountSeparateSymbol = @":"; 16 | 17 | static NSString * const kJsBridgeNativeCallbackFormat = @"native_callback_%@"; 18 | 19 | @implementation HCWebViewJsBridgeUtil 20 | 21 | #pragma mark - null judge 22 | + (BOOL)nonNull:(id)value { 23 | return value != nil 24 | && ![value isEqual:[NSNull null]] 25 | && ![@"undefined" isEqualToString:value]; 26 | } 27 | 28 | + (BOOL)isNull:(id)value { 29 | return value == nil 30 | || [value isEqual:[NSNull null]] 31 | || [@"undefined" isEqualToString:value]; 32 | } 33 | 34 | + (HCJsApiName *)resolveMessageName:(NSString *)name { 35 | NSArray *spacenameComponents = [name componentsSeparatedByString:kJsBridgeApiSpacenameSeparateSymbol]; 36 | NSString *spacename, *messageName; 37 | if (spacenameComponents.count == 1) { 38 | spacename = kJsBridgeApiSpacenameDefault; 39 | messageName = name; 40 | } else if (spacenameComponents.count == 2) { 41 | spacename = spacenameComponents[0]; 42 | messageName = spacenameComponents[1]; 43 | } else { 44 | return nil; 45 | } 46 | return [[HCJsApiName alloc] initWithName:messageName spacename:spacename]; 47 | } 48 | 49 | + (HCJsBridgeHandleApiResultType)handleApiWithName:(HCJsApiName *)apiName 50 | data:(id)data 51 | callback:(HCJBResponseCallback)responseCallback 52 | apiDict:(NSDictionary *)apiDict 53 | cacheDict:(NSMutableDictionary *)cacheDict { 54 | id target = apiDict[apiName.spacename]; 55 | if (!target) { 56 | return HCJsBridgeHandleApiResultTypeNotFoundTarget; 57 | } 58 | NSArray *cacheMethods = cacheDict[apiName.spacename]; 59 | if (cacheMethods) { 60 | // PASS 61 | } else { 62 | NSMutableArray *methodNameArray = [[NSMutableArray alloc] init]; 63 | unsigned int methodCount = 0; 64 | Method *methods = class_copyMethodList([target class], &methodCount); 65 | for(int i = 0; i < methodCount; i++) { 66 | Method method = methods[i]; 67 | SEL sel = method_getName(method); 68 | NSString *methodName = [NSString stringWithCString:sel_getName(sel) 69 | encoding:NSUTF8StringEncoding]; 70 | NSArray *components = [methodName componentsSeparatedByString:kJsBridgeApiSelArgCountSeparateSymbol]; 71 | NSUInteger numberOfParameter = components.count - 1; 72 | HCJsApiMethod *apiMethod = [[HCJsApiMethod alloc] initWithName:methodName 73 | sel:sel 74 | numberOfParameter:numberOfParameter]; 75 | [methodNameArray addObject:apiMethod]; 76 | } 77 | cacheMethods = [methodNameArray copy]; 78 | [cacheDict setObject:cacheMethods forKey:apiName.spacename]; 79 | } 80 | HCJsBridgeMessageType messageType = [HCWebViewJsBridgeUtil judgeMessageTypeWithData:data 81 | callback:responseCallback]; 82 | if (messageType == HCJsBridgeMessageTypeNoArgument) { 83 | SEL sel = [HCWebViewJsBridgeUtil noParameterfindSELWithApiName:apiName.name 84 | methodList:cacheMethods]; 85 | if (!sel) { 86 | return HCJsBridgeHandleApiResultTypeNotFoundMethod; 87 | } 88 | ((void(*)(id,SEL))objc_msgSend)(target, sel); 89 | } else { 90 | NSString *searchApiName = [NSString stringWithFormat:@"%@:", apiName.name]; 91 | if (messageType == HCJsBridgeMessageTypeDataAndCallback) { 92 | searchApiName = [NSString stringWithFormat:@"%@:callback:", apiName.name]; 93 | } 94 | SEL sel = [HCWebViewJsBridgeUtil moreParameterfindSELWithApiName:searchApiName 95 | methodList:cacheMethods]; 96 | if (!sel) { 97 | return HCJsBridgeHandleApiResultTypeNotFoundMethod; 98 | } 99 | if (messageType == HCJsBridgeMessageTypeDataAndCallback) { 100 | ((void(*)(id,SEL,id,id))objc_msgSend)(target, sel, data, responseCallback); 101 | } else if (messageType == HCJsBridgeMessageTypeOnlyData) { 102 | ((void(*)(id,SEL,id))objc_msgSend)(target, sel, data); 103 | } else if (messageType == HCJsBridgeMessageTypeOnlyCallback) { 104 | ((void(*)(id,SEL,id))objc_msgSend)(target, sel, responseCallback); 105 | } 106 | } 107 | return HCJsBridgeHandleApiResultTypeSuccess; 108 | } 109 | 110 | + (SEL)noParameterfindSELWithApiName:(NSString *)apiName methodList:(NSArray *)methodList { 111 | for (HCJsApiMethod *apiMethod in methodList) { 112 | if ([apiMethod.name isEqualToString:apiName]) { 113 | return apiMethod.selector; 114 | } 115 | } 116 | return nil; 117 | } 118 | 119 | + (SEL)moreParameterfindSELWithApiName:(NSString *)apiName methodList:(NSArray *)methodList { 120 | for (HCJsApiMethod *apiMethod in methodList) { 121 | if ([apiMethod.name isEqualToString:apiName]) { 122 | return apiMethod.selector; 123 | } 124 | } 125 | return nil; 126 | } 127 | 128 | + (HCJsBridgeMessageType)judgeMessageTypeWithData:(id)data 129 | callback:(HCJBResponseCallback)responseCallback { 130 | if ([HCWebViewJsBridgeUtil nonNull:data] && [HCWebViewJsBridgeUtil nonNull:responseCallback]) { 131 | return HCJsBridgeMessageTypeDataAndCallback; 132 | } else if ([HCWebViewJsBridgeUtil nonNull:data]) { 133 | return HCJsBridgeMessageTypeOnlyData; 134 | } else if ([HCWebViewJsBridgeUtil nonNull:responseCallback]) { 135 | return HCJsBridgeMessageTypeOnlyCallback; 136 | } 137 | return HCJsBridgeMessageTypeNoArgument; 138 | } 139 | 140 | + (NSString *)generateCallbackId { 141 | NSString *uuid = [[[NSUUID UUID] UUIDString] stringByReplacingOccurrencesOfString:@"-" withString:@""]; 142 | NSString *callbackId = [NSString stringWithFormat:kJsBridgeNativeCallbackFormat, uuid]; 143 | return callbackId; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Liu Haichuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebViewJsBridge-iOS 2 | 3 | [![](https://img.shields.io/badge/build-pass-green)](https://github.com/al-liu/WebViewJsBridge-iOS) [![](https://img.shields.io/badge/language-Objective--C-brightgreen)](https://github.com/al-liu/WebViewJsBridge-iOS) [![](https://img.shields.io/cocoapods/p/HCWebViewJsBridge)](https://github.com/al-liu/WebViewJsBridge-iOS) [![](https://img.shields.io/github/license/al-liu/WebViewJsBridge-iOS)](./LICENSE) 4 | 5 | WebViewJsBridge-iOS 是 JavaScript 与 iOS WKWebView 通信的桥接库。 6 | 7 | 配套的 Android 版本:[https://github.com/al-liu/WebViewJsBridge-Android](https://github.com/al-liu/WebViewJsBridge-Android) 8 | 9 | 如果还需要兼容 UIWebView 请参考文档底部的说明。 10 | 11 | 本桥接库的特点是跨平台,支持 iOS,Android。Js 对 iOS,Android 的接口调用统一,简单易用。支持将客户端接口划分到多个实现类中进行管理,用命名空间加以区分,如 ui.alert,ui 对应一个实现类的命名空间,alert 是该实现类的一个实现方法。 12 | 13 | ## 安装 14 | 15 | ### CocoaPods 16 | [CocoaPods](https://cocoapods.org/) 是 Cocoa 项目的依赖管理器,使用方法和安装步骤请参考 CocoaPods 的官网。使用 CocoaPods 整合 WebViewJsBridge-iOS 到你的项目中,需要指定如下内容到你的 Podfile 文件: 17 | 18 | ```oc 19 | platform :ios, '8.0' 20 | 21 | target 'TargetName' do 22 | pod 'HCWebViewJsBridge', '~> 1.2.0' 23 | end 24 | ``` 25 | 26 | 然后,运行如下命令: 27 | 28 | ```oc 29 | $ pod install 30 | ``` 31 | 32 | ### 手动安装 33 | 下载 HCWebViewJsBridge 的源代码,并添加到自己的项目中即可使用。 34 | 35 | ### 引入 hcJsBridge.min.js 文件 36 | 在 html 文件中引用 js: `` 。 37 | 38 | #### 在 vue 项目中引用 hcJsBridge.min.js 39 | 引入方法:`import './hcJsBridge.min.js'` 40 | import js 文件后,即可用 `window.hcJsBridge` 调用客户端接口。 41 | 如果不想用 `window.hcJsBridge` 的方式调用,可以使用 vue 插件。 42 | 43 | ```js 44 | var jsBridge = {} 45 | jsBridge.install = function (Vue, options) { 46 | Vue.prototype.$hcJsBridge = window.hcJsBridge 47 | } 48 | export default jsBridge 49 | ``` 50 | 51 | 然后在 main.js 中: 52 | 53 | ```js 54 | import JsBridge from './plugins/jsBridge' 55 | Vue.use(JsBridge) 56 | ``` 57 | 58 | 在 vue 实例中使用: 59 | 60 | ```js 61 | this.$hcJsBridge.callHandler('ui.alert', data, function (responseData) { 62 | if (responseData === 'ok') { 63 | affirm() 64 | } else { 65 | cancel() 66 | } 67 | }) 68 | ``` 69 | 70 | ## Example 的说明 71 | `/Example/iOS Example` 文件夹下提供完整使用示例,包括基础的调用演示和进阶用法,如,使用 `UIImagePickerController` 调用相机拍摄一张图片,使用 `NSURLSession` 发起一个 GET 请求。 72 | 73 | ## 使用方法 74 | 75 | ### 初始化原生的 WebViewJsBridge 环境 76 | 77 | #### WKWebView 78 | 79 | **如果 H5 引入 hcJsBridge.js,则使用下面这个初始化方法。** 80 | 81 | ```oc 82 | _bridge = [HCWKWebViewJsBridge bridgeWithWebView:self.wkWebView]; 83 | ``` 84 | 85 | **如果 H5 不引入 hcJsBridge.js,则使用下面这个初始化方法。** 86 | 87 | ```oc 88 | _bridge = [HCWKWebViewJsBridge bridgeWithWebView:self.wkWebView injectJS:YES]; 89 | ``` 90 | 91 | ### 原生注册接口供 HTML5 调用 92 | 93 | ```c 94 | UIJsApi *uiApi = [UIJsApi new]; 95 | [_bridge addJsBridgeApiObject:uiApi namespace:@"ui"]; 96 | 97 | RequestJsApi *requestJsApi = [RequestJsApi new]; 98 | [_bridge addJsBridgeApiObject:requestJsApi namespace:@"request"]; 99 | ``` 100 | 101 | UIJsApi 实现类: 102 | 103 | ```c 104 | - (void)alert:(NSDictionary *)data callback:(HCJBResponseCallback)callback { 105 | callback(@"native api alert’callback."); 106 | } 107 | // 接口实现类支持四种方法签名(Js 在调用时要遵循对应的方法签名): 108 | // 1. 有参数,有回调 109 | - (void)test1:(NSString *)data callback:(HCJBResponseCallback)callback { 110 | NSLog(@"Js call native api test1, data is:%@", data); 111 | callback(@"native api test1’callback.(备注:汉字测试)"); 112 | } 113 | // 2. 有参数,无回调 114 | - (void)test2:(NSDictionary *)data { 115 | NSLog(@"Js native api:test2, data is:%@", data); 116 | } 117 | // 3. 无参数,无回调 118 | - (void)test3 { 119 | NSLog(@"Js native api:test3"); 120 | } 121 | // 4. 无参数,有回调 122 | - (void)test4:(HCJBResponseCallback)callback { 123 | NSLog(@"Js native api:test4"); 124 | callback(@"native api test4'callback.(备注:汉字测试)"); 125 | } 126 | ``` 127 | 128 | ### 原生调用 HTML5 接口 129 | 130 | ```c 131 | [_bridge callHandler:@"testCallJs" data:@{@"foo": @"bar"} responseCallback:^(id _Nonnull responseData) { 132 | NSLog(@"testCallJs callback data is:%@", responseData); 133 | }]; 134 | ``` 135 | 136 | ### 初始化 HTML5 的 WebViewJsBridge 环境 137 | 138 | 初始化环境需要引入 `hcJsBridge.min.js` 文件,引用方式前面有介绍。 139 | 140 | **如果 H5 不引入 hcJsBridge.min.js,则需要使用下面的方式注册接口。** 141 | 142 | ```js 143 | // 在这个 window._hcJsBridgeInitFinished 全局函数中等待 bridge 初始化完成,然后注册接口,初始调用。 144 | window._hcJsBridgeInitFinished = function(bridge) { 145 | // 注册接口给原生调用 146 | bridge.registerHandler("test1", function(data, callback) { 147 | callback('callback native,handlename is test1'); 148 | }) 149 | 150 | // 调用原生接口 151 | bridge.callHandler('ui.test3'); 152 | } 153 | ``` 154 | 155 | ### HTML5 注册接口供原生调用 156 | 157 | ```js 158 | hcJsBridge.registerHandler("testCallJs", function(data, callback) { 159 | log('Native call js ,handlename is testCallJs, data is:', data); 160 | callback('callback native, handlename is testCallJs'); 161 | }) 162 | ``` 163 | 164 | ### HTML5 调用原生接口 165 | 166 | ```js 167 | var data = {foo: "bar"}; 168 | hcJsBridge.callHandler('ui.alert', data, function (responseData) { 169 | log('Js receives the response data returned by native, response data is', responseData); 170 | }) 171 | ``` 172 | 173 | ### 开启 debug 日志 174 | 175 | 开启 debug 日志,将打印一些调用信息,辅助排查问题。debug 日志默认不开启,release 模式下屏蔽 debug 日志,但不屏蔽 error 日志。 176 | 177 | ```oc 178 | [_bridge enableDebugLogging:YES]; 179 | ``` 180 | 181 | ## 兼容 UIWebView 182 | 183 | 您如果还需要兼容 UIWebView,请使用 1.1.0 版本。 184 | 185 | ```oc 186 | platform :ios, '8.0' 187 | 188 | target 'TargetName' do 189 | pod 'HCWebViewJsBridge', '~> 1.1.0' 190 | end 191 | ``` 192 | 193 | 使用过程中如果不起作用,请查看项目中除本工具库外,有没有使用该方法 `- (void)webView:(id)unuse didCreateJavaScriptContext:(JSContext *)ctx forFrame:(id)frame`,如果使用多个该方法只会有一个生效,所以只能保留一个该分类方法,并统一通知的 NotificationName。 194 | 195 | 196 | ``` 197 | NSString * const kHCDidCreateJSContextNotification = @"com.lhc.HCWebViewJsBridge.DidCreateJSContext"; 198 | @implementation NSObject (HCJSContext) 199 | 200 | - (void)webView:(id)unuse didCreateJavaScriptContext:(JSContext *)ctx forFrame:(id)frame { 201 | [[NSNotificationCenter defaultCenter] postNotificationName:kHCDidCreateJSContextNotification object:ctx]; 202 | } 203 | ``` 204 | 205 | ## License 206 | WebViewJsBridge-iOS 使用 MIT license 发布,查看 [LICENSE](./LICENSE) 详情。 207 | 208 | --------------------------------------------------------------------------------