├── .DS_Store ├── EasyJSWebViewSample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── alex.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── alex621.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── alex.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints.xcbkptlist │ └── xcschemes │ │ ├── EasyJSWebViewSample.xcscheme │ │ └── xcschememanagement.plist │ └── alex621.xcuserdatad │ └── xcschemes │ ├── EasyJSWebViewSample.xcscheme │ └── xcschememanagement.plist ├── EasyJSWebViewSample ├── .DS_Store ├── AppDelegate.h ├── AppDelegate.m ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── EasyJSWebView │ ├── EasyJSDataFunction.h │ ├── EasyJSDataFunction.m │ ├── EasyJSWebView.h │ ├── EasyJSWebView.m │ ├── EasyJSWebViewProxyDelegate.h │ ├── EasyJSWebViewProxyDelegate.m │ └── easyjs-inject.js ├── EasyJSWebViewSample-Info.plist ├── EasyJSWebViewSample-Prefix.pch ├── MyJSInterface.h ├── MyJSInterface.m ├── ViewController.h ├── ViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── ViewController_iPhone.xib ├── main.m └── test.html └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/.DS_Store -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B56DD5EE16AAE68C00AD40F3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56DD5ED16AAE68C00AD40F3 /* UIKit.framework */; }; 11 | B56DD5F016AAE68C00AD40F3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56DD5EF16AAE68C00AD40F3 /* Foundation.framework */; }; 12 | B56DD5F216AAE68C00AD40F3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B56DD5F116AAE68C00AD40F3 /* CoreGraphics.framework */; }; 13 | B56DD5F816AAE68C00AD40F3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B56DD5F616AAE68C00AD40F3 /* InfoPlist.strings */; }; 14 | B56DD5FA16AAE68C00AD40F3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD5F916AAE68C00AD40F3 /* main.m */; }; 15 | B56DD5FE16AAE68C00AD40F3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD5FD16AAE68C00AD40F3 /* AppDelegate.m */; }; 16 | B56DD60016AAE68C00AD40F3 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = B56DD5FF16AAE68C00AD40F3 /* Default.png */; }; 17 | B56DD60216AAE68C00AD40F3 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B56DD60116AAE68C00AD40F3 /* Default@2x.png */; }; 18 | B56DD60416AAE68C00AD40F3 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B56DD60316AAE68C00AD40F3 /* Default-568h@2x.png */; }; 19 | B56DD60716AAE68C00AD40F3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD60616AAE68C00AD40F3 /* ViewController.m */; }; 20 | B56DD60A16AAE68C00AD40F3 /* ViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = B56DD60816AAE68C00AD40F3 /* ViewController_iPhone.xib */; }; 21 | B56DD61916AAE6D700AD40F3 /* easyjs-inject.js in Sources */ = {isa = PBXBuildFile; fileRef = B56DD61416AAE6D700AD40F3 /* easyjs-inject.js */; }; 22 | B56DD61A16AAE6D700AD40F3 /* EasyJSWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD61616AAE6D700AD40F3 /* EasyJSWebView.m */; }; 23 | B56DD61B16AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD61816AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.m */; }; 24 | B56DD61D16AAE73500AD40F3 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = B56DD61C16AAE73500AD40F3 /* test.html */; }; 25 | B56DD62016AAE7A300AD40F3 /* MyJSInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = B56DD61F16AAE7A200AD40F3 /* MyJSInterface.m */; }; 26 | FAFC6E1816AD815200DFE50D /* EasyJSDataFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = FAFC6E1716AD815200DFE50D /* EasyJSDataFunction.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | B56DD5E916AAE68C00AD40F3 /* EasyJSWebViewSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EasyJSWebViewSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | B56DD5ED16AAE68C00AD40F3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 32 | B56DD5EF16AAE68C00AD40F3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 33 | B56DD5F116AAE68C00AD40F3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 34 | B56DD5F516AAE68C00AD40F3 /* EasyJSWebViewSample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "EasyJSWebViewSample-Info.plist"; sourceTree = ""; }; 35 | B56DD5F716AAE68C00AD40F3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 36 | B56DD5F916AAE68C00AD40F3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 37 | B56DD5FB16AAE68C00AD40F3 /* EasyJSWebViewSample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EasyJSWebViewSample-Prefix.pch"; sourceTree = ""; }; 38 | B56DD5FC16AAE68C00AD40F3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | B56DD5FD16AAE68C00AD40F3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | B56DD5FF16AAE68C00AD40F3 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 41 | B56DD60116AAE68C00AD40F3 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 42 | B56DD60316AAE68C00AD40F3 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 43 | B56DD60516AAE68C00AD40F3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | B56DD60616AAE68C00AD40F3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | B56DD60916AAE68C00AD40F3 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController_iPhone.xib; sourceTree = ""; }; 46 | B56DD61416AAE6D700AD40F3 /* easyjs-inject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "easyjs-inject.js"; sourceTree = ""; }; 47 | B56DD61516AAE6D700AD40F3 /* EasyJSWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EasyJSWebView.h; sourceTree = ""; }; 48 | B56DD61616AAE6D700AD40F3 /* EasyJSWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EasyJSWebView.m; sourceTree = ""; }; 49 | B56DD61716AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EasyJSWebViewProxyDelegate.h; sourceTree = ""; }; 50 | B56DD61816AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EasyJSWebViewProxyDelegate.m; sourceTree = ""; }; 51 | B56DD61C16AAE73500AD40F3 /* test.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test.html; sourceTree = ""; }; 52 | B56DD61E16AAE7A200AD40F3 /* MyJSInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyJSInterface.h; sourceTree = ""; }; 53 | B56DD61F16AAE7A200AD40F3 /* MyJSInterface.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyJSInterface.m; sourceTree = ""; }; 54 | FAFC6E1616AD815200DFE50D /* EasyJSDataFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EasyJSDataFunction.h; sourceTree = ""; }; 55 | FAFC6E1716AD815200DFE50D /* EasyJSDataFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EasyJSDataFunction.m; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | B56DD5E616AAE68C00AD40F3 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | B56DD5EE16AAE68C00AD40F3 /* UIKit.framework in Frameworks */, 64 | B56DD5F016AAE68C00AD40F3 /* Foundation.framework in Frameworks */, 65 | B56DD5F216AAE68C00AD40F3 /* CoreGraphics.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | B56DD5DE16AAE68C00AD40F3 = { 73 | isa = PBXGroup; 74 | children = ( 75 | B56DD5F316AAE68C00AD40F3 /* EasyJSWebViewSample */, 76 | B56DD5EC16AAE68C00AD40F3 /* Frameworks */, 77 | B56DD5EA16AAE68C00AD40F3 /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | B56DD5EA16AAE68C00AD40F3 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | B56DD5E916AAE68C00AD40F3 /* EasyJSWebViewSample.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | B56DD5EC16AAE68C00AD40F3 /* Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | B56DD5ED16AAE68C00AD40F3 /* UIKit.framework */, 93 | B56DD5EF16AAE68C00AD40F3 /* Foundation.framework */, 94 | B56DD5F116AAE68C00AD40F3 /* CoreGraphics.framework */, 95 | ); 96 | name = Frameworks; 97 | sourceTree = ""; 98 | }; 99 | B56DD5F316AAE68C00AD40F3 /* EasyJSWebViewSample */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | B56DD61316AAE6D700AD40F3 /* EasyJSWebView */, 103 | B56DD5FC16AAE68C00AD40F3 /* AppDelegate.h */, 104 | B56DD5FD16AAE68C00AD40F3 /* AppDelegate.m */, 105 | B56DD61E16AAE7A200AD40F3 /* MyJSInterface.h */, 106 | B56DD61F16AAE7A200AD40F3 /* MyJSInterface.m */, 107 | B56DD60516AAE68C00AD40F3 /* ViewController.h */, 108 | B56DD60616AAE68C00AD40F3 /* ViewController.m */, 109 | B56DD60816AAE68C00AD40F3 /* ViewController_iPhone.xib */, 110 | B56DD5F416AAE68C00AD40F3 /* Supporting Files */, 111 | ); 112 | path = EasyJSWebViewSample; 113 | sourceTree = ""; 114 | }; 115 | B56DD5F416AAE68C00AD40F3 /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | B56DD61C16AAE73500AD40F3 /* test.html */, 119 | B56DD5F516AAE68C00AD40F3 /* EasyJSWebViewSample-Info.plist */, 120 | B56DD5F616AAE68C00AD40F3 /* InfoPlist.strings */, 121 | B56DD5F916AAE68C00AD40F3 /* main.m */, 122 | B56DD5FB16AAE68C00AD40F3 /* EasyJSWebViewSample-Prefix.pch */, 123 | B56DD5FF16AAE68C00AD40F3 /* Default.png */, 124 | B56DD60116AAE68C00AD40F3 /* Default@2x.png */, 125 | B56DD60316AAE68C00AD40F3 /* Default-568h@2x.png */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | B56DD61316AAE6D700AD40F3 /* EasyJSWebView */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | B56DD61416AAE6D700AD40F3 /* easyjs-inject.js */, 134 | B56DD61516AAE6D700AD40F3 /* EasyJSWebView.h */, 135 | B56DD61616AAE6D700AD40F3 /* EasyJSWebView.m */, 136 | B56DD61716AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.h */, 137 | B56DD61816AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.m */, 138 | FAFC6E1616AD815200DFE50D /* EasyJSDataFunction.h */, 139 | FAFC6E1716AD815200DFE50D /* EasyJSDataFunction.m */, 140 | ); 141 | path = EasyJSWebView; 142 | sourceTree = ""; 143 | }; 144 | /* End PBXGroup section */ 145 | 146 | /* Begin PBXNativeTarget section */ 147 | B56DD5E816AAE68C00AD40F3 /* EasyJSWebViewSample */ = { 148 | isa = PBXNativeTarget; 149 | buildConfigurationList = B56DD61016AAE68C00AD40F3 /* Build configuration list for PBXNativeTarget "EasyJSWebViewSample" */; 150 | buildPhases = ( 151 | B56DD5E516AAE68C00AD40F3 /* Sources */, 152 | B56DD5E616AAE68C00AD40F3 /* Frameworks */, 153 | B56DD5E716AAE68C00AD40F3 /* Resources */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = EasyJSWebViewSample; 160 | productName = EasyJSWebViewSample; 161 | productReference = B56DD5E916AAE68C00AD40F3 /* EasyJSWebViewSample.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | B56DD5E016AAE68C00AD40F3 /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | LastUpgradeCheck = 0450; 171 | ORGANIZATIONNAME = Dukeland; 172 | }; 173 | buildConfigurationList = B56DD5E316AAE68C00AD40F3 /* Build configuration list for PBXProject "EasyJSWebViewSample" */; 174 | compatibilityVersion = "Xcode 3.2"; 175 | developmentRegion = English; 176 | hasScannedForEncodings = 0; 177 | knownRegions = ( 178 | en, 179 | ); 180 | mainGroup = B56DD5DE16AAE68C00AD40F3; 181 | productRefGroup = B56DD5EA16AAE68C00AD40F3 /* Products */; 182 | projectDirPath = ""; 183 | projectRoot = ""; 184 | targets = ( 185 | B56DD5E816AAE68C00AD40F3 /* EasyJSWebViewSample */, 186 | ); 187 | }; 188 | /* End PBXProject section */ 189 | 190 | /* Begin PBXResourcesBuildPhase section */ 191 | B56DD5E716AAE68C00AD40F3 /* Resources */ = { 192 | isa = PBXResourcesBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | B56DD5F816AAE68C00AD40F3 /* InfoPlist.strings in Resources */, 196 | B56DD60016AAE68C00AD40F3 /* Default.png in Resources */, 197 | B56DD60216AAE68C00AD40F3 /* Default@2x.png in Resources */, 198 | B56DD60416AAE68C00AD40F3 /* Default-568h@2x.png in Resources */, 199 | B56DD60A16AAE68C00AD40F3 /* ViewController_iPhone.xib in Resources */, 200 | B56DD61D16AAE73500AD40F3 /* test.html in Resources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXResourcesBuildPhase section */ 205 | 206 | /* Begin PBXSourcesBuildPhase section */ 207 | B56DD5E516AAE68C00AD40F3 /* Sources */ = { 208 | isa = PBXSourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | B56DD5FA16AAE68C00AD40F3 /* main.m in Sources */, 212 | B56DD5FE16AAE68C00AD40F3 /* AppDelegate.m in Sources */, 213 | B56DD60716AAE68C00AD40F3 /* ViewController.m in Sources */, 214 | B56DD61916AAE6D700AD40F3 /* easyjs-inject.js in Sources */, 215 | B56DD61A16AAE6D700AD40F3 /* EasyJSWebView.m in Sources */, 216 | B56DD61B16AAE6D700AD40F3 /* EasyJSWebViewProxyDelegate.m in Sources */, 217 | B56DD62016AAE7A300AD40F3 /* MyJSInterface.m in Sources */, 218 | FAFC6E1816AD815200DFE50D /* EasyJSDataFunction.m in Sources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXSourcesBuildPhase section */ 223 | 224 | /* Begin PBXVariantGroup section */ 225 | B56DD5F616AAE68C00AD40F3 /* InfoPlist.strings */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | B56DD5F716AAE68C00AD40F3 /* en */, 229 | ); 230 | name = InfoPlist.strings; 231 | sourceTree = ""; 232 | }; 233 | B56DD60816AAE68C00AD40F3 /* ViewController_iPhone.xib */ = { 234 | isa = PBXVariantGroup; 235 | children = ( 236 | B56DD60916AAE68C00AD40F3 /* en */, 237 | ); 238 | name = ViewController_iPhone.xib; 239 | sourceTree = ""; 240 | }; 241 | /* End PBXVariantGroup section */ 242 | 243 | /* Begin XCBuildConfiguration section */ 244 | B56DD60E16AAE68C00AD40F3 /* Debug */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 249 | CLANG_CXX_LIBRARY = "libc++"; 250 | CLANG_ENABLE_OBJC_ARC = NO; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 253 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 254 | COPY_PHASE_STRIP = NO; 255 | GCC_C_LANGUAGE_STANDARD = gnu99; 256 | GCC_DYNAMIC_NO_PIC = NO; 257 | GCC_OPTIMIZATION_LEVEL = 0; 258 | GCC_PREPROCESSOR_DEFINITIONS = ( 259 | "DEBUG=1", 260 | "$(inherited)", 261 | ); 262 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 263 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 264 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 267 | ONLY_ACTIVE_ARCH = YES; 268 | SDKROOT = iphoneos; 269 | TARGETED_DEVICE_FAMILY = "1,2"; 270 | }; 271 | name = Debug; 272 | }; 273 | B56DD60F16AAE68C00AD40F3 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_OBJC_ARC = NO; 280 | CLANG_WARN_EMPTY_BODY = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 283 | COPY_PHASE_STRIP = YES; 284 | GCC_C_LANGUAGE_STANDARD = gnu99; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 287 | GCC_WARN_UNUSED_VARIABLE = YES; 288 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 289 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 290 | SDKROOT = iphoneos; 291 | TARGETED_DEVICE_FAMILY = "1,2"; 292 | VALIDATE_PRODUCT = YES; 293 | }; 294 | name = Release; 295 | }; 296 | B56DD61116AAE68C00AD40F3 /* Debug */ = { 297 | isa = XCBuildConfiguration; 298 | buildSettings = { 299 | CLANG_ENABLE_OBJC_ARC = NO; 300 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 301 | GCC_PREFIX_HEADER = "EasyJSWebViewSample/EasyJSWebViewSample-Prefix.pch"; 302 | INFOPLIST_FILE = "EasyJSWebViewSample/EasyJSWebViewSample-Info.plist"; 303 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 304 | PRODUCT_NAME = "$(TARGET_NAME)"; 305 | WRAPPER_EXTENSION = app; 306 | }; 307 | name = Debug; 308 | }; 309 | B56DD61216AAE68C00AD40F3 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | CLANG_ENABLE_OBJC_ARC = NO; 313 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 314 | GCC_PREFIX_HEADER = "EasyJSWebViewSample/EasyJSWebViewSample-Prefix.pch"; 315 | INFOPLIST_FILE = "EasyJSWebViewSample/EasyJSWebViewSample-Info.plist"; 316 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 317 | PRODUCT_NAME = "$(TARGET_NAME)"; 318 | WRAPPER_EXTENSION = app; 319 | }; 320 | name = Release; 321 | }; 322 | /* End XCBuildConfiguration section */ 323 | 324 | /* Begin XCConfigurationList section */ 325 | B56DD5E316AAE68C00AD40F3 /* Build configuration list for PBXProject "EasyJSWebViewSample" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | B56DD60E16AAE68C00AD40F3 /* Debug */, 329 | B56DD60F16AAE68C00AD40F3 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | B56DD61016AAE68C00AD40F3 /* Build configuration list for PBXNativeTarget "EasyJSWebViewSample" */ = { 335 | isa = XCConfigurationList; 336 | buildConfigurations = ( 337 | B56DD61116AAE68C00AD40F3 /* Debug */, 338 | B56DD61216AAE68C00AD40F3 /* Release */, 339 | ); 340 | defaultConfigurationIsVisible = 0; 341 | defaultConfigurationName = Release; 342 | }; 343 | /* End XCConfigurationList section */ 344 | }; 345 | rootObject = B56DD5E016AAE68C00AD40F3 /* Project object */; 346 | } 347 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/project.xcworkspace/xcuserdata/alex.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample.xcodeproj/project.xcworkspace/xcuserdata/alex.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/project.xcworkspace/xcuserdata/alex621.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample.xcodeproj/project.xcworkspace/xcuserdata/alex621.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/xcuserdata/alex.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/xcuserdata/alex.xcuserdatad/xcschemes/EasyJSWebViewSample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/xcuserdata/alex.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | EasyJSWebViewSample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B56DD5E816AAE68C00AD40F3 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/xcuserdata/alex621.xcuserdatad/xcschemes/EasyJSWebViewSample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /EasyJSWebViewSample.xcodeproj/xcuserdata/alex621.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | EasyJSWebViewSample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B56DD5E816AAE68C00AD40F3 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample/.DS_Store -------------------------------------------------------------------------------- /EasyJSWebViewSample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ViewController; 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) ViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil]; 20 | self.window.rootViewController = self.viewController; 21 | [self.window makeKeyAndVisible]; 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application 26 | { 27 | // 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. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | - (void)applicationDidEnterBackground:(UIApplication *)application 32 | { 33 | // 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. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application 38 | { 39 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | - (void)applicationDidBecomeActive:(UIApplication *)application 43 | { 44 | // 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. 45 | } 46 | 47 | - (void)applicationWillTerminate:(UIApplication *)application 48 | { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample/Default-568h@2x.png -------------------------------------------------------------------------------- /EasyJSWebViewSample/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample/Default.png -------------------------------------------------------------------------------- /EasyJSWebViewSample/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dukeland/EasyJSWebViewSample/e5cc510bdbdfbb8ce355c5d6bc6cff913602b199/EasyJSWebViewSample/Default@2x.png -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSDataFunction.h: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSDataFunction.h 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Alex Lau on 21/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EasyJSWebView.h" 11 | 12 | @interface EasyJSDataFunction : NSObject 13 | 14 | @property (nonatomic, retain) NSString* funcID; 15 | @property (nonatomic, retain) EasyJSWebView* webView; 16 | @property (nonatomic, assign) BOOL removeAfterExecute; 17 | 18 | - (id) initWithWebView: (EasyJSWebView*) _webView; 19 | 20 | - (NSString*) execute; 21 | - (NSString*) executeWithParam: (NSString*) param; 22 | - (NSString*) executeWithParams: (NSArray*) params; 23 | 24 | @end -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSDataFunction.m: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSDataFunction.m 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Alex Lau on 21/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "EasyJSDataFunction.h" 10 | 11 | @implementation EasyJSDataFunction 12 | 13 | @synthesize funcID; 14 | @synthesize webView; 15 | @synthesize removeAfterExecute; 16 | 17 | - (id) initWithWebView:(EasyJSWebView *)_webView{ 18 | self = [super init]; 19 | if (self) { 20 | self.webView = _webView; 21 | } 22 | return self; 23 | } 24 | 25 | - (NSString*) execute{ 26 | return [self executeWithParams:nil]; 27 | } 28 | 29 | - (NSString*) executeWithParam: (NSString*) param{ 30 | NSMutableArray* params = [[NSMutableArray alloc] initWithObjects:param, nil]; 31 | return [self executeWithParams:params]; 32 | } 33 | 34 | - (NSString*) executeWithParams: (NSArray*) params{ 35 | NSMutableString* injection = [[NSMutableString alloc] init]; 36 | 37 | [injection appendFormat:@"EasyJS.invokeCallback(\"%@\", %@", self.funcID, self.removeAfterExecute ? @"true" : @"false"]; 38 | 39 | if (params){ 40 | for (int i = 0, l = params.count; i < l; i++){ 41 | NSString* arg = [params objectAtIndex:i]; 42 | NSString* encodedArg = (NSString*) CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)arg, NULL, (CFStringRef) @"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8); 43 | 44 | [injection appendFormat:@", \"%@\"", encodedArg]; 45 | } 46 | } 47 | 48 | [injection appendString:@");"]; 49 | 50 | if (self.webView){ 51 | return [self.webView stringByEvaluatingJavaScriptFromString:injection]; 52 | }else{ 53 | return nil; 54 | } 55 | } 56 | 57 | @end -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSWebView.h: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSWebView.h 3 | // EasyJS 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EasyJSWebViewProxyDelegate.h" 11 | 12 | @interface EasyJSWebView : UIWebView 13 | 14 | // All the events will pass through this proxy delegate first 15 | @property (nonatomic, retain) EasyJSWebViewProxyDelegate* proxyDelegate; 16 | 17 | - (void) initEasyJS; 18 | - (void) addJavascriptInterfaces:(NSObject*) interface WithName:(NSString*) name; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSWebView.m: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSWebView.m 3 | // EasyJS 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "EasyJSWebView.h" 10 | 11 | @implementation EasyJSWebView 12 | 13 | @synthesize proxyDelegate; 14 | 15 | - (id)initWithFrame:(CGRect)frame{ 16 | self = [super initWithFrame:frame]; 17 | if (self) { 18 | [self initEasyJS]; 19 | } 20 | return self; 21 | } 22 | - (id)init{ 23 | self = [super init]; 24 | if (self) { 25 | [self initEasyJS]; 26 | } 27 | return self; 28 | } 29 | - (id)initWithCoder:(NSCoder *)aDecoder{ 30 | self = [super initWithCoder:aDecoder]; 31 | 32 | if (self){ 33 | [self initEasyJS]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | - (void) initEasyJS{ 40 | self.proxyDelegate = [[EasyJSWebViewProxyDelegate alloc] init]; 41 | self.delegate = self.proxyDelegate; 42 | } 43 | 44 | - (void) setDelegate:(id)delegate{ 45 | if (delegate != self.proxyDelegate){ 46 | self.proxyDelegate.realDelegate = delegate; 47 | }else{ 48 | [super setDelegate:delegate]; 49 | } 50 | } 51 | 52 | - (void) addJavascriptInterfaces:(NSObject*) interface WithName:(NSString*) name{ 53 | [self.proxyDelegate addJavascriptInterfaces:interface WithName:name]; 54 | } 55 | 56 | - (void) dealloc{ 57 | [super dealloc]; 58 | 59 | [self.proxyDelegate release]; 60 | self.proxyDelegate = nil; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSWebViewProxyDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSWebViewDelegate.h 3 | // EasyJS 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface EasyJSWebViewProxyDelegate : NSObject 12 | 13 | @property (nonatomic, retain) NSMutableDictionary* javascriptInterfaces; 14 | @property (nonatomic, retain) id realDelegate; 15 | 16 | - (void) addJavascriptInterfaces:(NSObject*) interface WithName:(NSString*) name; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/EasyJSWebViewProxyDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // EasyJSWebViewDelegate.m 3 | // EasyJS 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "EasyJSWebViewProxyDelegate.h" 10 | #import "EasyJSDataFunction.h" 11 | #import 12 | 13 | /* 14 | This is the content of easyjs-inject.js 15 | Putting it inline in order to prevent loading from files 16 | */ 17 | NSString* INJECT_JS = @"window.EasyJS = {\ 18 | __callbacks: {},\ 19 | \ 20 | invokeCallback: function (cbID, removeAfterExecute){\ 21 | var args = Array.prototype.slice.call(arguments);\ 22 | args.shift();\ 23 | args.shift();\ 24 | \ 25 | for (var i = 0, l = args.length; i < l; i++){\ 26 | args[i] = decodeURIComponent(args[i]);\ 27 | }\ 28 | \ 29 | var cb = EasyJS.__callbacks[cbID];\ 30 | if (removeAfterExecute){\ 31 | EasyJS.__callbacks[cbID] = undefined;\ 32 | }\ 33 | return cb.apply(null, args);\ 34 | },\ 35 | \ 36 | call: function (obj, functionName, args){\ 37 | var formattedArgs = [];\ 38 | for (var i = 0, l = args.length; i < l; i++){\ 39 | if (typeof args[i] == \"function\"){\ 40 | formattedArgs.push(\"f\");\ 41 | var cbID = \"__cb\" + (+new Date);\ 42 | EasyJS.__callbacks[cbID] = args[i];\ 43 | formattedArgs.push(cbID);\ 44 | }else{\ 45 | formattedArgs.push(\"s\");\ 46 | formattedArgs.push(encodeURIComponent(args[i]));\ 47 | }\ 48 | }\ 49 | \ 50 | var argStr = (formattedArgs.length > 0 ? \":\" + encodeURIComponent(formattedArgs.join(\":\")) : \"\");\ 51 | \ 52 | var iframe = document.createElement(\"IFRAME\");\ 53 | iframe.setAttribute(\"src\", \"easy-js:\" + obj + \":\" + encodeURIComponent(functionName) + argStr);\ 54 | document.documentElement.appendChild(iframe);\ 55 | iframe.parentNode.removeChild(iframe);\ 56 | iframe = null;\ 57 | \ 58 | var ret = EasyJS.retValue;\ 59 | EasyJS.retValue = undefined;\ 60 | \ 61 | if (ret){\ 62 | return decodeURIComponent(ret);\ 63 | }\ 64 | },\ 65 | \ 66 | inject: function (obj, methods){\ 67 | window[obj] = {};\ 68 | var jsObj = window[obj];\ 69 | \ 70 | for (var i = 0, l = methods.length; i < l; i++){\ 71 | (function (){\ 72 | var method = methods[i];\ 73 | var jsMethod = method.replace(new RegExp(\":\", \"g\"), \"\");\ 74 | jsObj[jsMethod] = function (){\ 75 | return EasyJS.call(obj, method, Array.prototype.slice.call(arguments));\ 76 | };\ 77 | })();\ 78 | }\ 79 | }\ 80 | };"; 81 | 82 | @implementation EasyJSWebViewProxyDelegate 83 | 84 | @synthesize realDelegate; 85 | @synthesize javascriptInterfaces; 86 | 87 | - (void) addJavascriptInterfaces:(NSObject*) interface WithName:(NSString*) name{ 88 | if (! self.javascriptInterfaces){ 89 | self.javascriptInterfaces = [[NSMutableDictionary alloc] init]; 90 | } 91 | 92 | [self.javascriptInterfaces setValue:interface forKey:name]; 93 | } 94 | 95 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ 96 | [self.realDelegate webView:webView didFailLoadWithError:error]; 97 | } 98 | 99 | - (void)webViewDidFinishLoad:(UIWebView *)webView{ 100 | [self.realDelegate webViewDidFinishLoad:webView]; 101 | } 102 | 103 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ 104 | 105 | NSString *requestString = [[request URL] absoluteString]; 106 | 107 | if ([requestString hasPrefix:@"easy-js:"]) { 108 | /* 109 | A sample URL structure: 110 | easy-js:MyJSTest:test 111 | easy-js:MyJSTest:testWithParam%3A:haha 112 | */ 113 | NSArray *components = [requestString componentsSeparatedByString:@":"]; 114 | //NSLog(@"req: %@", requestString); 115 | 116 | NSString* obj = (NSString*)[components objectAtIndex:1]; 117 | NSString* method = [(NSString*)[components objectAtIndex:2] 118 | stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 119 | 120 | NSObject* interface = [javascriptInterfaces objectForKey:obj]; 121 | 122 | // execute the interfacing method 123 | SEL selector = NSSelectorFromString(method); 124 | NSMethodSignature* sig = [[interface class] instanceMethodSignatureForSelector:selector]; 125 | NSInvocation* invoker = [NSInvocation invocationWithMethodSignature:sig]; 126 | invoker.selector = selector; 127 | invoker.target = interface; 128 | 129 | NSMutableArray* args = [[NSMutableArray alloc] init]; 130 | 131 | if ([components count] > 3){ 132 | NSString *argsAsString = [(NSString*)[components objectAtIndex:3] 133 | stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 134 | 135 | NSArray* formattedArgs = [argsAsString componentsSeparatedByString:@":"]; 136 | for (int i = 0, j = 0, l = [formattedArgs count]; i < l; i+=2, j++){ 137 | NSString* type = ((NSString*) [formattedArgs objectAtIndex:i]); 138 | NSString* argStr = ((NSString*) [formattedArgs objectAtIndex:i + 1]); 139 | 140 | if ([@"f" isEqualToString:type]){ 141 | EasyJSDataFunction* func = [[EasyJSDataFunction alloc] initWithWebView:(EasyJSWebView *)webView]; 142 | func.funcID = argStr; 143 | [args addObject:func]; 144 | [invoker setArgument:&func atIndex:(j + 2)]; 145 | }else if ([@"s" isEqualToString:type]){ 146 | NSString* arg = [argStr stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 147 | [args addObject:arg]; 148 | [invoker setArgument:&arg atIndex:(j + 2)]; 149 | } 150 | } 151 | } 152 | [invoker invoke]; 153 | 154 | //return the value by using javascript 155 | if ([sig methodReturnLength] > 0){ 156 | NSString* retValue; 157 | [invoker getReturnValue:&retValue]; 158 | 159 | if (retValue == NULL || retValue == nil){ 160 | [webView stringByEvaluatingJavaScriptFromString:@"EasyJS.retValue=null;"]; 161 | }else{ 162 | retValue = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,(CFStringRef) retValue, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8)); 163 | [webView stringByEvaluatingJavaScriptFromString:[@"" stringByAppendingFormat:@"EasyJS.retValue=\"%@\";", retValue]]; 164 | } 165 | } 166 | 167 | [args release]; 168 | 169 | return NO; 170 | } 171 | 172 | if (! self.realDelegate){ 173 | return YES; 174 | } 175 | 176 | return [self.realDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; 177 | } 178 | 179 | - (void)webViewDidStartLoad:(UIWebView *)webView{ 180 | [self.realDelegate webViewDidStartLoad:webView]; 181 | 182 | if (! self.javascriptInterfaces){ 183 | self.javascriptInterfaces = [[NSMutableDictionary alloc] init]; 184 | } 185 | 186 | NSMutableString* injection = [[NSMutableString alloc] init]; 187 | 188 | //inject the javascript interface 189 | for(id key in self.javascriptInterfaces) { 190 | NSObject* interface = [self.javascriptInterfaces objectForKey:key]; 191 | 192 | [injection appendString:@"EasyJS.inject(\""]; 193 | [injection appendString:key]; 194 | [injection appendString:@"\", ["]; 195 | 196 | unsigned int mc = 0; 197 | Class cls = object_getClass(interface); 198 | Method * mlist = class_copyMethodList(cls, &mc); 199 | for (int i = 0; i < mc; i++){ 200 | [injection appendString:@"\""]; 201 | [injection appendString:[NSString stringWithUTF8String:sel_getName(method_getName(mlist[i]))]]; 202 | [injection appendString:@"\""]; 203 | 204 | if (i != mc - 1){ 205 | [injection appendString:@", "]; 206 | } 207 | } 208 | 209 | free(mlist); 210 | 211 | [injection appendString:@"]);"]; 212 | } 213 | 214 | 215 | NSString* js = INJECT_JS; 216 | //inject the basic functions first 217 | [webView stringByEvaluatingJavaScriptFromString:js]; 218 | //inject the function interface 219 | [webView stringByEvaluatingJavaScriptFromString:injection]; 220 | 221 | [injection release]; 222 | } 223 | 224 | - (void)dealloc{ 225 | if (self.javascriptInterfaces){ 226 | [self.javascriptInterfaces release]; 227 | self.javascriptInterfaces = nil; 228 | } 229 | 230 | if (self.realDelegate){ 231 | [self.realDelegate release]; 232 | self.realDelegate = nil; 233 | } 234 | 235 | [super dealloc]; 236 | } 237 | 238 | @end -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebView/easyjs-inject.js: -------------------------------------------------------------------------------- 1 | window.EasyJS = { 2 | __callbacks: {}, 3 | 4 | invokeCallback: function (cbID, removeAfterExecute){ 5 | var args = Array.prototype.slice.call(arguments); 6 | args.shift(); 7 | args.shift(); 8 | 9 | for (var i = 0, l = args.length; i < l; i++){ 10 | args[i] = decodeURIComponent(args[i]); 11 | } 12 | 13 | var cb = EasyJS.__callbacks[cbID]; 14 | if (removeAfterExecute){ 15 | EasyJS.__callbacks[cbID] = undefined; 16 | } 17 | return cb.apply(null, args); 18 | }, 19 | 20 | call: function (obj, functionName, args){ 21 | var formattedArgs = []; 22 | for (var i = 0, l = args.length; i < l; i++){ 23 | if (typeof args[i] == "function"){ 24 | formattedArgs.push("f"); 25 | var cbID = "__cb" + (+new Date); 26 | EasyJS.__callbacks[cbID] = args[i]; 27 | formattedArgs.push(cbID); 28 | }else{ 29 | formattedArgs.push("s"); 30 | formattedArgs.push(encodeURIComponent(args[i])); 31 | } 32 | } 33 | 34 | var argStr = (formattedArgs.length > 0 ? ":" + encodeURIComponent(formattedArgs.join(":")) : ""); 35 | 36 | var iframe = document.createElement("IFRAME"); 37 | iframe.setAttribute("src", "easy-js:" + obj + ":" + encodeURIComponent(functionName) + argStr); 38 | document.documentElement.appendChild(iframe); 39 | iframe.parentNode.removeChild(iframe); 40 | iframe = null; 41 | 42 | var ret = EasyJS.retValue; 43 | EasyJS.retValue = undefined; 44 | 45 | if (ret){ 46 | return decodeURIComponent(ret); 47 | } 48 | }, 49 | 50 | inject: function (obj, methods){ 51 | window[obj] = {}; 52 | var jsObj = window[obj]; 53 | 54 | for (var i = 0, l = methods.length; i < l; i++){ 55 | (function (){ 56 | var method = methods[i]; 57 | var jsMethod = method.replace(new RegExp(":", "g"), ""); 58 | jsObj[jsMethod] = function (){ 59 | return EasyJS.call(obj, method, Array.prototype.slice.call(arguments)); 60 | }; 61 | })(); 62 | } 63 | } 64 | }; -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebViewSample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.dukeland.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 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 | 45 | 46 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/EasyJSWebViewSample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'EasyJSWebViewSample' target in the 'EasyJSWebViewSample' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/MyJSInterface.h: -------------------------------------------------------------------------------- 1 | // 2 | // MyJSInterface.h 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EasyJSDataFunction.h" 11 | 12 | @interface MyJSInterface : NSObject 13 | 14 | - (void) test; 15 | - (void) testWithParam: (NSString*) param; 16 | - (void) testWithTwoParam: (NSString*) param AndParam2: (NSString*) param2; 17 | 18 | - (void) testWithFuncParam: (EasyJSDataFunction*) param; 19 | - (void) testWithFuncParam2: (EasyJSDataFunction*) param; 20 | 21 | - (NSString*) testWithRet; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/MyJSInterface.m: -------------------------------------------------------------------------------- 1 | // 2 | // MyJSInterface.m 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "MyJSInterface.h" 10 | 11 | @implementation MyJSInterface 12 | 13 | - (void) test{ 14 | NSLog(@"test called"); 15 | } 16 | 17 | - (void) testWithParam: (NSString*) param{ 18 | NSLog(@"test with param: %@", param); 19 | } 20 | 21 | - (void) testWithTwoParam: (NSString*) param AndParam2: (NSString*) param2{ 22 | NSLog(@"test with param: %@ and param2: %@", param, param2); 23 | } 24 | 25 | - (void) testWithFuncParam: (EasyJSDataFunction*) param{ 26 | NSLog(@"test with func"); 27 | 28 | param.removeAfterExecute = YES; 29 | NSString* ret = [param executeWithParam:@"blabla:\"bla"]; 30 | 31 | NSLog(@"Return value from callback: %@", ret); 32 | } 33 | 34 | - (void) testWithFuncParam2: (EasyJSDataFunction*) param{ 35 | NSLog(@"test with func 2 but not removing callback after invocation"); 36 | 37 | param.removeAfterExecute = NO; 38 | [param executeWithParam:@"data 1"]; 39 | [param executeWithParam:@"data 2"]; 40 | } 41 | 42 | - (NSString*) testWithRet{ 43 | NSString* ret = @"js"; 44 | return ret; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EasyJSWebView.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (nonatomic, retain) IBOutlet EasyJSWebView* myWebView; 15 | 16 | - (void) testDealloc; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "MyJSInterface.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view, typically from a nib. 22 | 23 | MyJSInterface* interface = [MyJSInterface new]; 24 | [self.myWebView addJavascriptInterfaces:interface WithName:@"MyJSTest"]; 25 | [interface release]; 26 | 27 | [self.myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"test" ofType:@"html"]isDirectory:NO]]]; 28 | 29 | //[self performSelector:@selector(testDealloc) withObject:self afterDelay:40]; 30 | } 31 | 32 | - (void) testDealloc{ 33 | [self.myWebView removeFromSuperview]; 34 | } 35 | 36 | - (void)didReceiveMemoryWarning 37 | { 38 | [super didReceiveMemoryWarning]; 39 | // Dispose of any resources that can be recreated. 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/en.lproj/ViewController_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1536 5 | 11G63 6 | 2844 7 | 1138.51 8 | 569.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1930 12 | 13 | 14 | IBProxyObject 15 | IBUIView 16 | IBUIWebView 17 | 18 | 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | PluginDependencyRecalculationVersion 23 | 24 | 25 | 26 | 27 | IBFilesOwner 28 | IBCocoaTouchFramework 29 | 30 | 31 | IBFirstResponder 32 | IBCocoaTouchFramework 33 | 34 | 35 | 36 | 274 37 | 38 | 39 | 40 | 274 41 | {320, 548} 42 | 43 | 44 | _NS:9 45 | 46 | 1 47 | MSAxIDEAA 48 | 49 | IBCocoaTouchFramework 50 | 1 51 | YES 52 | 53 | 54 | {{0, 20}, {320, 548}} 55 | 56 | 57 | 58 | 3 59 | MC43NQA 60 | 61 | 2 62 | 63 | 64 | NO 65 | 66 | 67 | IBUIScreenMetrics 68 | 69 | YES 70 | 71 | 72 | 73 | 74 | 75 | {320, 568} 76 | {568, 320} 77 | 78 | 79 | IBCocoaTouchFramework 80 | Retina 4 Full Screen 81 | 2 82 | 83 | IBCocoaTouchFramework 84 | 85 | 86 | 87 | 88 | 89 | 90 | view 91 | 92 | 93 | 94 | 7 95 | 96 | 97 | 98 | myWebView 99 | 100 | 101 | 102 | 13 103 | 104 | 105 | 106 | 107 | 108 | 0 109 | 110 | 111 | 112 | 113 | 114 | -1 115 | 116 | 117 | File's Owner 118 | 119 | 120 | -2 121 | 122 | 123 | 124 | 125 | 6 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 8 134 | 135 | 136 | 137 | 138 | 139 | 140 | ViewController 141 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 142 | UIResponder 143 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 144 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 145 | EasyJSWebView 146 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 147 | 148 | 149 | 150 | 151 | 152 | 13 153 | 154 | 155 | 156 | 157 | EasyJSWebView 158 | UIWebView 159 | 160 | IBProjectSource 161 | ./Classes/EasyJSWebView.h 162 | 163 | 164 | 165 | ViewController 166 | UIViewController 167 | 168 | myWebView 169 | EasyJSWebView 170 | 171 | 172 | myWebView 173 | 174 | myWebView 175 | EasyJSWebView 176 | 177 | 178 | 179 | IBProjectSource 180 | ./Classes/ViewController.h 181 | 182 | 183 | 184 | 185 | 0 186 | IBCocoaTouchFramework 187 | YES 188 | 3 189 | 1930 190 | 191 | 192 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // EasyJSWebViewSample 4 | // 5 | // Created by Lau Alex on 19/1/13. 6 | // Copyright (c) 2013 Dukeland. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /EasyJSWebViewSample/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | Easy JS Hello World 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EasyJSWebViewSample - a sample project of EasyJSWebView 2 | =================== 3 | 4 | You are using UIWebView in your iOS app and you want to do some communications between the Javascript inside the WebView and Objective-C. How would you do it? 5 | 6 | To run Javascript in Objective-C, you can use the **– stringByEvaluatingJavaScriptFromString:** method. To run Objective-C method, well it is a little bit tricky, you need to implement the **UIWebViewDelegate** and the **shouldStartLoadWithRequest** method. 7 | 8 | Do you know how to do this in Android? You simply need to create a class and pass an instance to the WebView through **addJavascriptInterface(Object object, String name)**. 9 | 10 | EasyJSWebView is a library that allows you to do the same in Objective-C. Download it and try. **I promise. It is much simpler to do the job!!!** 11 | 12 | You may find the library [here](https://github.com/dukeland/EasyJSWebView). 13 | 14 | ###Some code to demonstrate 15 | So basically what you need to do is create a class like this. 16 | 17 | ```obj-c 18 | @interface MyJSInterface : NSObject 19 | 20 | - (void) test; 21 | - (void) testWithParam: (NSString*) param; 22 | - (void) testWithTwoParam: (NSString*) param AndParam2: (NSString*) param2; 23 | 24 | - (NSString*) testWithRet; 25 | 26 | @end 27 | ``` 28 | 29 | Then add the interface to your UIWebView. 30 | 31 | ```obj-c 32 | MyJSInterface* interface = [MyJSInterface new]; 33 | [self.myWebView addJavascriptInterfaces:interface WithName:@"MyJSTest"]; 34 | [interface release]; 35 | ``` 36 | In Javascript, you can call the Objective-C methods by this simple code. 37 | 38 | ```js 39 | MyJSTest.test(); 40 | MyJSTest.testWithParam("ha:ha"); 41 | MyJSTest.testWithTwoParamAndParam2("haha1", "haha2"); 42 | 43 | var str = MyJSTest.testWithRet(); 44 | ``` 45 | 46 | Just that simple!!! EasyJSWebView will help you do the injection. And you do not even need to use async-style writing to get the return value!!! 47 | 48 | But of course, sometimes we may need to use the async-style code. It is also supported. You can even get the return value from the callback function. 49 | 50 | ```obj-c 51 | - (void) testWithFuncParam: (EasyJSDataFunction*) param{ 52 | NSLog(@"test with func"); 53 | 54 | NSString* ret = [param executeWithParam:@"blabla:\"bla"]; 55 | 56 | NSLog(@"Return value from callback: %@", ret); 57 | } 58 | ``` 59 | 60 | And in Javascript, 61 | 62 | ```js 63 | MyJSTest.testWithFuncParam(function (data){ 64 | alert(data); //data would be blabla:"bla 65 | return "some data"; 66 | }); 67 | ``` 68 | 69 | Simple, huh!? 70 | 71 | **Try it now!!!** 72 | 73 | ###Some simple facts 74 | * NSInvocation does not live peacefully with ARC. This library is thus a non-ARC library. 75 | * It supports only NSString* for message passing now. 76 | * We are Dukeland from Hong Kong! A group of IT-holic guys 77 | --------------------------------------------------------------------------------