diff --git a/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 39fe931..0000000 Binary files a/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.pbxproj b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.pbxproj new file mode 100644 index 0000000..58df434 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.pbxproj @@ -0,0 +1,581 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B95413251D9BB9B600600D09 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413241D9BB9B600600D09 /* main.m */; }; + B95413281D9BB9B600600D09 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413271D9BB9B600600D09 /* AppDelegate.m */; }; + B954132B1D9BB9B600600D09 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B954132A1D9BB9B600600D09 /* ViewController.m */; }; + B954132E1D9BB9B600600D09 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B954132C1D9BB9B600600D09 /* Main.storyboard */; }; + B95413301D9BB9B600600D09 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B954132F1D9BB9B600600D09 /* Assets.xcassets */; }; + B95413331D9BB9B600600D09 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B95413311D9BB9B600600D09 /* LaunchScreen.storyboard */; }; + B95413791D9BBA5200600D09 /* CDVJSON_private.m in Sources */ = {isa = PBXBuildFile; fileRef = B954133E1D9BBA5200600D09 /* CDVJSON_private.m */; }; + B954137A1D9BBA5200600D09 /* CDVGestureHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413431D9BBA5200600D09 /* CDVGestureHandler.m */; }; + B954137B1D9BBA5200600D09 /* CDVHandleOpenURL.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413461D9BBA5200600D09 /* CDVHandleOpenURL.m */; }; + B954137C1D9BBA5200600D09 /* CDVIntentAndNavigationFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413491D9BBA5200600D09 /* CDVIntentAndNavigationFilter.m */; }; + B954137D1D9BBA5200600D09 /* CDVLocalStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = B954134C1D9BBA5200600D09 /* CDVLocalStorage.m */; }; + B954137E1D9BBA5200600D09 /* CDVUIWebViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B954134F1D9BBA5200600D09 /* CDVUIWebViewDelegate.m */; }; + B954137F1D9BBA5200600D09 /* CDVUIWebViewEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413511D9BBA5200600D09 /* CDVUIWebViewEngine.m */; }; + B95413801D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413531D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.m */; }; + B95413811D9BBA5200600D09 /* CDVAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413571D9BBA5200600D09 /* CDVAppDelegate.m */; }; + B95413821D9BBA5200600D09 /* CDVCommandDelegateImpl.m in Sources */ = {isa = PBXBuildFile; fileRef = B954135C1D9BBA5200600D09 /* CDVCommandDelegateImpl.m */; }; + B95413831D9BBA5200600D09 /* CDVCommandQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = B954135E1D9BBA5200600D09 /* CDVCommandQueue.m */; }; + B95413841D9BBA5200600D09 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413601D9BBA5200600D09 /* CDVConfigParser.m */; }; + B95413851D9BBA5200600D09 /* CDVInvokedUrlCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413621D9BBA5200600D09 /* CDVInvokedUrlCommand.m */; }; + B95413861D9BBA5200600D09 /* CDVPlugin+Resources.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413641D9BBA5200600D09 /* CDVPlugin+Resources.m */; }; + B95413871D9BBA5200600D09 /* CDVPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413661D9BBA5200600D09 /* CDVPlugin.m */; }; + B95413881D9BBA5200600D09 /* CDVPluginResult.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413681D9BBA5200600D09 /* CDVPluginResult.m */; }; + B95413891D9BBA5200600D09 /* CDVTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = B954136B1D9BBA5200600D09 /* CDVTimer.m */; }; + B954138A1D9BBA5200600D09 /* CDVURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = B954136D1D9BBA5200600D09 /* CDVURLProtocol.m */; }; + B954138B1D9BBA5200600D09 /* CDVUserAgentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B954136F1D9BBA5200600D09 /* CDVUserAgentUtil.m */; }; + B954138C1D9BBA5200600D09 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413711D9BBA5200600D09 /* CDVViewController.m */; }; + B954138D1D9BBA5200600D09 /* CDVWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413741D9BBA5200600D09 /* CDVWhitelist.m */; }; + B954138E1D9BBA5200600D09 /* NSDictionary+CordovaPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413761D9BBA5200600D09 /* NSDictionary+CordovaPreferences.m */; }; + B954138F1D9BBA5200600D09 /* NSMutableArray+QueueAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = B95413781D9BBA5200600D09 /* NSMutableArray+QueueAdditions.m */; }; + B95413931D9BC21A00600D09 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = B95413921D9BC21A00600D09 /* config.xml */; }; + B95413951D9BCC0900600D09 /* www in Resources */ = {isa = PBXBuildFile; fileRef = B95413941D9BCC0900600D09 /* www */; }; + B954139B1D9CA7EB00600D09 /* HaleyPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = B954139A1D9CA7EB00600D09 /* HaleyPlugin.m */; }; + B954139F1D9CA86400600D09 /* HLAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = B954139D1D9CA86400600D09 /* HLAudioPlayer.m */; }; + B95413A01D9CA86400600D09 /* shake_sound_male.wav in Resources */ = {isa = PBXBuildFile; fileRef = B954139E1D9CA86400600D09 /* shake_sound_male.wav */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B95413201D9BB9B600600D09 /* JS_OC_Cordova.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JS_OC_Cordova.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B95413241D9BB9B600600D09 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B95413261D9BB9B600600D09 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B95413271D9BB9B600600D09 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B95413291D9BB9B600600D09 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; + B954132A1D9BB9B600600D09 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + B954132D1D9BB9B600600D09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B954132F1D9BB9B600600D09 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B95413321D9BB9B600600D09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B95413341D9BB9B600600D09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B954133C1D9BBA5200600D09 /* CDVDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVDebug.h; sourceTree = ""; }; + B954133D1D9BBA5200600D09 /* CDVJSON_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVJSON_private.h; sourceTree = ""; }; + B954133E1D9BBA5200600D09 /* CDVJSON_private.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVJSON_private.m; sourceTree = ""; }; + B954133F1D9BBA5200600D09 /* CDVPlugin+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CDVPlugin+Private.h"; sourceTree = ""; }; + B95413421D9BBA5200600D09 /* CDVGestureHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVGestureHandler.h; sourceTree = ""; }; + B95413431D9BBA5200600D09 /* CDVGestureHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVGestureHandler.m; sourceTree = ""; }; + B95413451D9BBA5200600D09 /* CDVHandleOpenURL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVHandleOpenURL.h; sourceTree = ""; }; + B95413461D9BBA5200600D09 /* CDVHandleOpenURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVHandleOpenURL.m; sourceTree = ""; }; + B95413481D9BBA5200600D09 /* CDVIntentAndNavigationFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVIntentAndNavigationFilter.h; sourceTree = ""; }; + B95413491D9BBA5200600D09 /* CDVIntentAndNavigationFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVIntentAndNavigationFilter.m; sourceTree = ""; }; + B954134B1D9BBA5200600D09 /* CDVLocalStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVLocalStorage.h; sourceTree = ""; }; + B954134C1D9BBA5200600D09 /* CDVLocalStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVLocalStorage.m; sourceTree = ""; }; + B954134E1D9BBA5200600D09 /* CDVUIWebViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVUIWebViewDelegate.h; sourceTree = ""; }; + B954134F1D9BBA5200600D09 /* CDVUIWebViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUIWebViewDelegate.m; sourceTree = ""; }; + B95413501D9BBA5200600D09 /* CDVUIWebViewEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVUIWebViewEngine.h; sourceTree = ""; }; + B95413511D9BBA5200600D09 /* CDVUIWebViewEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUIWebViewEngine.m; sourceTree = ""; }; + B95413521D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVUIWebViewNavigationDelegate.h; sourceTree = ""; }; + B95413531D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUIWebViewNavigationDelegate.m; sourceTree = ""; }; + B95413551D9BBA5200600D09 /* CDV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDV.h; sourceTree = ""; }; + B95413561D9BBA5200600D09 /* CDVAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAppDelegate.h; sourceTree = ""; }; + B95413571D9BBA5200600D09 /* CDVAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVAppDelegate.m; sourceTree = ""; }; + B95413581D9BBA5200600D09 /* CDVAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAvailability.h; sourceTree = ""; }; + B95413591D9BBA5200600D09 /* CDVAvailabilityDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVAvailabilityDeprecated.h; sourceTree = ""; }; + B954135A1D9BBA5200600D09 /* CDVCommandDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegate.h; sourceTree = ""; }; + B954135B1D9BBA5200600D09 /* CDVCommandDelegateImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandDelegateImpl.h; sourceTree = ""; }; + B954135C1D9BBA5200600D09 /* CDVCommandDelegateImpl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCommandDelegateImpl.m; sourceTree = ""; }; + B954135D1D9BBA5200600D09 /* CDVCommandQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCommandQueue.h; sourceTree = ""; }; + B954135E1D9BBA5200600D09 /* CDVCommandQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCommandQueue.m; sourceTree = ""; }; + B954135F1D9BBA5200600D09 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVConfigParser.h; sourceTree = ""; }; + B95413601D9BBA5200600D09 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVConfigParser.m; sourceTree = ""; }; + B95413611D9BBA5200600D09 /* CDVInvokedUrlCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVInvokedUrlCommand.h; sourceTree = ""; }; + B95413621D9BBA5200600D09 /* CDVInvokedUrlCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommand.m; sourceTree = ""; }; + B95413631D9BBA5200600D09 /* CDVPlugin+Resources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CDVPlugin+Resources.h"; sourceTree = ""; }; + B95413641D9BBA5200600D09 /* CDVPlugin+Resources.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CDVPlugin+Resources.m"; sourceTree = ""; }; + B95413651D9BBA5200600D09 /* CDVPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPlugin.h; sourceTree = ""; }; + B95413661D9BBA5200600D09 /* CDVPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPlugin.m; sourceTree = ""; }; + B95413671D9BBA5200600D09 /* CDVPluginResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVPluginResult.h; sourceTree = ""; }; + B95413681D9BBA5200600D09 /* CDVPluginResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVPluginResult.m; sourceTree = ""; }; + B95413691D9BBA5200600D09 /* CDVScreenOrientationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVScreenOrientationDelegate.h; sourceTree = ""; }; + B954136A1D9BBA5200600D09 /* CDVTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVTimer.h; sourceTree = ""; }; + B954136B1D9BBA5200600D09 /* CDVTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVTimer.m; sourceTree = ""; }; + B954136C1D9BBA5200600D09 /* CDVURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVURLProtocol.h; sourceTree = ""; }; + B954136D1D9BBA5200600D09 /* CDVURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVURLProtocol.m; sourceTree = ""; }; + B954136E1D9BBA5200600D09 /* CDVUserAgentUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVUserAgentUtil.h; sourceTree = ""; }; + B954136F1D9BBA5200600D09 /* CDVUserAgentUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUserAgentUtil.m; sourceTree = ""; }; + B95413701D9BBA5200600D09 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVViewController.h; sourceTree = ""; }; + B95413711D9BBA5200600D09 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVViewController.m; sourceTree = ""; }; + B95413721D9BBA5200600D09 /* CDVWebViewEngineProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWebViewEngineProtocol.h; sourceTree = ""; }; + B95413731D9BBA5200600D09 /* CDVWhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVWhitelist.h; sourceTree = ""; }; + B95413741D9BBA5200600D09 /* CDVWhitelist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVWhitelist.m; sourceTree = ""; }; + B95413751D9BBA5200600D09 /* NSDictionary+CordovaPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+CordovaPreferences.h"; sourceTree = ""; }; + B95413761D9BBA5200600D09 /* NSDictionary+CordovaPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+CordovaPreferences.m"; sourceTree = ""; }; + B95413771D9BBA5200600D09 /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+QueueAdditions.h"; sourceTree = ""; }; + B95413781D9BBA5200600D09 /* NSMutableArray+QueueAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+QueueAdditions.m"; sourceTree = ""; }; + B95413901D9BBCC100600D09 /* PrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrefixHeader.pch; sourceTree = ""; }; + B95413921D9BC21A00600D09 /* config.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = config.xml; sourceTree = ""; }; + B95413941D9BCC0900600D09 /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = ""; }; + B95413991D9CA7EB00600D09 /* HaleyPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HaleyPlugin.h; sourceTree = ""; }; + B954139A1D9CA7EB00600D09 /* HaleyPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HaleyPlugin.m; sourceTree = ""; }; + B954139C1D9CA86400600D09 /* HLAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAudioPlayer.h; sourceTree = ""; }; + B954139D1D9CA86400600D09 /* HLAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLAudioPlayer.m; sourceTree = ""; }; + B954139E1D9CA86400600D09 /* shake_sound_male.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = shake_sound_male.wav; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B954131D1D9BB9B600600D09 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B95413171D9BB9B600600D09 = { + isa = PBXGroup; + children = ( + B95413221D9BB9B600600D09 /* JS_OC_Cordova */, + B95413211D9BB9B600600D09 /* Products */, + ); + sourceTree = ""; + }; + B95413211D9BB9B600600D09 /* Products */ = { + isa = PBXGroup; + children = ( + B95413201D9BB9B600600D09 /* JS_OC_Cordova.app */, + ); + name = Products; + sourceTree = ""; + }; + B95413221D9BB9B600600D09 /* JS_OC_Cordova */ = { + isa = PBXGroup; + children = ( + B954133A1D9BBA5200600D09 /* CordovaLib */, + B95413981D9CA7EB00600D09 /* Plugins */, + B95413261D9BB9B600600D09 /* AppDelegate.h */, + B95413271D9BB9B600600D09 /* AppDelegate.m */, + B95413291D9BB9B600600D09 /* ViewController.h */, + B954132A1D9BB9B600600D09 /* ViewController.m */, + B954139C1D9CA86400600D09 /* HLAudioPlayer.h */, + B954139D1D9CA86400600D09 /* HLAudioPlayer.m */, + B954139E1D9CA86400600D09 /* shake_sound_male.wav */, + B95413941D9BCC0900600D09 /* www */, + B95413231D9BB9B600600D09 /* Supporting Files */, + ); + path = JS_OC_Cordova; + sourceTree = ""; + }; + B95413231D9BB9B600600D09 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B954132C1D9BB9B600600D09 /* Main.storyboard */, + B954132F1D9BB9B600600D09 /* Assets.xcassets */, + B95413311D9BB9B600600D09 /* LaunchScreen.storyboard */, + B95413341D9BB9B600600D09 /* Info.plist */, + B95413241D9BB9B600600D09 /* main.m */, + B95413901D9BBCC100600D09 /* PrefixHeader.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B954133A1D9BBA5200600D09 /* CordovaLib */ = { + isa = PBXGroup; + children = ( + B95413921D9BC21A00600D09 /* config.xml */, + B954133B1D9BBA5200600D09 /* Private */, + B95413541D9BBA5200600D09 /* Public */, + ); + path = CordovaLib; + sourceTree = ""; + }; + B954133B1D9BBA5200600D09 /* Private */ = { + isa = PBXGroup; + children = ( + B954133C1D9BBA5200600D09 /* CDVDebug.h */, + B954133D1D9BBA5200600D09 /* CDVJSON_private.h */, + B954133E1D9BBA5200600D09 /* CDVJSON_private.m */, + B954133F1D9BBA5200600D09 /* CDVPlugin+Private.h */, + B95413401D9BBA5200600D09 /* Plugins */, + ); + path = Private; + sourceTree = ""; + }; + B95413401D9BBA5200600D09 /* Plugins */ = { + isa = PBXGroup; + children = ( + B95413411D9BBA5200600D09 /* CDVGestureHandler */, + B95413441D9BBA5200600D09 /* CDVHandleOpenURL */, + B95413471D9BBA5200600D09 /* CDVIntentAndNavigationFilter */, + B954134A1D9BBA5200600D09 /* CDVLocalStorage */, + B954134D1D9BBA5200600D09 /* CDVUIWebViewEngine */, + ); + path = Plugins; + sourceTree = ""; + }; + B95413411D9BBA5200600D09 /* CDVGestureHandler */ = { + isa = PBXGroup; + children = ( + B95413421D9BBA5200600D09 /* CDVGestureHandler.h */, + B95413431D9BBA5200600D09 /* CDVGestureHandler.m */, + ); + path = CDVGestureHandler; + sourceTree = ""; + }; + B95413441D9BBA5200600D09 /* CDVHandleOpenURL */ = { + isa = PBXGroup; + children = ( + B95413451D9BBA5200600D09 /* CDVHandleOpenURL.h */, + B95413461D9BBA5200600D09 /* CDVHandleOpenURL.m */, + ); + path = CDVHandleOpenURL; + sourceTree = ""; + }; + B95413471D9BBA5200600D09 /* CDVIntentAndNavigationFilter */ = { + isa = PBXGroup; + children = ( + B95413481D9BBA5200600D09 /* CDVIntentAndNavigationFilter.h */, + B95413491D9BBA5200600D09 /* CDVIntentAndNavigationFilter.m */, + ); + path = CDVIntentAndNavigationFilter; + sourceTree = ""; + }; + B954134A1D9BBA5200600D09 /* CDVLocalStorage */ = { + isa = PBXGroup; + children = ( + B954134B1D9BBA5200600D09 /* CDVLocalStorage.h */, + B954134C1D9BBA5200600D09 /* CDVLocalStorage.m */, + ); + path = CDVLocalStorage; + sourceTree = ""; + }; + B954134D1D9BBA5200600D09 /* CDVUIWebViewEngine */ = { + isa = PBXGroup; + children = ( + B954134E1D9BBA5200600D09 /* CDVUIWebViewDelegate.h */, + B954134F1D9BBA5200600D09 /* CDVUIWebViewDelegate.m */, + B95413501D9BBA5200600D09 /* CDVUIWebViewEngine.h */, + B95413511D9BBA5200600D09 /* CDVUIWebViewEngine.m */, + B95413521D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.h */, + B95413531D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.m */, + ); + path = CDVUIWebViewEngine; + sourceTree = ""; + }; + B95413541D9BBA5200600D09 /* Public */ = { + isa = PBXGroup; + children = ( + B95413551D9BBA5200600D09 /* CDV.h */, + B95413561D9BBA5200600D09 /* CDVAppDelegate.h */, + B95413571D9BBA5200600D09 /* CDVAppDelegate.m */, + B95413581D9BBA5200600D09 /* CDVAvailability.h */, + B95413591D9BBA5200600D09 /* CDVAvailabilityDeprecated.h */, + B954135A1D9BBA5200600D09 /* CDVCommandDelegate.h */, + B954135B1D9BBA5200600D09 /* CDVCommandDelegateImpl.h */, + B954135C1D9BBA5200600D09 /* CDVCommandDelegateImpl.m */, + B954135D1D9BBA5200600D09 /* CDVCommandQueue.h */, + B954135E1D9BBA5200600D09 /* CDVCommandQueue.m */, + B954135F1D9BBA5200600D09 /* CDVConfigParser.h */, + B95413601D9BBA5200600D09 /* CDVConfigParser.m */, + B95413611D9BBA5200600D09 /* CDVInvokedUrlCommand.h */, + B95413621D9BBA5200600D09 /* CDVInvokedUrlCommand.m */, + B95413631D9BBA5200600D09 /* CDVPlugin+Resources.h */, + B95413641D9BBA5200600D09 /* CDVPlugin+Resources.m */, + B95413651D9BBA5200600D09 /* CDVPlugin.h */, + B95413661D9BBA5200600D09 /* CDVPlugin.m */, + B95413671D9BBA5200600D09 /* CDVPluginResult.h */, + B95413681D9BBA5200600D09 /* CDVPluginResult.m */, + B95413691D9BBA5200600D09 /* CDVScreenOrientationDelegate.h */, + B954136A1D9BBA5200600D09 /* CDVTimer.h */, + B954136B1D9BBA5200600D09 /* CDVTimer.m */, + B954136C1D9BBA5200600D09 /* CDVURLProtocol.h */, + B954136D1D9BBA5200600D09 /* CDVURLProtocol.m */, + B954136E1D9BBA5200600D09 /* CDVUserAgentUtil.h */, + B954136F1D9BBA5200600D09 /* CDVUserAgentUtil.m */, + B95413701D9BBA5200600D09 /* CDVViewController.h */, + B95413711D9BBA5200600D09 /* CDVViewController.m */, + B95413721D9BBA5200600D09 /* CDVWebViewEngineProtocol.h */, + B95413731D9BBA5200600D09 /* CDVWhitelist.h */, + B95413741D9BBA5200600D09 /* CDVWhitelist.m */, + B95413751D9BBA5200600D09 /* NSDictionary+CordovaPreferences.h */, + B95413761D9BBA5200600D09 /* NSDictionary+CordovaPreferences.m */, + B95413771D9BBA5200600D09 /* NSMutableArray+QueueAdditions.h */, + B95413781D9BBA5200600D09 /* NSMutableArray+QueueAdditions.m */, + ); + path = Public; + sourceTree = ""; + }; + B95413981D9CA7EB00600D09 /* Plugins */ = { + isa = PBXGroup; + children = ( + B95413991D9CA7EB00600D09 /* HaleyPlugin.h */, + B954139A1D9CA7EB00600D09 /* HaleyPlugin.m */, + ); + path = Plugins; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B954131F1D9BB9B600600D09 /* JS_OC_Cordova */ = { + isa = PBXNativeTarget; + buildConfigurationList = B95413371D9BB9B600600D09 /* Build configuration list for PBXNativeTarget "JS_OC_Cordova" */; + buildPhases = ( + B954131C1D9BB9B600600D09 /* Sources */, + B954131D1D9BB9B600600D09 /* Frameworks */, + B954131E1D9BB9B600600D09 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JS_OC_Cordova; + productName = JS_OC_Cordova; + productReference = B95413201D9BB9B600600D09 /* JS_OC_Cordova.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B95413181D9BB9B600600D09 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0800; + ORGANIZATIONNAME = Haley; + TargetAttributes = { + B954131F1D9BB9B600600D09 = { + CreatedOnToolsVersion = 8.0; + DevelopmentTeam = 456T9KL6YP; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = B954131B1D9BB9B600600D09 /* Build configuration list for PBXProject "JS_OC_Cordova" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B95413171D9BB9B600600D09; + productRefGroup = B95413211D9BB9B600600D09 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B954131F1D9BB9B600600D09 /* JS_OC_Cordova */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B954131E1D9BB9B600600D09 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B95413331D9BB9B600600D09 /* LaunchScreen.storyboard in Resources */, + B95413301D9BB9B600600D09 /* Assets.xcassets in Resources */, + B954132E1D9BB9B600600D09 /* Main.storyboard in Resources */, + B95413951D9BCC0900600D09 /* www in Resources */, + B95413A01D9CA86400600D09 /* shake_sound_male.wav in Resources */, + B95413931D9BC21A00600D09 /* config.xml in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B954131C1D9BB9B600600D09 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B95413861D9BBA5200600D09 /* CDVPlugin+Resources.m in Sources */, + B954138F1D9BBA5200600D09 /* NSMutableArray+QueueAdditions.m in Sources */, + B95413851D9BBA5200600D09 /* CDVInvokedUrlCommand.m in Sources */, + B95413811D9BBA5200600D09 /* CDVAppDelegate.m in Sources */, + B95413891D9BBA5200600D09 /* CDVTimer.m in Sources */, + B954132B1D9BB9B600600D09 /* ViewController.m in Sources */, + B954137D1D9BBA5200600D09 /* CDVLocalStorage.m in Sources */, + B954137A1D9BBA5200600D09 /* CDVGestureHandler.m in Sources */, + B954137F1D9BBA5200600D09 /* CDVUIWebViewEngine.m in Sources */, + B95413881D9BBA5200600D09 /* CDVPluginResult.m in Sources */, + B954139B1D9CA7EB00600D09 /* HaleyPlugin.m in Sources */, + B95413791D9BBA5200600D09 /* CDVJSON_private.m in Sources */, + B954137C1D9BBA5200600D09 /* CDVIntentAndNavigationFilter.m in Sources */, + B954138D1D9BBA5200600D09 /* CDVWhitelist.m in Sources */, + B954138E1D9BBA5200600D09 /* NSDictionary+CordovaPreferences.m in Sources */, + B954138A1D9BBA5200600D09 /* CDVURLProtocol.m in Sources */, + B954137E1D9BBA5200600D09 /* CDVUIWebViewDelegate.m in Sources */, + B954139F1D9CA86400600D09 /* HLAudioPlayer.m in Sources */, + B954138C1D9BBA5200600D09 /* CDVViewController.m in Sources */, + B954137B1D9BBA5200600D09 /* CDVHandleOpenURL.m in Sources */, + B95413281D9BB9B600600D09 /* AppDelegate.m in Sources */, + B95413801D9BBA5200600D09 /* CDVUIWebViewNavigationDelegate.m in Sources */, + B95413821D9BBA5200600D09 /* CDVCommandDelegateImpl.m in Sources */, + B95413251D9BB9B600600D09 /* main.m in Sources */, + B95413841D9BBA5200600D09 /* CDVConfigParser.m in Sources */, + B95413871D9BBA5200600D09 /* CDVPlugin.m in Sources */, + B954138B1D9BBA5200600D09 /* CDVUserAgentUtil.m in Sources */, + B95413831D9BBA5200600D09 /* CDVCommandQueue.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B954132C1D9BB9B600600D09 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B954132D1D9BB9B600600D09 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B95413311D9BB9B600600D09 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B95413321D9BB9B600600D09 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B95413351D9BB9B600600D09 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B95413361D9BB9B600600D09 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B95413381D9BB9B600600D09 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 456T9KL6YP; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = JS_OC_Cordova/PrefixHeader.pch; + INFOPLIST_FILE = JS_OC_Cordova/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.haley.JS-OC-Cordova"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B95413391D9BB9B600600D09 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = 456T9KL6YP; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = JS_OC_Cordova/PrefixHeader.pch; + INFOPLIST_FILE = JS_OC_Cordova/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.haley.JS-OC-Cordova"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B954131B1D9BB9B600600D09 /* Build configuration list for PBXProject "JS_OC_Cordova" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B95413351D9BB9B600600D09 /* Debug */, + B95413361D9BB9B600600D09 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B95413371D9BB9B600600D09 /* Build configuration list for PBXNativeTarget "JS_OC_Cordova" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B95413381D9BB9B600600D09 /* Debug */, + B95413391D9BB9B600600D09 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = B95413181D9BB9B600600D09 /* Project object */; +} diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1a497bd --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..daac213 Binary files /dev/null and b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..7d06858 Binary files /dev/null and b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..c2af6ea --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JS_OC_Cordova.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..4b754cf --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_Cordova.xcscheme b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_Cordova.xcscheme new file mode 100644 index 0000000..0a0b024 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_Cordova.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..2c2498b --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JS_OC_Cordova.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B954131F1D9BB9B600600D09 + + primary + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.h new file mode 100644 index 0000000..7e8e766 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.m b/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.m new file mode 100644 index 0000000..f359448 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/AppDelegate.m @@ -0,0 +1,51 @@ +// +// AppDelegate.m +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + + +@end diff --git a/JS_OC/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_Cordova/JS_OC_Cordova/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from JS_OC/Assets.xcassets/AppIcon.appiconset/Contents.json rename to JS_OC_Cordova/JS_OC_Cordova/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/LaunchScreen.storyboard b/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/Main.storyboard b/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/Main.storyboard new file mode 100644 index 0000000..161ac6c --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/Base.lproj/Main.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVDebug.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVDebug.h new file mode 100755 index 0000000..4a0d9f9 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVDebug.h @@ -0,0 +1,25 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#ifdef DEBUG + #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) +#else + #define DLog(...) +#endif +#define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.h new file mode 100755 index 0000000..afb5cc6 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.h @@ -0,0 +1,31 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +@interface NSArray (CDVJSONSerializingPrivate) +- (NSString*)cdv_JSONString; +@end + +@interface NSDictionary (CDVJSONSerializingPrivate) +- (NSString*)cdv_JSONString; +@end + +@interface NSString (CDVJSONSerializingPrivate) +- (id)cdv_JSONObject; +- (id)cdv_JSONFragment; +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.m new file mode 100755 index 0000000..5385680 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVJSON_private.m @@ -0,0 +1,91 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVJSON_private.h" +#import + +@implementation NSArray (CDVJSONSerializingPrivate) + +- (NSString*)cdv_JSONString +{ + NSError* error = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self + options:0 + error:&error]; + + if (error != nil) { + NSLog(@"NSArray JSONString error: %@", [error localizedDescription]); + return nil; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } +} + +@end + +@implementation NSDictionary (CDVJSONSerializingPrivate) + +- (NSString*)cdv_JSONString +{ + NSError* error = nil; + NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self + options:NSJSONWritingPrettyPrinted + error:&error]; + + if (error != nil) { + NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]); + return nil; + } else { + return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } +} + +@end + +@implementation NSString (CDVJSONSerializingPrivate) + +- (id)cdv_JSONObject +{ + NSError* error = nil; + id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingMutableContainers + error:&error]; + + if (error != nil) { + NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); + } + + return object; +} + +- (id)cdv_JSONFragment +{ + NSError* error = nil; + id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding] + options:NSJSONReadingAllowFragments + error:&error]; + + if (error != nil) { + NSLog(@"NSString JSONObject error: %@", [error localizedDescription]); + } + + return object; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVPlugin+Private.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVPlugin+Private.h new file mode 100755 index 0000000..f88638c --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/CDVPlugin+Private.h @@ -0,0 +1,24 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +@interface CDVPlugin (Private) + +- (instancetype)initWithWebViewEngine:(id )theWebViewEngine; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h new file mode 100755 index 0000000..510b6eb --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.h @@ -0,0 +1,26 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPlugin.h" + +@interface CDVGestureHandler : CDVPlugin + +@property (nonatomic, strong) UILongPressGestureRecognizer* lpgr; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m new file mode 100755 index 0000000..242ac55 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVGestureHandler/CDVGestureHandler.m @@ -0,0 +1,74 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVGestureHandler.h" + +@implementation CDVGestureHandler + +- (void)pluginInitialize +{ + [self applyLongPressFix]; +} + +- (void)applyLongPressFix +{ + // You can't suppress 3D Touch and still have regular longpress, + // so if this is false, let's not consider the 3D Touch setting at all. + if (![self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] || + ![[self.commandDelegate.settings objectForKey:@"suppresseslongpressgesture"] boolValue]) { + return; + } + + self.lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGestures:)]; + self.lpgr.minimumPressDuration = 0.45f; + self.lpgr.allowableMovement = 100.0f; + + // 0.45 is ok for 'regular longpress', 0.05-0.08 is required for '3D Touch longpress', + // but since this will also kill onclick handlers (not ontouchend) it's optional. + if ([self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] && + [[self.commandDelegate.settings objectForKey:@"suppresses3dtouchgesture"] boolValue]) { + self.lpgr.minimumPressDuration = 0.05f; + } + + NSArray *views = self.webView.subviews; + if (views.count == 0) { + NSLog(@"No webview subviews found, not applying the longpress fix."); + return; + } + for (int i=0; i + ++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist; ++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue; ++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType; +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m new file mode 100755 index 0000000..bd3a5a8 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVIntentAndNavigationFilter/CDVIntentAndNavigationFilter.m @@ -0,0 +1,142 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVIntentAndNavigationFilter.h" +#import "CDV.h" + +@interface CDVIntentAndNavigationFilter () + +@property (nonatomic, readwrite) NSMutableArray* allowIntents; +@property (nonatomic, readwrite) NSMutableArray* allowNavigations; +@property (nonatomic, readwrite) CDVWhitelist* allowIntentsWhitelist; +@property (nonatomic, readwrite) CDVWhitelist* allowNavigationsWhitelist; + +@end + +@implementation CDVIntentAndNavigationFilter + +#pragma mark NSXMLParserDelegate + +- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict +{ + if ([elementName isEqualToString:@"allow-navigation"]) { + [self.allowNavigations addObject:attributeDict[@"href"]]; + } + if ([elementName isEqualToString:@"allow-intent"]) { + [self.allowIntents addObject:attributeDict[@"href"]]; + } +} + +- (void)parserDidStartDocument:(NSXMLParser*)parser +{ + // file: url are added by default + self.allowNavigations = [[NSMutableArray alloc] initWithArray:@[ @"file://" ]]; + // no intents are added by default + self.allowIntents = [[NSMutableArray alloc] init]; +} + +- (void)parserDidEndDocument:(NSXMLParser*)parser +{ + self.allowIntentsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowIntents]; + self.allowNavigationsWhitelist = [[CDVWhitelist alloc] initWithArray:self.allowNavigations]; +} + +- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError +{ + NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]); +} + +#pragma mark CDVPlugin + +- (void)pluginInitialize +{ + if ([self.viewController isKindOfClass:[CDVViewController class]]) { + [(CDVViewController*)self.viewController parseSettingsWithParser:self]; + } +} + ++ (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url intentsWhitelist:(CDVWhitelist*)intentsWhitelist navigationsWhitelist:(CDVWhitelist*)navigationsWhitelist +{ + // a URL can only allow-intent OR allow-navigation, if both are specified, + // only allow-navigation is allowed + + BOOL allowNavigationsPass = [navigationsWhitelist URLIsAllowed:url logFailure:NO]; + BOOL allowIntentPass = [intentsWhitelist URLIsAllowed:url logFailure:NO]; + + if (allowNavigationsPass && allowIntentPass) { + return CDVIntentAndNavigationFilterValueNavigationAllowed; + } else if (allowNavigationsPass) { + return CDVIntentAndNavigationFilterValueNavigationAllowed; + } else if (allowIntentPass) { + return CDVIntentAndNavigationFilterValueIntentAllowed; + } + + return CDVIntentAndNavigationFilterValueNoneAllowed; +} + +- (CDVIntentAndNavigationFilterValue) filterUrl:(NSURL*)url +{ + return [[self class] filterUrl:url intentsWhitelist:self.allowIntentsWhitelist navigationsWhitelist:self.allowNavigationsWhitelist]; +} + ++ (BOOL)shouldOpenURLRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + return (UIWebViewNavigationTypeLinkClicked == navigationType || + (UIWebViewNavigationTypeOther == navigationType && + [[request.mainDocumentURL absoluteString] isEqualToString:[request.URL absoluteString]] + ) + ); +} + ++ (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType filterValue:(CDVIntentAndNavigationFilterValue)filterValue +{ + NSString* allowIntents_whitelistRejectionFormatString = @"ERROR External navigation rejected - not set for url='%@'"; + NSString* allowNavigations_whitelistRejectionFormatString = @"ERROR Internal navigation rejected - not set for url='%@'"; + + NSURL* url = [request URL]; + + switch (filterValue) { + case CDVIntentAndNavigationFilterValueNavigationAllowed: + return YES; + case CDVIntentAndNavigationFilterValueIntentAllowed: + // only allow-intent if it's a UIWebViewNavigationTypeLinkClicked (anchor tag) OR + // it's a UIWebViewNavigationTypeOther, and it's an internal link + if ([[self class] shouldOpenURLRequest:request navigationType:navigationType]){ + [[UIApplication sharedApplication] openURL:url]; + } + + // consume the request (i.e. no error) if it wasn't handled above + return NO; + case CDVIntentAndNavigationFilterValueNoneAllowed: + // allow-navigation attempt failed for sure + NSLog(@"%@", [NSString stringWithFormat:allowNavigations_whitelistRejectionFormatString, [url absoluteString]]); + // anchor tag link means it was an allow-intent attempt that failed as well + if (UIWebViewNavigationTypeLinkClicked == navigationType) { + NSLog(@"%@", [NSString stringWithFormat:allowIntents_whitelistRejectionFormatString, [url absoluteString]]); + } + return NO; + } +} + +- (BOOL)shouldOverrideLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + return [[self class] shouldOverrideLoadWithRequest:request navigationType:navigationType filterValue:[self filterUrl:request.URL]]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h new file mode 100755 index 0000000..dec6ab3 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.h @@ -0,0 +1,50 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPlugin.h" + +#define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain" +#define kCDVLocalStorageFileOperationError 1 + +@interface CDVLocalStorage : CDVPlugin + +@property (nonatomic, readonly, strong) NSMutableArray* backupInfo; + +- (BOOL)shouldBackup; +- (BOOL)shouldRestore; +- (void)backup:(CDVInvokedUrlCommand*)command; +- (void)restore:(CDVInvokedUrlCommand*)command; + ++ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType; +// Visible for testing. ++ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict + bundlePath:(NSString*)bundlePath + fileManager:(NSFileManager*)fileManager; +@end + +@interface CDVBackupInfo : NSObject + +@property (nonatomic, copy) NSString* original; +@property (nonatomic, copy) NSString* backup; +@property (nonatomic, copy) NSString* label; + +- (BOOL)shouldBackup; +- (BOOL)shouldRestore; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m new file mode 100755 index 0000000..252dfaf --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVLocalStorage/CDVLocalStorage.m @@ -0,0 +1,487 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVLocalStorage.h" +#import "CDV.h" + +@interface CDVLocalStorage () + +@property (nonatomic, readwrite, strong) NSMutableArray* backupInfo; // array of CDVBackupInfo objects +@property (nonatomic, readwrite, weak) id webviewDelegate; + +@end + +@implementation CDVLocalStorage + +@synthesize backupInfo, webviewDelegate; + +- (void)pluginInitialize +{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive) + name:UIApplicationWillResignActiveNotification object:nil]; + BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[[@"BackupWebStorage" lowercaseString]]]; + + self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup]; +} + +#pragma mark - +#pragma mark Plugin interface methods + ++ (NSMutableArray*)createBackupInfoWithTargetDir:(NSString*)targetDir backupDir:(NSString*)backupDir targetDirNests:(BOOL)targetDirNests backupDirNests:(BOOL)backupDirNests rename:(BOOL)rename +{ + /* + This "helper" does so much work and has so many options it would probably be clearer to refactor the whole thing. + Basically, there are three database locations: + + 1. "Normal" dir -- LIB// + 2. "Caches" dir -- LIB/Caches/ + 3. "Backup" dir -- DOC/Backups/ + + And between these three, there are various migration paths, most of which only consider 2 of the 3, which is why this helper is based on 2 locations and has a notion of "direction". + */ + NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:3]; + + NSString* original; + NSString* backup; + CDVBackupInfo* backupItem; + + // ////////// LOCALSTORAGE + + original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"]; + backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; + backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")]; + + backupItem = [[CDVBackupInfo alloc] init]; + backupItem.backup = backup; + backupItem.original = original; + backupItem.label = @"localStorage database"; + + [backupInfo addObject:backupItem]; + + // ////////// WEBSQL MAIN DB + + original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"]; + backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; + backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")]; + + backupItem = [[CDVBackupInfo alloc] init]; + backupItem.backup = backup; + backupItem.original = original; + backupItem.label = @"websql main database"; + + [backupInfo addObject:backupItem]; + + // ////////// WEBSQL DATABASES + + original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"]; + backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")]; + backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")]; + + backupItem = [[CDVBackupInfo alloc] init]; + backupItem.backup = backup; + backupItem.original = original; + backupItem.label = @"websql databases"; + + [backupInfo addObject:backupItem]; + + return backupInfo; +} + ++ (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup +{ + // create backup info from backup folder to caches folder + NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"]; + NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"]; + + // create the backups folder, if needed + [[NSFileManager defaultManager] createDirectoryAtPath:backupsFolder withIntermediateDirectories:YES attributes:nil error:nil]; + + [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:backupsFolder] skip:!cloudBackup]; + + return [self createBackupInfoWithTargetDir:cacheFolder backupDir:backupsFolder targetDirNests:NO backupDirNests:NO rename:YES]; +} + ++ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL*)URL skip:(BOOL)skip +{ + NSError* error = nil; + BOOL success = [URL setResourceValue:[NSNumber numberWithBool:skip] forKey:NSURLIsExcludedFromBackupKey error:&error]; + + if (!success) { + NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error); + } + return success; +} + ++ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error +{ + NSFileManager* fileManager = [NSFileManager defaultManager]; + + if (![fileManager fileExistsAtPath:src]) { + NSString* errorString = [NSString stringWithFormat:@"%@ file does not exist.", src]; + if (error != NULL) { + (*error) = [NSError errorWithDomain:kCDVLocalStorageErrorDomain + code:kCDVLocalStorageFileOperationError + userInfo:[NSDictionary dictionaryWithObject:errorString + forKey:NSLocalizedDescriptionKey]]; + } + return NO; + } + + // generate unique filepath in temp directory + CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); + CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); + NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"]; + CFRelease(uuidString); + CFRelease(uuidRef); + + BOOL destExists = [fileManager fileExistsAtPath:dest]; + + // backup the dest + if (destExists && ![fileManager copyItemAtPath:dest toPath:tempBackup error:error]) { + return NO; + } + + // remove the dest + if (destExists && ![fileManager removeItemAtPath:dest error:error]) { + return NO; + } + + // create path to dest + if (!destExists && ![fileManager createDirectoryAtPath:[dest stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:error]) { + return NO; + } + + // copy src to dest + if ([fileManager copyItemAtPath:src toPath:dest error:error]) { + // success - cleanup - delete the backup to the dest + if ([fileManager fileExistsAtPath:tempBackup]) { + [fileManager removeItemAtPath:tempBackup error:error]; + } + return YES; + } else { + // failure - we restore the temp backup file to dest + [fileManager copyItemAtPath:tempBackup toPath:dest error:error]; + // cleanup - delete the backup to the dest + if ([fileManager fileExistsAtPath:tempBackup]) { + [fileManager removeItemAtPath:tempBackup error:error]; + } + return NO; + } +} + +- (BOOL)shouldBackup +{ + for (CDVBackupInfo* info in self.backupInfo) { + if ([info shouldBackup]) { + return YES; + } + } + + return NO; +} + +- (BOOL)shouldRestore +{ + for (CDVBackupInfo* info in self.backupInfo) { + if ([info shouldRestore]) { + return YES; + } + } + + return NO; +} + +/* copy from webkitDbLocation to persistentDbLocation */ +- (void)backup:(CDVInvokedUrlCommand*)command +{ + NSString* callbackId = command.callbackId; + + NSError* __autoreleasing error = nil; + CDVPluginResult* result = nil; + NSString* message = nil; + + for (CDVBackupInfo* info in self.backupInfo) { + if ([info shouldBackup]) { + [[self class] copyFrom:info.original to:info.backup error:&error]; + + if (callbackId) { + if (error == nil) { + message = [NSString stringWithFormat:@"Backed up: %@", info.label]; + NSLog(@"%@", message); + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; + [self.commandDelegate sendPluginResult:result callbackId:callbackId]; + } else { + message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) backup: %@", info.label, [error localizedDescription]]; + NSLog(@"%@", message); + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; + [self.commandDelegate sendPluginResult:result callbackId:callbackId]; + } + } + } + } +} + +/* copy from persistentDbLocation to webkitDbLocation */ +- (void)restore:(CDVInvokedUrlCommand*)command +{ + NSError* __autoreleasing error = nil; + CDVPluginResult* result = nil; + NSString* message = nil; + + for (CDVBackupInfo* info in self.backupInfo) { + if ([info shouldRestore]) { + [[self class] copyFrom:info.backup to:info.original error:&error]; + + if (error == nil) { + message = [NSString stringWithFormat:@"Restored: %@", info.label]; + NSLog(@"%@", message); + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:message]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + } else { + message = [NSString stringWithFormat:@"Error in CDVLocalStorage (%@) restore: %@", info.label, [error localizedDescription]]; + NSLog(@"%@", message); + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + } + } + } +} + ++ (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType +{ + [self __verifyAndFixDatabaseLocations]; + [self __restoreLegacyDatabaseLocationsWithBackupType:backupType]; +} + ++ (void)__verifyAndFixDatabaseLocations +{ + NSBundle* mainBundle = [NSBundle mainBundle]; + NSString* bundlePath = [[mainBundle bundlePath] stringByDeletingLastPathComponent]; + NSString* bundleIdentifier = [[mainBundle infoDictionary] objectForKey:@"CFBundleIdentifier"]; + NSString* appPlistPath = [bundlePath stringByAppendingPathComponent:[NSString stringWithFormat:@"Library/Preferences/%@.plist", bundleIdentifier]]; + + NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithContentsOfFile:appPlistPath]; + BOOL modified = [[self class] __verifyAndFixDatabaseLocationsWithAppPlistDict:appPlistDict + bundlePath:bundlePath + fileManager:[NSFileManager defaultManager]]; + + if (modified) { + BOOL ok = [appPlistDict writeToFile:appPlistPath atomically:YES]; + [[NSUserDefaults standardUserDefaults] synchronize]; + NSLog(@"Fix applied for database locations?: %@", ok ? @"YES" : @"NO"); + } +} + ++ (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict + bundlePath:(NSString*)bundlePath + fileManager:(NSFileManager*)fileManager +{ + NSString* libraryCaches = @"Library/Caches"; + NSString* libraryWebKit = @"Library/WebKit"; + + NSArray* keysToCheck = [NSArray arrayWithObjects: + @"WebKitLocalStorageDatabasePathPreferenceKey", + @"WebDatabaseDirectory", + nil]; + + BOOL dirty = NO; + + for (NSString* key in keysToCheck) { + NSString* value = [appPlistDict objectForKey:key]; + // verify key exists, and path is in app bundle, if not - fix + if ((value != nil) && ![value hasPrefix:bundlePath]) { + // the pathSuffix to use may be wrong - OTA upgrades from < 5.1 to 5.1 do keep the old path Library/WebKit, + // while Xcode synced ones do change the storage location to Library/Caches + NSString* newBundlePath = [bundlePath stringByAppendingPathComponent:libraryCaches]; + if (![fileManager fileExistsAtPath:newBundlePath]) { + newBundlePath = [bundlePath stringByAppendingPathComponent:libraryWebKit]; + } + [appPlistDict setValue:newBundlePath forKey:key]; + dirty = YES; + } + } + + return dirty; +} + ++ (void)__restoreLegacyDatabaseLocationsWithBackupType:(NSString*)backupType +{ + // on iOS 6, if you toggle between cloud/local backup, you must move database locations. Default upgrade from iOS5.1 to iOS6 is like a toggle from local to cloud. + NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; + + NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0]; + + if ([backupType isEqualToString:@"cloud"]) { +#ifdef DEBUG + NSLog(@"\n\nStarted backup to iCloud! Please be careful." + "\nYour application might be rejected by Apple if you store too much data." + "\nFor more information please read \"iOS Data Storage Guidelines\" at:" + "\nhttps://developer.apple.com/icloud/documentation/data-storage/" + "\nTo disable web storage backup to iCloud, set the BackupWebStorage preference to \"local\" in the Cordova config.xml file\n\n"); +#endif + // We would like to restore old backups/caches databases to the new destination (nested in lib folder) + [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appDocumentsFolder stringByAppendingPathComponent:@"Backups"] targetDirNests:YES backupDirNests:NO rename:YES]]; + [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:appLibraryFolder backupDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] targetDirNests:YES backupDirNests:NO rename:NO]]; + } else { + // For ios6 local backups we also want to restore from Backups dir -- but we don't need to do that here, since the plugin will do that itself. + [backupInfo addObjectsFromArray:[self createBackupInfoWithTargetDir:[appLibraryFolder stringByAppendingPathComponent:@"Caches"] backupDir:appLibraryFolder targetDirNests:NO backupDirNests:YES rename:NO]]; + } + + NSFileManager* manager = [NSFileManager defaultManager]; + + for (CDVBackupInfo* info in backupInfo) { + if ([manager fileExistsAtPath:info.backup]) { + if ([info shouldRestore]) { + NSLog(@"Restoring old webstorage backup. From: '%@' To: '%@'.", info.backup, info.original); + [self copyFrom:info.backup to:info.original error:nil]; + } + NSLog(@"Removing old webstorage backup: '%@'.", info.backup); + [manager removeItemAtPath:info.backup error:nil]; + } + } + + [[NSUserDefaults standardUserDefaults] setBool:[backupType isEqualToString:@"cloud"] forKey:@"WebKitStoreWebDataForBackup"]; +} + +#pragma mark - +#pragma mark Notification handlers + +- (void)onResignActive +{ + UIDevice* device = [UIDevice currentDevice]; + NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"]; + + BOOL isMultitaskingSupported = [device respondsToSelector:@selector(isMultitaskingSupported)] && [device isMultitaskingSupported]; + + if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default) + exitsOnSuspend = [NSNumber numberWithBool:NO]; + } + + if (exitsOnSuspend) { + [self backup:nil]; + } else if (isMultitaskingSupported) { + __block UIBackgroundTaskIdentifier backgroundTaskID = UIBackgroundTaskInvalid; + + backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; + backgroundTaskID = UIBackgroundTaskInvalid; + NSLog(@"Background task to backup WebSQL/LocalStorage expired."); + }]; + CDVLocalStorage __weak* weakSelf = self; + [self.commandDelegate runInBackground:^{ + [weakSelf backup:nil]; + + [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID]; + backgroundTaskID = UIBackgroundTaskInvalid; + }]; + } +} + +- (void)onAppTerminate +{ + [self onResignActive]; +} + +- (void)onReset +{ + [self restore:nil]; +} + +@end + +#pragma mark - +#pragma mark CDVBackupInfo implementation + +@implementation CDVBackupInfo + +@synthesize original, backup, label; + +- (BOOL)file:(NSString*)aPath isNewerThanFile:(NSString*)bPath +{ + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSError* __autoreleasing error = nil; + + NSDictionary* aPathAttribs = [fileManager attributesOfItemAtPath:aPath error:&error]; + NSDictionary* bPathAttribs = [fileManager attributesOfItemAtPath:bPath error:&error]; + + NSDate* aPathModDate = [aPathAttribs objectForKey:NSFileModificationDate]; + NSDate* bPathModDate = [bPathAttribs objectForKey:NSFileModificationDate]; + + if ((nil == aPathModDate) && (nil == bPathModDate)) { + return NO; + } + + return [aPathModDate compare:bPathModDate] == NSOrderedDescending || bPathModDate == nil; +} + +- (BOOL)item:(NSString*)aPath isNewerThanItem:(NSString*)bPath +{ + NSFileManager* fileManager = [NSFileManager defaultManager]; + + BOOL aPathIsDir = NO, bPathIsDir = NO; + BOOL aPathExists = [fileManager fileExistsAtPath:aPath isDirectory:&aPathIsDir]; + + [fileManager fileExistsAtPath:bPath isDirectory:&bPathIsDir]; + + if (!aPathExists) { + return NO; + } + + if (!(aPathIsDir && bPathIsDir)) { // just a file + return [self file:aPath isNewerThanFile:bPath]; + } + + // essentially we want rsync here, but have to settle for our poor man's implementation + // we get the files in aPath, and see if it is newer than the file in bPath + // (it is newer if it doesn't exist in bPath) if we encounter the FIRST file that is newer, + // we return YES + NSDirectoryEnumerator* directoryEnumerator = [fileManager enumeratorAtPath:aPath]; + NSString* path; + + while ((path = [directoryEnumerator nextObject])) { + NSString* aPathFile = [aPath stringByAppendingPathComponent:path]; + NSString* bPathFile = [bPath stringByAppendingPathComponent:path]; + + BOOL isNewer = [self file:aPathFile isNewerThanFile:bPathFile]; + if (isNewer) { + return YES; + } + } + + return NO; +} + +- (BOOL)shouldBackup +{ + return [self item:self.original isNewerThanItem:self.backup]; +} + +- (BOOL)shouldRestore +{ + return [self item:self.backup isNewerThanItem:self.original]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h new file mode 100755 index 0000000..d77f191 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.h @@ -0,0 +1,41 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVAvailability.h" + +/** + * Distinguishes top-level navigations from sub-frame navigations. + * shouldStartLoadWithRequest is called for every request, but didStartLoad + * and didFinishLoad is called only for top-level navigations. + * Relevant bug: CB-2389 + */ +@interface CDVUIWebViewDelegate : NSObject { + __weak NSObject * _delegate; + NSInteger _loadCount; + NSInteger _state; + NSInteger _curLoadToken; + NSInteger _loadStartPollCount; +} + +- (id)initWithDelegate:(NSObject *)delegate; + +- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m new file mode 100755 index 0000000..0af97df --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewDelegate.m @@ -0,0 +1,400 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +// +// Testing shows: +// +// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback. +// When loading a page with a redirect: +// 1. shouldStartLoading (requestURL is target page) +// 2. didStartLoading +// 3. shouldStartLoading (requestURL is redirect target) +// 4. didFinishLoad (request.URL is redirect target) +// +// Note the lack of a second didStartLoading ** +// +// When loading a page with iframes: +// 1. shouldStartLoading (requestURL is main page) +// 2. didStartLoading +// 3. shouldStartLoading (requestURL is one of the iframes) +// 4. didStartLoading +// 5. didFinishLoad +// 6. didFinishLoad +// +// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad ** +// +// Loading a page by calling window.history.go(-1): +// 1. didStartLoading +// 2. didFinishLoad +// +// Note the lack of a shouldStartLoading call ** +// Actually - this is fixed on iOS6. iOS6 has a shouldStart. ** +// +// Loading a page by calling location.reload() +// 1. shouldStartLoading +// 2. didStartLoading +// 3. didFinishLoad +// +// Loading a page with an iframe that fails to load: +// 1. shouldStart (main page) +// 2. didStart +// 3. shouldStart (iframe) +// 4. didStart +// 5. didFailWithError +// 6. didFinish +// +// Loading a page with an iframe that fails to load due to an invalid URL: +// 1. shouldStart (main page) +// 2. didStart +// 3. shouldStart (iframe) +// 5. didFailWithError +// 6. didFinish +// +// This case breaks our logic since there is a missing didStart. To prevent this, +// we check URLs in shouldStart and return NO if they are invalid. +// +// Loading a page with an invalid URL +// 1. shouldStart (main page) +// 2. didFailWithError +// +// TODO: Record order when page is re-navigated before the first navigation finishes. +// + +#import "CDVUIWebViewDelegate.h" + +// #define VerboseLog NSLog +#define VerboseLog(...) do { \ +} while (0) + +typedef enum { + STATE_IDLE = 0, + STATE_WAITING_FOR_LOAD_START = 1, + STATE_WAITING_FOR_LOAD_FINISH = 2, + STATE_IOS5_POLLING_FOR_LOAD_START = 3, + STATE_IOS5_POLLING_FOR_LOAD_FINISH = 4, + STATE_CANCELLED = 5 +} State; + +static NSString *stripFragment(NSString* url) +{ + NSRange r = [url rangeOfString:@"#"]; + + if (r.location == NSNotFound) { + return url; + } + return [url substringToIndex:r.location]; +} + +@implementation CDVUIWebViewDelegate + +- (id)initWithDelegate:(NSObject *)delegate +{ + self = [super init]; + if (self != nil) { + _delegate = delegate; + _loadCount = -1; + _state = STATE_IDLE; + } + return self; +} + +- (BOOL)request:(NSURLRequest*)newRequest isEqualToRequestAfterStrippingFragments:(NSURLRequest*)originalRequest +{ + if (originalRequest.URL && newRequest.URL) { + NSString* originalRequestUrl = [originalRequest.URL absoluteString]; + NSString* newRequestUrl = [newRequest.URL absoluteString]; + + NSString* baseOriginalRequestUrl = stripFragment(originalRequestUrl); + NSString* baseNewRequestUrl = stripFragment(newRequestUrl); + return [baseOriginalRequestUrl isEqualToString:baseNewRequestUrl]; + } + + return NO; +} + +- (BOOL)isPageLoaded:(UIWebView*)webView +{ + NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]; + + return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"]; +} + +- (BOOL)isJsLoadTokenSet:(UIWebView*)webView +{ + NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"]; + + return [[NSString stringWithFormat:@"%ld", (long)_curLoadToken] isEqualToString:loadToken]; +} + +- (void)setLoadToken:(UIWebView*)webView +{ + _curLoadToken += 1; + [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%ld", (long)_curLoadToken]]; +} + +- (NSString*)evalForCurrentURL:(UIWebView*)webView +{ + return [webView stringByEvaluatingJavaScriptFromString:@"location.href"]; +} + +- (void)pollForPageLoadStart:(UIWebView*)webView +{ + if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) { + return; + } + if (![self isJsLoadTokenSet:webView]) { + VerboseLog(@"Polled for page load start. result = YES!"); + _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH; + [self setLoadToken:webView]; + if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { + [_delegate webViewDidStartLoad:webView]; + } + [self pollForPageLoadFinish:webView]; + } else { + VerboseLog(@"Polled for page load start. result = NO"); + // Poll only for 1 second, and then fall back on checking only when delegate methods are called. + ++_loadStartPollCount; + if (_loadStartPollCount < (1000 * .05)) { + [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05]; + } + } +} + +- (void)pollForPageLoadFinish:(UIWebView*)webView +{ + if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) { + return; + } + if ([self isPageLoaded:webView]) { + VerboseLog(@"Polled for page load finish. result = YES!"); + _state = STATE_IDLE; + if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { + [_delegate webViewDidFinishLoad:webView]; + } + } else { + VerboseLog(@"Polled for page load finish. result = NO"); + [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05]; + } +} + +- (BOOL)shouldLoadRequest:(NSURLRequest*)request +{ + NSString* scheme = [[request URL] scheme]; + NSArray* allowedSchemes = [NSArray arrayWithObjects:@"mailto",@"tel",@"blob",@"sms",@"data", nil]; + if([allowedSchemes containsObject:scheme]) { + return YES; + } + else { + return [NSURLConnection canHandleRequest:request]; + } +} + +- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + BOOL shouldLoad = YES; + + if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { + shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; + } + + VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL); + + if (shouldLoad) { + // When devtools refresh occurs, it blindly uses the same request object. If a history.replaceState() has occured, then + // mainDocumentURL != URL even though it's a top-level navigation. + BOOL isDevToolsRefresh = (request == webView.request); + BOOL isTopLevelNavigation = isDevToolsRefresh || [request.URL isEqual:[request mainDocumentURL]]; + if (isTopLevelNavigation) { + // Ignore hash changes that don't navigate to a different page. + // webView.request does actually update when history.replaceState() gets called. + if ([self request:request isEqualToRequestAfterStrippingFragments:webView.request]) { + NSString* prevURL = [self evalForCurrentURL:webView]; + if ([prevURL isEqualToString:[request.URL absoluteString]]) { + VerboseLog(@"Page reload detected."); + } else { + VerboseLog(@"Detected hash change shouldLoad"); + return shouldLoad; + } + } + + switch (_state) { + case STATE_WAITING_FOR_LOAD_FINISH: + // Redirect case. + // We expect loadCount == 1. + if (_loadCount != 1) { + NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%ld", (long)_loadCount); + } + break; + + case STATE_IDLE: + case STATE_IOS5_POLLING_FOR_LOAD_START: + case STATE_CANCELLED: + // Page navigation start. + _loadCount = 0; + _state = STATE_WAITING_FOR_LOAD_START; + break; + + default: + { + NSString* description = [NSString stringWithFormat:@"CDVWebViewDelegate: Navigation started when state=%ld", (long)_state]; + NSLog(@"%@", description); + _loadCount = 0; + _state = STATE_WAITING_FOR_LOAD_START; + if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { + NSDictionary* errorDictionary = @{NSLocalizedDescriptionKey : description}; + NSError* error = [[NSError alloc] initWithDomain:@"CDVUIWebViewDelegate" code:1 userInfo:errorDictionary]; + [_delegate webView:webView didFailLoadWithError:error]; + } + } + } + } else { + // Deny invalid URLs so that we don't get the case where we go straight from + // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount). + shouldLoad = shouldLoad && [self shouldLoadRequest:request]; + } + VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount); + } + return shouldLoad; +} + +- (void)webViewDidStartLoad:(UIWebView*)webView +{ + VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount); + BOOL fireCallback = NO; + switch (_state) { + case STATE_IDLE: + break; + + case STATE_CANCELLED: + fireCallback = YES; + _state = STATE_WAITING_FOR_LOAD_FINISH; + _loadCount += 1; + break; + + case STATE_WAITING_FOR_LOAD_START: + if (_loadCount != 0) { + NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%ld", (long)_loadCount); + } + fireCallback = YES; + _state = STATE_WAITING_FOR_LOAD_FINISH; + _loadCount = 1; + break; + + case STATE_WAITING_FOR_LOAD_FINISH: + _loadCount += 1; + break; + + case STATE_IOS5_POLLING_FOR_LOAD_START: + [self pollForPageLoadStart:webView]; + break; + + case STATE_IOS5_POLLING_FOR_LOAD_FINISH: + [self pollForPageLoadFinish:webView]; + break; + + default: + NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%ld loadCount=%ld", (long)_state, (long)_loadCount); + } + VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback); + if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { + [_delegate webViewDidStartLoad:webView]; + } +} + +- (void)webViewDidFinishLoad:(UIWebView*)webView +{ + VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount); + BOOL fireCallback = NO; + switch (_state) { + case STATE_IDLE: + break; + + case STATE_WAITING_FOR_LOAD_START: + NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start."); + break; + + case STATE_WAITING_FOR_LOAD_FINISH: + if (_loadCount == 1) { + fireCallback = YES; + _state = STATE_IDLE; + } + _loadCount -= 1; + break; + + case STATE_IOS5_POLLING_FOR_LOAD_START: + [self pollForPageLoadStart:webView]; + break; + + case STATE_IOS5_POLLING_FOR_LOAD_FINISH: + [self pollForPageLoadFinish:webView]; + break; + } + VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback); + if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { + [_delegate webViewDidFinishLoad:webView]; + } +} + +- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error +{ + VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount); + BOOL fireCallback = NO; + + switch (_state) { + case STATE_IDLE: + break; + + case STATE_WAITING_FOR_LOAD_START: + if ([error code] == NSURLErrorCancelled) { + _state = STATE_CANCELLED; + } else { + _state = STATE_IDLE; + } + fireCallback = YES; + break; + + case STATE_WAITING_FOR_LOAD_FINISH: + if ([error code] != NSURLErrorCancelled) { + if (_loadCount == 1) { + _state = STATE_IDLE; + fireCallback = YES; + } + _loadCount = -1; + } else { + fireCallback = YES; + _state = STATE_CANCELLED; + _loadCount -= 1; + } + break; + + case STATE_IOS5_POLLING_FOR_LOAD_START: + [self pollForPageLoadStart:webView]; + break; + + case STATE_IOS5_POLLING_FOR_LOAD_FINISH: + [self pollForPageLoadFinish:webView]; + break; + } + VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback); + if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { + [_delegate webView:webView didFailLoadWithError:error]; + } +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h new file mode 100755 index 0000000..6a9ee77 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.h @@ -0,0 +1,27 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPlugin.h" +#import "CDVWebViewEngineProtocol.h" + +@interface CDVUIWebViewEngine : CDVPlugin + +@property (nonatomic, strong, readonly) id uiWebViewDelegate; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m new file mode 100755 index 0000000..f571d80 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewEngine.m @@ -0,0 +1,202 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVUIWebViewEngine.h" +#import "CDVUIWebViewDelegate.h" +#import "CDVUIWebViewNavigationDelegate.h" +#import "NSDictionary+CordovaPreferences.h" + +#import + +@interface CDVUIWebViewEngine () + +@property (nonatomic, strong, readwrite) UIView* engineWebView; +@property (nonatomic, strong, readwrite) id uiWebViewDelegate; +@property (nonatomic, strong, readwrite) CDVUIWebViewNavigationDelegate* navWebViewDelegate; + +@end + +@implementation CDVUIWebViewEngine + +@synthesize engineWebView = _engineWebView; + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super init]; + if (self) { + self.engineWebView = [[UIWebView alloc] initWithFrame:frame]; + NSLog(@"Using UIWebView"); + } + + return self; +} + +- (void)pluginInitialize +{ + // viewController would be available now. we attempt to set all possible delegates to it, by default + + UIWebView* uiWebView = (UIWebView*)_engineWebView; + + if ([self.viewController conformsToProtocol:@protocol(UIWebViewDelegate)]) { + self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id )self.viewController]; + uiWebView.delegate = self.uiWebViewDelegate; + } else { + self.navWebViewDelegate = [[CDVUIWebViewNavigationDelegate alloc] initWithEnginePlugin:self]; + self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:self.navWebViewDelegate]; + uiWebView.delegate = self.uiWebViewDelegate; + } + + [self updateSettings:self.commandDelegate.settings]; +} + +- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler +{ + NSString* ret = [(UIWebView*)_engineWebView stringByEvaluatingJavaScriptFromString:javaScriptString]; + + if (completionHandler) { + completionHandler(ret, nil); + } +} + +- (id)loadRequest:(NSURLRequest*)request +{ + [(UIWebView*)_engineWebView loadRequest:request]; + return nil; +} + +- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL +{ + [(UIWebView*)_engineWebView loadHTMLString:string baseURL:baseURL]; + return nil; +} + +- (NSURL*)URL +{ + return [[(UIWebView*)_engineWebView request] URL]; +} + +- (BOOL) canLoadRequest:(NSURLRequest*)request +{ + return (request != nil); +} + +- (void)updateSettings:(NSDictionary*)settings +{ + UIWebView* uiWebView = (UIWebView*)_engineWebView; + + uiWebView.scalesPageToFit = [settings cordovaBoolSettingForKey:@"EnableViewportScale" defaultValue:NO]; + uiWebView.allowsInlineMediaPlayback = [settings cordovaBoolSettingForKey:@"AllowInlineMediaPlayback" defaultValue:NO]; + uiWebView.mediaPlaybackRequiresUserAction = [settings cordovaBoolSettingForKey:@"MediaPlaybackRequiresUserAction" defaultValue:YES]; + uiWebView.mediaPlaybackAllowsAirPlay = [settings cordovaBoolSettingForKey:@"MediaPlaybackAllowsAirPlay" defaultValue:YES]; + uiWebView.keyboardDisplayRequiresUserAction = [settings cordovaBoolSettingForKey:@"KeyboardDisplayRequiresUserAction" defaultValue:YES]; + uiWebView.suppressesIncrementalRendering = [settings cordovaBoolSettingForKey:@"SuppressesIncrementalRendering" defaultValue:NO]; + uiWebView.gapBetweenPages = [settings cordovaFloatSettingForKey:@"GapBetweenPages" defaultValue:0.0]; + uiWebView.pageLength = [settings cordovaFloatSettingForKey:@"PageLength" defaultValue:0.0]; + + id prefObj = nil; + + // By default, DisallowOverscroll is false (thus bounce is allowed) + BOOL bounceAllowed = !([settings cordovaBoolSettingForKey:@"DisallowOverscroll" defaultValue:NO]); + + // prevent webView from bouncing + if (!bounceAllowed) { + if ([uiWebView respondsToSelector:@selector(scrollView)]) { + ((UIScrollView*)[uiWebView scrollView]).bounces = NO; + } else { + for (id subview in self.webView.subviews) { + if ([[subview class] isSubclassOfClass:[UIScrollView class]]) { + ((UIScrollView*)subview).bounces = NO; + } + } + } + } + + NSString* decelerationSetting = [settings cordovaSettingForKey:@"UIWebViewDecelerationSpeed"]; + if (![@"fast" isEqualToString:decelerationSetting]) { + [uiWebView.scrollView setDecelerationRate:UIScrollViewDecelerationRateNormal]; + } + + NSInteger paginationBreakingMode = 0; // default - UIWebPaginationBreakingModePage + prefObj = [settings cordovaSettingForKey:@"PaginationBreakingMode"]; + if (prefObj != nil) { + NSArray* validValues = @[@"page", @"column"]; + NSString* prefValue = [validValues objectAtIndex:0]; + + if ([prefObj isKindOfClass:[NSString class]]) { + prefValue = prefObj; + } + + paginationBreakingMode = [validValues indexOfObject:[prefValue lowercaseString]]; + if (paginationBreakingMode == NSNotFound) { + paginationBreakingMode = 0; + } + } + uiWebView.paginationBreakingMode = paginationBreakingMode; + + NSInteger paginationMode = 0; // default - UIWebPaginationModeUnpaginated + prefObj = [settings cordovaSettingForKey:@"PaginationMode"]; + if (prefObj != nil) { + NSArray* validValues = @[@"unpaginated", @"lefttoright", @"toptobottom", @"bottomtotop", @"righttoleft"]; + NSString* prefValue = [validValues objectAtIndex:0]; + + if ([prefObj isKindOfClass:[NSString class]]) { + prefValue = prefObj; + } + + paginationMode = [validValues indexOfObject:[prefValue lowercaseString]]; + if (paginationMode == NSNotFound) { + paginationMode = 0; + } + } + uiWebView.paginationMode = paginationMode; +} + +- (void)updateWithInfo:(NSDictionary*)info +{ + UIWebView* uiWebView = (UIWebView*)_engineWebView; + + id uiWebViewDelegate = [info objectForKey:kCDVWebViewEngineUIWebViewDelegate]; + NSDictionary* settings = [info objectForKey:kCDVWebViewEngineWebViewPreferences]; + + if (uiWebViewDelegate && + [uiWebViewDelegate conformsToProtocol:@protocol(UIWebViewDelegate)]) { + self.uiWebViewDelegate = [[CDVUIWebViewDelegate alloc] initWithDelegate:(id )self.viewController]; + uiWebView.delegate = self.uiWebViewDelegate; + } + + if (settings && [settings isKindOfClass:[NSDictionary class]]) { + [self updateSettings:settings]; + } +} + +// This forwards the methods that are in the header that are not implemented here. +// Both WKWebView and UIWebView implement the below: +// loadHTMLString:baseURL: +// loadRequest: +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _engineWebView; +} + +- (UIView*)webView +{ + return self.engineWebView; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h new file mode 100755 index 0000000..9138deb --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.h @@ -0,0 +1,29 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVUIWebViewEngine.h" + +@interface CDVUIWebViewNavigationDelegate : NSObject + +@property (nonatomic, weak) CDVPlugin* enginePlugin; + +- (instancetype)initWithEnginePlugin:(CDVPlugin*)enginePlugin; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m new file mode 100755 index 0000000..490cff4 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Private/Plugins/CDVUIWebViewEngine/CDVUIWebViewNavigationDelegate.m @@ -0,0 +1,151 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVUIWebViewNavigationDelegate.h" +#import "CDVViewController.h" +#import "CDVCommandDelegateImpl.h" +#import "CDVUserAgentUtil.h" +#import + +@implementation CDVUIWebViewNavigationDelegate + +- (instancetype)initWithEnginePlugin:(CDVPlugin*)theEnginePlugin +{ + self = [super init]; + if (self) { + self.enginePlugin = theEnginePlugin; + } + + return self; +} + +/** + When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and + the device's data such as device ID, platform version, etc. + */ +- (void)webViewDidStartLoad:(UIWebView*)theWebView +{ + NSLog(@"Resetting plugins due to page load."); + CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; + + [vc.commandQueue resetRequestId]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.enginePlugin.webView]]; +} + +/** + Called when the webview finishes loading. This stops the activity view. + */ +- (void)webViewDidFinishLoad:(UIWebView*)theWebView +{ + NSLog(@"Finished load of: %@", theWebView.request.URL); + CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; + + // It's safe to release the lock even if this is just a sub-frame that's finished loading. + [CDVUserAgentUtil releaseLock:vc.userAgentLockToken]; + + /* + * Hide the Top Activity THROBBER in the Battery Bar + */ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.enginePlugin.webView]]; +} + +- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error +{ + CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; + + [CDVUserAgentUtil releaseLock:vc.userAgentLockToken]; + + NSString* message = [NSString stringWithFormat:@"Failed to load webpage with error: %@", [error localizedDescription]]; + NSLog(@"%@", message); + + NSURL* errorUrl = vc.errorURL; + if (errorUrl) { + errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [message stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl]; + NSLog(@"%@", [errorUrl absoluteString]); + [theWebView loadRequest:[NSURLRequest requestWithURL:errorUrl]]; + } +} + +- (BOOL)defaultResourcePolicyForURL:(NSURL*)url +{ + /* + * If a URL is being loaded that's a file url, just load it internally + */ + if ([url isFileURL]) { + return YES; + } + + return NO; +} + +- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType +{ + NSURL* url = [request URL]; + CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController; + + /* + * Execute any commands queued with cordova.exec() on the JS side. + * The part of the URL after gap:// is irrelevant. + */ + if ([[url scheme] isEqualToString:@"gap"]) { + [vc.commandQueue fetchCommandsFromJs]; + // The delegate is called asynchronously in this case, so we don't have to use + // flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes. + [vc.commandQueue executePending]; + return NO; + } + + /* + * Give plugins the chance to handle the url + */ + BOOL anyPluginsResponded = NO; + BOOL shouldAllowRequest = NO; + + for (NSString* pluginName in vc.pluginObjects) { + CDVPlugin* plugin = [vc.pluginObjects objectForKey:pluginName]; + SEL selector = NSSelectorFromString(@"shouldOverrideLoadWithRequest:navigationType:"); + if ([plugin respondsToSelector:selector]) { + anyPluginsResponded = YES; + shouldAllowRequest = (((BOOL (*)(id, SEL, id, int))objc_msgSend)(plugin, selector, request, navigationType)); + if (!shouldAllowRequest) { + break; + } + } + } + + if (anyPluginsResponded) { + return shouldAllowRequest; + } + + /* + * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview. + */ + BOOL shouldAllowNavigation = [self defaultResourcePolicyForURL:url]; + if (shouldAllowNavigation) { + return YES; + } else { + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + } + + return NO; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDV.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDV.h new file mode 100755 index 0000000..96d6efc --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDV.h @@ -0,0 +1,32 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVAvailability.h" +#import "CDVAvailabilityDeprecated.h" +#import "CDVAppDelegate.h" +#import "CDVPlugin.h" +#import "CDVPluginResult.h" +#import "CDVViewController.h" +#import "CDVCommandDelegate.h" +#import "CDVURLProtocol.h" +#import "CDVInvokedUrlCommand.h" +#import "CDVWhitelist.h" +#import "CDVScreenOrientationDelegate.h" +#import "CDVTimer.h" +#import "CDVUserAgentUtil.h" diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.h new file mode 100755 index 0000000..de5b518 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.h @@ -0,0 +1,28 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVViewController.h" + +@interface CDVAppDelegate : NSObject {} + +@property (nonatomic, strong) IBOutlet UIWindow* window; +@property (nonatomic, strong) IBOutlet CDVViewController* viewController; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.m new file mode 100755 index 0000000..13c2e7b --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAppDelegate.m @@ -0,0 +1,105 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVAppDelegate.h" + +@implementation CDVAppDelegate + +@synthesize window, viewController; + +- (id)init +{ + /** If you need to do any extra app-specific initialization, you can do it here + * -jm + **/ + NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + + [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways]; + + int cacheSizeMemory = 8 * 1024 * 1024; // 8MB + int cacheSizeDisk = 32 * 1024 * 1024; // 32MB + NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"]; + [NSURLCache setSharedURLCache:sharedCache]; + + self = [super init]; + return self; +} + +#pragma mark UIApplicationDelegate implementation + +/** + * This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up) + */ +- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions +{ + CGRect screenBounds = [[UIScreen mainScreen] bounds]; + + self.window = [[UIWindow alloc] initWithFrame:screenBounds]; + self.window.autoresizesSubviews = YES; + + // only set if not already set in subclass + if (self.viewController == nil) { + self.viewController = [[CDVViewController alloc] init]; + } + + // Set your app's start page by setting the tag in config.xml. + // If necessary, uncomment the line below to override it. + // self.viewController.startPage = @"index.html"; + + // NOTE: To customize the view's frame size (which defaults to full screen), override + // [self.viewController viewWillAppear:] in your view controller. + + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + + return YES; +} + +// this happens while we are running ( in the background, or from within our own app ) +// only valid if 40x-Info.plist specifies a protocol to handle +- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation +{ + if (!url) { + return NO; + } + + // all plugins will get the notification, and their handlers will be called + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]]; + + return YES; +} + +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 +- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window +#else +- (UIInterfaceOrientationMask)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window +#endif +{ + // iPhone doesn't support upside down by default, while the iPad does. Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected). + NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown); + + return supportedInterfaceOrientations; +} + +- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application +{ + [[NSURLCache sharedURLCache] removeAllCachedResponses]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailability.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailability.h new file mode 100755 index 0000000..10d6d50 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailability.h @@ -0,0 +1,104 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVAvailabilityDeprecated.h" + +#define __CORDOVA_IOS__ + +#define __CORDOVA_0_9_6 906 +#define __CORDOVA_1_0_0 10000 +#define __CORDOVA_1_1_0 10100 +#define __CORDOVA_1_2_0 10200 +#define __CORDOVA_1_3_0 10300 +#define __CORDOVA_1_4_0 10400 +#define __CORDOVA_1_4_1 10401 +#define __CORDOVA_1_5_0 10500 +#define __CORDOVA_1_6_0 10600 +#define __CORDOVA_1_6_1 10601 +#define __CORDOVA_1_7_0 10700 +#define __CORDOVA_1_8_0 10800 +#define __CORDOVA_1_8_1 10801 +#define __CORDOVA_1_9_0 10900 +#define __CORDOVA_2_0_0 20000 +#define __CORDOVA_2_1_0 20100 +#define __CORDOVA_2_2_0 20200 +#define __CORDOVA_2_3_0 20300 +#define __CORDOVA_2_4_0 20400 +#define __CORDOVA_2_5_0 20500 +#define __CORDOVA_2_6_0 20600 +#define __CORDOVA_2_7_0 20700 +#define __CORDOVA_2_8_0 20800 +#define __CORDOVA_2_9_0 20900 +#define __CORDOVA_3_0_0 30000 +#define __CORDOVA_3_1_0 30100 +#define __CORDOVA_3_2_0 30200 +#define __CORDOVA_3_3_0 30300 +#define __CORDOVA_3_4_0 30400 +#define __CORDOVA_3_4_1 30401 +#define __CORDOVA_3_5_0 30500 +#define __CORDOVA_3_6_0 30600 +#define __CORDOVA_3_7_0 30700 +#define __CORDOVA_3_8_0 30800 +#define __CORDOVA_3_9_0 30900 +#define __CORDOVA_3_9_1 30901 +#define __CORDOVA_3_9_2 30902 +#define __CORDOVA_4_0_0 40000 +#define __CORDOVA_4_0_1 40001 +#define __CORDOVA_4_1_0 40100 +#define __CORDOVA_4_1_1 40101 +#define __CORDOVA_4_2_0 40200 +#define __CORDOVA_4_2_1 40201 +/* coho:next-version,insert-before */ +#define __CORDOVA_NA 99999 /* not available */ + +/* + #if CORDOVA_VERSION_MIN_REQUIRED >= __CORDOVA_4_0_0 + // do something when its at least 4.0.0 + #else + // do something else (non 4.0.0) + #endif + */ +#ifndef CORDOVA_VERSION_MIN_REQUIRED + /* coho:next-version-min-required,replace-after */ + #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_4_2_1 +#endif + +/* + Returns YES if it is at least version specified as NSString(X) + Usage: + if (IsAtLeastiOSVersion(@"5.1")) { + // do something for iOS 5.1 or greater + } + */ +#define IsAtLeastiOSVersion(X) ([[[UIDevice currentDevice] systemVersion] compare:X options:NSNumericSearch] != NSOrderedAscending) + +/* Return the string version of the decimal version */ +#define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \ + (CORDOVA_VERSION_MIN_REQUIRED / 10000), \ + (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100, \ + (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100] + +// Enable this to log all exec() calls. +#define CDV_ENABLE_EXEC_LOGGING 0 +#if CDV_ENABLE_EXEC_LOGGING + #define CDV_EXEC_LOG NSLog +#else + #define CDV_EXEC_LOG(...) do { \ +} while (NO) +#endif diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailabilityDeprecated.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailabilityDeprecated.h new file mode 100755 index 0000000..abf7a16 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVAvailabilityDeprecated.h @@ -0,0 +1,26 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +#ifdef __clang__ + #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg))) +#else + #define CDV_DEPRECATED(version, msg) __attribute__((deprecated())) +#endif diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegate.h new file mode 100755 index 0000000..3d9d90c --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegate.h @@ -0,0 +1,51 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVAvailability.h" +#import "CDVInvokedUrlCommand.h" + +@class CDVPlugin; +@class CDVPluginResult; +@class CDVWhitelist; + +typedef NSURL* (^ UrlTransformerBlock)(NSURL*); + +@protocol CDVCommandDelegate + +@property (nonatomic, readonly) NSDictionary* settings; +@property (nonatomic, copy) UrlTransformerBlock urlTransformer; + +- (NSString*)pathForResource:(NSString*)resourcepath; +- (id)getCommandInstance:(NSString*)pluginName; + +// Sends a plugin result to the JS. This is thread-safe. +- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId; +// Evaluates the given JS. This is thread-safe. +- (void)evalJs:(NSString*)js; +// Can be used to evaluate JS right away instead of scheduling it on the run-loop. +// This is required for dispatch resign and pause events, but should not be used +// without reason. Without the run-loop delay, alerts used in JS callbacks may result +// in dead-lock. This method must be called from the UI thread. +- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop; +// Runs the given block on a background thread using a shared thread-pool. +- (void)runInBackground:(void (^)())block; +// Returns the User-Agent of the associated UIWebView. +- (NSString*)userAgent; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.h new file mode 100755 index 0000000..0531134 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.h @@ -0,0 +1,36 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVCommandDelegate.h" + +@class CDVViewController; +@class CDVCommandQueue; + +@interface CDVCommandDelegateImpl : NSObject { + @private + __weak CDVViewController* _viewController; + NSRegularExpression* _callbackIdPattern; + @protected + __weak CDVCommandQueue* _commandQueue; + BOOL _delayResponses; +} +- (id)initWithViewController:(CDVViewController*)viewController; +- (void)flushCommandQueueWithDelayedJs; +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.m new file mode 100755 index 0000000..fd8b3e8 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandDelegateImpl.m @@ -0,0 +1,186 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVCommandDelegateImpl.h" +#import "CDVJSON_private.h" +#import "CDVCommandQueue.h" +#import "CDVPluginResult.h" +#import "CDVViewController.h" + +@implementation CDVCommandDelegateImpl + +@synthesize urlTransformer; + +- (id)initWithViewController:(CDVViewController*)viewController +{ + self = [super init]; + if (self != nil) { + _viewController = viewController; + _commandQueue = _viewController.commandQueue; + + NSError* err = nil; + _callbackIdPattern = [NSRegularExpression regularExpressionWithPattern:@"[^A-Za-z0-9._-]" options:0 error:&err]; + if (err != nil) { + // Couldn't initialize Regex + NSLog(@"Error: Couldn't initialize regex"); + _callbackIdPattern = nil; + } + } + return self; +} + +- (NSString*)pathForResource:(NSString*)resourcepath +{ + NSBundle* mainBundle = [NSBundle mainBundle]; + NSMutableArray* directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]]; + NSString* filename = [directoryParts lastObject]; + + [directoryParts removeLastObject]; + + NSString* directoryPartsJoined = [directoryParts componentsJoinedByString:@"/"]; + NSString* directoryStr = _viewController.wwwFolderName; + + if ([directoryPartsJoined length] > 0) { + directoryStr = [NSString stringWithFormat:@"%@/%@", _viewController.wwwFolderName, [directoryParts componentsJoinedByString:@"/"]]; + } + + return [mainBundle pathForResource:filename ofType:@"" inDirectory:directoryStr]; +} + +- (void)flushCommandQueueWithDelayedJs +{ + _delayResponses = YES; + [_commandQueue executePending]; + _delayResponses = NO; +} + +- (void)evalJsHelper2:(NSString*)js +{ + CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]); + [_viewController.webViewEngine evaluateJavaScript:js completionHandler:^(id obj, NSError* error) { + // TODO: obj can be something other than string + if ([obj isKindOfClass:[NSString class]]) { + NSString* commandsJSON = (NSString*)obj; + if ([commandsJSON length] > 0) { + CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining."); + } + + [_commandQueue enqueueCommandBatch:commandsJSON]; + [_commandQueue executePending]; + } + }]; +} + +- (void)evalJsHelper:(NSString*)js +{ + // Cycle the run-loop before executing the JS. + // For _delayResponses - + // This ensures that we don't eval JS during the middle of an existing JS + // function (possible since UIWebViewDelegate callbacks can be synchronous). + // For !isMainThread - + // It's a hard error to eval on the non-UI thread. + // For !_commandQueue.currentlyExecuting - + // This works around a bug where sometimes alerts() within callbacks can cause + // dead-lock. + // If the commandQueue is currently executing, then we know that it is safe to + // execute the callback immediately. + // Using (dispatch_get_main_queue()) does *not* fix deadlocks for some reason, + // but performSelectorOnMainThread: does. + if (_delayResponses || ![NSThread isMainThread] || !_commandQueue.currentlyExecuting) { + [self performSelectorOnMainThread:@selector(evalJsHelper2:) withObject:js waitUntilDone:NO]; + } else { + [self evalJsHelper2:js]; + } +} + +- (BOOL)isValidCallbackId:(NSString*)callbackId +{ + if ((callbackId == nil) || (_callbackIdPattern == nil)) { + return NO; + } + + // Disallow if too long or if any invalid characters were found. + if (([callbackId length] > 100) || [_callbackIdPattern firstMatchInString:callbackId options:0 range:NSMakeRange(0, [callbackId length])]) { + return NO; + } + return YES; +} + +- (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId +{ + CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status); + // This occurs when there is are no win/fail callbacks for the call. + if ([@"INVALID" isEqualToString:callbackId]) { + return; + } + // This occurs when the callback id is malformed. + if (![self isValidCallbackId:callbackId]) { + NSLog(@"Invalid callback id received by sendPluginResult"); + return; + } + int status = [result.status intValue]; + BOOL keepCallback = [result.keepCallback boolValue]; + NSString* argumentsAsJSON = [result argumentsAsJSON]; + BOOL debug = NO; + +#ifdef DEBUG + debug = YES; +#endif + + NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d, %d)", callbackId, status, argumentsAsJSON, keepCallback, debug]; + + [self evalJsHelper:js]; +} + +- (void)evalJs:(NSString*)js +{ + [self evalJs:js scheduledOnRunLoop:YES]; +} + +- (void)evalJs:(NSString*)js scheduledOnRunLoop:(BOOL)scheduledOnRunLoop +{ + js = [NSString stringWithFormat:@"try{cordova.require('cordova/exec').nativeEvalAndFetch(function(){%@})}catch(e){console.log('exception nativeEvalAndFetch : '+e);};", js]; + if (scheduledOnRunLoop) { + [self evalJsHelper:js]; + } else { + [self evalJsHelper2:js]; + } +} + +- (id)getCommandInstance:(NSString*)pluginName +{ + return [_viewController getCommandInstance:pluginName]; +} + +- (void)runInBackground:(void (^)())block +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); +} + +- (NSString*)userAgent +{ + return [_viewController userAgent]; +} + +- (NSDictionary*)settings +{ + return _viewController.settings; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.h new file mode 100755 index 0000000..cb7bd6e --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.h @@ -0,0 +1,39 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@class CDVInvokedUrlCommand; +@class CDVViewController; + +@interface CDVCommandQueue : NSObject + +@property (nonatomic, readonly) BOOL currentlyExecuting; + +- (id)initWithViewController:(CDVViewController*)viewController; +- (void)dispose; + +- (void)resetRequestId; +- (void)enqueueCommandBatch:(NSString*)batchJSON; + +- (void)fetchCommandsFromJs; +- (void)executePending; +- (BOOL)execute:(CDVInvokedUrlCommand*)command; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.m new file mode 100755 index 0000000..b78ed83 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVCommandQueue.m @@ -0,0 +1,194 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#include +#import "CDVCommandQueue.h" +#import "CDVViewController.h" +#import "CDVCommandDelegateImpl.h" +#import "CDVJSON_private.h" +#import "CDVDebug.h" + +// Parse JS on the main thread if it's shorter than this. +static const NSInteger JSON_SIZE_FOR_MAIN_THREAD = 4 * 1024; // Chosen arbitrarily. +// Execute multiple commands in one go until this many seconds have passed. +static const double MAX_EXECUTION_TIME = .008; // Half of a 60fps frame. + +@interface CDVCommandQueue () { + NSInteger _lastCommandQueueFlushRequestId; + __weak CDVViewController* _viewController; + NSMutableArray* _queue; + NSTimeInterval _startExecutionTime; +} +@end + +@implementation CDVCommandQueue + +- (BOOL)currentlyExecuting +{ + return _startExecutionTime > 0; +} + +- (id)initWithViewController:(CDVViewController*)viewController +{ + self = [super init]; + if (self != nil) { + _viewController = viewController; + _queue = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)dispose +{ + // TODO(agrieve): Make this a zeroing weak ref once we drop support for 4.3. + _viewController = nil; +} + +- (void)resetRequestId +{ + _lastCommandQueueFlushRequestId = 0; +} + +- (void)enqueueCommandBatch:(NSString*)batchJSON +{ + if ([batchJSON length] > 0) { + NSMutableArray* commandBatchHolder = [[NSMutableArray alloc] init]; + [_queue addObject:commandBatchHolder]; + if ([batchJSON length] < JSON_SIZE_FOR_MAIN_THREAD) { + [commandBatchHolder addObject:[batchJSON cdv_JSONObject]]; + } else { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() { + NSMutableArray* result = [batchJSON cdv_JSONObject]; + @synchronized(commandBatchHolder) { + [commandBatchHolder addObject:result]; + } + [self performSelectorOnMainThread:@selector(executePending) withObject:nil waitUntilDone:NO]; + }); + } + } +} + +- (void)fetchCommandsFromJs +{ + __weak CDVCommandQueue* weakSelf = self; + NSString* js = @"cordova.require('cordova/exec').nativeFetchMessages()"; + + [_viewController.webViewEngine evaluateJavaScript:js + completionHandler:^(id obj, NSError* error) { + if ((error == nil) && [obj isKindOfClass:[NSString class]]) { + NSString* queuedCommandsJSON = (NSString*)obj; + CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0); + [weakSelf enqueueCommandBatch:queuedCommandsJSON]; + // this has to be called here now, because fetchCommandsFromJs is now async (previously: synchronous) + [self executePending]; + } + }]; +} + +- (void)executePending +{ + // Make us re-entrant-safe. + if (_startExecutionTime > 0) { + return; + } + @try { + _startExecutionTime = [NSDate timeIntervalSinceReferenceDate]; + + while ([_queue count] > 0) { + NSMutableArray* commandBatchHolder = _queue[0]; + NSMutableArray* commandBatch = nil; + @synchronized(commandBatchHolder) { + // If the next-up command is still being decoded, wait for it. + if ([commandBatchHolder count] == 0) { + break; + } + commandBatch = commandBatchHolder[0]; + } + + while ([commandBatch count] > 0) { + @autoreleasepool { + // Execute the commands one-at-a-time. + NSArray* jsonEntry = [commandBatch cdv_dequeue]; + if ([commandBatch count] == 0) { + [_queue removeObjectAtIndex:0]; + } + CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry]; + CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName); + + if (![self execute:command]) { +#ifdef DEBUG + NSString* commandJson = [jsonEntry cdv_JSONString]; + static NSUInteger maxLogLength = 1024; + NSString* commandString = ([commandJson length] > maxLogLength) ? + [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] : + commandJson; + + DLog(@"FAILED pluginJSON = %@", commandString); +#endif + } + } + + // Yield if we're taking too long. + if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) { + [self performSelector:@selector(executePending) withObject:nil afterDelay:0]; + return; + } + } + } + } @finally + { + _startExecutionTime = 0; + } +} + +- (BOOL)execute:(CDVInvokedUrlCommand*)command +{ + if ((command.className == nil) || (command.methodName == nil)) { + NSLog(@"ERROR: Classname and/or methodName not found for command."); + return NO; + } + + // Fetch an instance of this class + CDVPlugin* obj = [_viewController.commandDelegate getCommandInstance:command.className]; + + if (!([obj isKindOfClass:[CDVPlugin class]])) { + NSLog(@"ERROR: Plugin '%@' not found, or is not a CDVPlugin. Check your plugin mapping in config.xml.", command.className); + return NO; + } + BOOL retVal = YES; + double started = [[NSDate date] timeIntervalSince1970] * 1000.0; + // Find the proper selector to call. + NSString* methodName = [NSString stringWithFormat:@"%@:", command.methodName]; + SEL normalSelector = NSSelectorFromString(methodName); + if ([obj respondsToSelector:normalSelector]) { + // [obj performSelector:normalSelector withObject:command]; + ((void (*)(id, SEL, id))objc_msgSend)(obj, normalSelector, command); + } else { + // There's no method to call, so throw an error. + NSLog(@"ERROR: Method '%@' not defined in Plugin '%@'", methodName, command.className); + retVal = NO; + } + double elapsed = [[NSDate date] timeIntervalSince1970] * 1000.0 - started; + if (elapsed > 10) { + NSLog(@"THREAD WARNING: ['%@'] took '%f' ms. Plugin should use a background thread.", command.className, elapsed); + } + return retVal; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.h new file mode 100755 index 0000000..bae3d0f --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.h @@ -0,0 +1,30 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +@interface CDVConfigParser : NSObject +{ + NSString* featureName; +} + +@property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict; +@property (nonatomic, readonly, strong) NSMutableDictionary* settings; +@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames; +@property (nonatomic, readonly, strong) NSString* startPage; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.m new file mode 100755 index 0000000..ab32b4a --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVConfigParser.m @@ -0,0 +1,81 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVConfigParser.h" + +@interface CDVConfigParser () + +@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict; +@property (nonatomic, readwrite, strong) NSMutableDictionary* settings; +@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames; +@property (nonatomic, readwrite, strong) NSString* startPage; + +@end + +@implementation CDVConfigParser + +@synthesize pluginsDict, settings, startPage, startupPluginNames; + +- (id)init +{ + self = [super init]; + if (self != nil) { + self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30]; + self.settings = [[NSMutableDictionary alloc] initWithCapacity:30]; + self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8]; + featureName = nil; + } + return self; +} + +- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict +{ + if ([elementName isEqualToString:@"preference"]) { + settings[[attributeDict[@"name"] lowercaseString]] = attributeDict[@"value"]; + } else if ([elementName isEqualToString:@"feature"]) { // store feature name to use with correct parameter set + featureName = [attributeDict[@"name"] lowercaseString]; + } else if ((featureName != nil) && [elementName isEqualToString:@"param"]) { + NSString* paramName = [attributeDict[@"name"] lowercaseString]; + id value = attributeDict[@"value"]; + if ([paramName isEqualToString:@"ios-package"]) { + pluginsDict[featureName] = value; + } + BOOL paramIsOnload = ([paramName isEqualToString:@"onload"] && [@"true" isEqualToString : value]); + BOOL attribIsOnload = [@"true" isEqualToString :[attributeDict[@"onload"] lowercaseString]]; + if (paramIsOnload || attribIsOnload) { + [self.startupPluginNames addObject:featureName]; + } + } else if ([elementName isEqualToString:@"content"]) { + self.startPage = attributeDict[@"src"]; + } +} + +- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName +{ + if ([elementName isEqualToString:@"feature"]) { // no longer handling a feature so release + featureName = nil; + } +} + +- (void)parser:(NSXMLParser*)parser parseErrorOccurred:(NSError*)parseError +{ + NSAssert(NO, @"config.xml parse error line %ld col %ld", (long)[parser lineNumber], (long)[parser columnNumber]); +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.h new file mode 100755 index 0000000..993e0a2 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.h @@ -0,0 +1,52 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@interface CDVInvokedUrlCommand : NSObject { + NSString* _callbackId; + NSString* _className; + NSString* _methodName; + NSArray* _arguments; +} + +@property (nonatomic, readonly) NSArray* arguments; +@property (nonatomic, readonly) NSString* callbackId; +@property (nonatomic, readonly) NSString* className; +@property (nonatomic, readonly) NSString* methodName; + ++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry; + +- (id)initWithArguments:(NSArray*)arguments + callbackId:(NSString*)callbackId + className:(NSString*)className + methodName:(NSString*)methodName; + +- (id)initFromJson:(NSArray*)jsonEntry; + +// Returns the argument at the given index. +// If index >= the number of arguments, returns nil. +// If the argument at the given index is NSNull, returns nil. +- (id)argumentAtIndex:(NSUInteger)index; +// Same as above, but returns defaultValue instead of nil. +- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue; +// Same as above, but returns defaultValue instead of nil, and if the argument is not of the expected class, returns defaultValue +- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.m new file mode 100755 index 0000000..5b4281d --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVInvokedUrlCommand.m @@ -0,0 +1,116 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVInvokedUrlCommand.h" +#import "CDVJSON_private.h" + +@implementation CDVInvokedUrlCommand + +@synthesize arguments = _arguments; +@synthesize callbackId = _callbackId; +@synthesize className = _className; +@synthesize methodName = _methodName; + ++ (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry +{ + return [[CDVInvokedUrlCommand alloc] initFromJson:jsonEntry]; +} + +- (id)initFromJson:(NSArray*)jsonEntry +{ + id tmp = [jsonEntry objectAtIndex:0]; + NSString* callbackId = tmp == [NSNull null] ? nil : tmp; + NSString* className = [jsonEntry objectAtIndex:1]; + NSString* methodName = [jsonEntry objectAtIndex:2]; + NSMutableArray* arguments = [jsonEntry objectAtIndex:3]; + + return [self initWithArguments:arguments + callbackId:callbackId + className:className + methodName:methodName]; +} + +- (id)initWithArguments:(NSArray*)arguments + callbackId:(NSString*)callbackId + className:(NSString*)className + methodName:(NSString*)methodName +{ + self = [super init]; + if (self != nil) { + _arguments = arguments; + _callbackId = callbackId; + _className = className; + _methodName = methodName; + } + [self massageArguments]; + return self; +} + +- (void)massageArguments +{ + NSMutableArray* newArgs = nil; + + for (NSUInteger i = 0, count = [_arguments count]; i < count; ++i) { + id arg = [_arguments objectAtIndex:i]; + if (![arg isKindOfClass:[NSDictionary class]]) { + continue; + } + NSDictionary* dict = arg; + NSString* type = [dict objectForKey:@"CDVType"]; + if (!type || ![type isEqualToString:@"ArrayBuffer"]) { + continue; + } + NSString* data = [dict objectForKey:@"data"]; + if (!data) { + continue; + } + if (newArgs == nil) { + newArgs = [NSMutableArray arrayWithArray:_arguments]; + _arguments = newArgs; + } + [newArgs replaceObjectAtIndex:i withObject:[[NSData alloc] initWithBase64EncodedString:data options:0]]; + } +} + +- (id)argumentAtIndex:(NSUInteger)index +{ + return [self argumentAtIndex:index withDefault:nil]; +} + +- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue +{ + return [self argumentAtIndex:index withDefault:defaultValue andClass:nil]; +} + +- (id)argumentAtIndex:(NSUInteger)index withDefault:(id)defaultValue andClass:(Class)aClass +{ + if (index >= [_arguments count]) { + return defaultValue; + } + id ret = [_arguments objectAtIndex:index]; + if (ret == [NSNull null]) { + ret = defaultValue; + } + if ((aClass != nil) && ![ret isKindOfClass:aClass]) { + ret = defaultValue; + } + return ret; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.h new file mode 100755 index 0000000..cc43b16 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.h @@ -0,0 +1,39 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVPlugin.h" + +@interface CDVPlugin (CDVPluginResources) + +/* + This will return the localized string for a key in a .bundle that is named the same as your class + For example, if your plugin class was called Foo, and you have a Spanish localized strings file, it will + try to load the desired key from Foo.bundle/es.lproj/Localizable.strings + */ +- (NSString*)pluginLocalizedString:(NSString*)key; + +/* + This will return the image for a name in a .bundle that is named the same as your class + For example, if your plugin class was called Foo, and you have an image called "bar", + it will try to load the image from Foo.bundle/bar.png (and appropriately named retina versions) + */ +- (UIImage*)pluginImageResource:(NSString*)name; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.m new file mode 100755 index 0000000..5690738 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin+Resources.m @@ -0,0 +1,38 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPlugin+Resources.h" + +@implementation CDVPlugin (CDVPluginResources) + +- (NSString*)pluginLocalizedString:(NSString*)key +{ + NSBundle* bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:NSStringFromClass([self class]) ofType:@"bundle"]]; + + return [bundle localizedStringForKey:(key) value:nil table:nil]; +} + +- (UIImage*)pluginImageResource:(NSString*)name +{ + NSString* resourceIdentifier = [NSString stringWithFormat:@"%@.bundle/%@", NSStringFromClass([self class]), name]; + + return [UIImage imageNamed:resourceIdentifier]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.h new file mode 100755 index 0000000..b773d60 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.h @@ -0,0 +1,76 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import +#import "CDVPluginResult.h" +#import "NSMutableArray+QueueAdditions.h" +#import "CDVCommandDelegate.h" +#import "CDVWebViewEngineProtocol.h" + +@interface UIView (org_apache_cordova_UIView_Extension) + +@property (nonatomic, weak) UIScrollView* scrollView; + +@end + +extern NSString* const CDVPageDidLoadNotification; +extern NSString* const CDVPluginHandleOpenURLNotification; +extern NSString* const CDVPluginResetNotification; +extern NSString* const CDVLocalNotification; +extern NSString* const CDVRemoteNotification; +extern NSString* const CDVRemoteNotificationError; +extern NSString* const CDVViewWillAppearNotification; +extern NSString* const CDVViewDidAppearNotification; +extern NSString* const CDVViewWillDisappearNotification; +extern NSString* const CDVViewDidDisappearNotification; +extern NSString* const CDVViewWillLayoutSubviewsNotification; +extern NSString* const CDVViewDidLayoutSubviewsNotification; +extern NSString* const CDVViewWillTransitionToSizeNotification; + +@interface CDVPlugin : NSObject {} + +@property (nonatomic, readonly, weak) UIView* webView; +@property (nonatomic, readonly, weak) id webViewEngine; + +@property (nonatomic, weak) UIViewController* viewController; +@property (nonatomic, weak) id commandDelegate; + +@property (readonly, assign) BOOL hasPendingOperation; + +- (void)pluginInitialize; + +- (void)handleOpenURL:(NSNotification*)notification; +- (void)onAppTerminate; +- (void)onMemoryWarning; +- (void)onReset; +- (void)dispose; + +/* + // see initWithWebView implementation + - (void) onPause {} + - (void) onResume {} + - (void) onOrientationWillChange {} + - (void) onOrientationDidChange {} + - (void)didReceiveLocalNotification:(NSNotification *)notification; + */ + +- (id)appDelegate; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.m new file mode 100755 index 0000000..af29cad --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPlugin.m @@ -0,0 +1,178 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPlugin.h" +#import "CDVPlugin+Private.h" +#import "CDVPlugin+Resources.h" +#import "CDVViewController.h" +#include + +@implementation UIView (org_apache_cordova_UIView_Extension) + +@dynamic scrollView; + +- (UIScrollView*)scrollView +{ + SEL scrollViewSelector = NSSelectorFromString(@"scrollView"); + + if ([self respondsToSelector:scrollViewSelector]) { + return ((id (*)(id, SEL))objc_msgSend)(self, scrollViewSelector); + } + + return nil; +} + +@end + +NSString* const CDVPageDidLoadNotification = @"CDVPageDidLoadNotification"; +NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification"; +NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification"; +NSString* const CDVLocalNotification = @"CDVLocalNotification"; +NSString* const CDVRemoteNotification = @"CDVRemoteNotification"; +NSString* const CDVRemoteNotificationError = @"CDVRemoteNotificationError"; +NSString* const CDVViewWillAppearNotification = @"CDVViewWillAppearNotification"; +NSString* const CDVViewDidAppearNotification = @"CDVViewDidAppearNotification"; +NSString* const CDVViewWillDisappearNotification = @"CDVViewWillDisappearNotification"; +NSString* const CDVViewDidDisappearNotification = @"CDVViewDidDisappearNotification"; +NSString* const CDVViewWillLayoutSubviewsNotification = @"CDVViewWillLayoutSubviewsNotification"; +NSString* const CDVViewDidLayoutSubviewsNotification = @"CDVViewDidLayoutSubviewsNotification"; +NSString* const CDVViewWillTransitionToSizeNotification = @"CDVViewWillTransitionToSizeNotification"; + +@interface CDVPlugin () + +@property (readwrite, assign) BOOL hasPendingOperation; +@property (nonatomic, readwrite, weak) id webViewEngine; + +@end + +@implementation CDVPlugin +@synthesize webViewEngine, viewController, commandDelegate, hasPendingOperation; +@dynamic webView; + +// Do not override these methods. Use pluginInitialize instead. +- (instancetype)initWithWebViewEngine:(id )theWebViewEngine +{ + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppTerminate) name:UIApplicationWillTerminateNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:theWebViewEngine.engineWebView]; + + self.webViewEngine = theWebViewEngine; + } + return self; +} + +- (void)pluginInitialize +{ + // You can listen to more app notifications, see: + // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4 + + // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler + + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; + + // Added in 2.3.0 + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil]; + + // Added in 2.5.0 + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView]; + //Added in 4.3.0 + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillAppear:) name:CDVViewWillAppearNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidAppear:) name:CDVViewDidAppearNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillDisappear:) name:CDVViewWillDisappearNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidDisappear:) name:CDVViewDidDisappearNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillLayoutSubviews:) name:CDVViewWillLayoutSubviewsNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDidLayoutSubviews:) name:CDVViewDidLayoutSubviewsNotification object:nil]; + // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewWillTransitionToSize:) name:CDVViewWillTransitionToSizeNotification object:nil]; +} + +- (void)dispose +{ + viewController = nil; + commandDelegate = nil; +} + +- (UIView*)webView +{ + if (self.webViewEngine != nil) { + return self.webViewEngine.engineWebView; + } + + return nil; +} + +/* +// NOTE: for onPause and onResume, calls into JavaScript must not call or trigger any blocking UI, like alerts +- (void) onPause {} +- (void) onResume {} +- (void) onOrientationWillChange {} +- (void) onOrientationDidChange {} +*/ + +/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */ +- (void)handleOpenURL:(NSNotification*)notification +{ + // override to handle urls sent to your app + // register your url schemes in your App-Info.plist + + NSURL* url = [notification object]; + + if ([url isKindOfClass:[NSURL class]]) { + /* Do your thing! */ + } +} + +/* NOTE: calls into JavaScript must not call or trigger any blocking UI, like alerts */ +- (void)onAppTerminate +{ + // override this if you need to do any cleanup on app exit +} + +- (void)onMemoryWarning +{ + // override to remove caches, etc +} + +- (void)onReset +{ + // Override to cancel any long-running requests when the WebView navigates or refreshes. +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; // this will remove all notification unless added using addObserverForName:object:queue:usingBlock: +} + +- (id)appDelegate +{ + return [[UIApplication sharedApplication] delegate]; +} + +// default implementation does nothing, ideally, we are not registered for notification if we aren't going to do anything. +// - (void)didReceiveLocalNotification:(NSNotification *)notification +// { +// // UILocalNotification* localNotification = [notification object]; // get the payload as a LocalNotification +// } + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.h new file mode 100755 index 0000000..56b8c23 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.h @@ -0,0 +1,66 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVAvailability.h" + +typedef enum { + CDVCommandStatus_NO_RESULT = 0, + CDVCommandStatus_OK, + CDVCommandStatus_CLASS_NOT_FOUND_EXCEPTION, + CDVCommandStatus_ILLEGAL_ACCESS_EXCEPTION, + CDVCommandStatus_INSTANTIATION_EXCEPTION, + CDVCommandStatus_MALFORMED_URL_EXCEPTION, + CDVCommandStatus_IO_EXCEPTION, + CDVCommandStatus_INVALID_ACTION, + CDVCommandStatus_JSON_EXCEPTION, + CDVCommandStatus_ERROR +} CDVCommandStatus; + +@interface CDVPluginResult : NSObject {} + +@property (nonatomic, strong, readonly) NSNumber* status; +@property (nonatomic, strong, readonly) id message; +@property (nonatomic, strong) NSNumber* keepCallback; +// This property can be used to scope the lifetime of another object. For example, +// Use it to store the associated NSData when `message` is created using initWithBytesNoCopy. +@property (nonatomic, strong) id associatedObject; + +- (CDVPluginResult*)init; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages; ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode; + ++ (void)setVerbose:(BOOL)verbose; ++ (BOOL)isVerbose; + +- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback; + +- (NSString*)argumentsAsJSON; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.m new file mode 100755 index 0000000..3521e6d --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVPluginResult.m @@ -0,0 +1,186 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVPluginResult.h" +#import "CDVJSON_private.h" +#import "CDVDebug.h" + +@interface CDVPluginResult () + +- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage; + +@end + +@implementation CDVPluginResult +@synthesize status, message, keepCallback, associatedObject; + +static NSArray* org_apache_cordova_CommandStatusMsgs; + +id messageFromArrayBuffer(NSData* data) +{ + return @{ + @"CDVType" : @"ArrayBuffer", + @"data" :[data base64EncodedStringWithOptions:0] + }; +} + +id massageMessage(id message) +{ + if ([message isKindOfClass:[NSData class]]) { + return messageFromArrayBuffer(message); + } + return message; +} + +id messageFromMultipart(NSArray* theMessages) +{ + NSMutableArray* messages = [NSMutableArray arrayWithArray:theMessages]; + + for (NSUInteger i = 0; i < messages.count; ++i) { + [messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])]; + } + + return @{ + @"CDVType" : @"MultiPart", + @"messages" : messages + }; +} + ++ (void)initialize +{ + org_apache_cordova_CommandStatusMsgs = [[NSArray alloc] initWithObjects:@"No result", + @"OK", + @"Class not found", + @"Illegal access", + @"Instantiation error", + @"Malformed url", + @"IO error", + @"Invalid action", + @"JSON error", + @"Error", + nil]; +} + +- (CDVPluginResult*)init +{ + return [self initWithStatus:CDVCommandStatus_NO_RESULT message:nil]; +} + +- (CDVPluginResult*)initWithStatus:(CDVCommandStatus)statusOrdinal message:(id)theMessage +{ + self = [super init]; + if (self) { + status = [NSNumber numberWithInt:statusOrdinal]; + message = theMessage; + keepCallback = [NSNumber numberWithBool:NO]; + } + return self; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal +{ + return [[self alloc] initWithStatus:statusOrdinal message:nil]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsString:(NSString*)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArray:(NSArray*)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsInt:(int)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInt:theMessage]]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSInteger:(NSInteger)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithInteger:theMessage]]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsNSUInteger:(NSUInteger)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithUnsignedInteger:theMessage]]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDouble:(double)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithDouble:theMessage]]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:[NSNumber numberWithBool:theMessage]]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:theMessage]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage +{ + return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages +{ + return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)]; +} + ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode +{ + NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]}; + + return [[self alloc] initWithStatus:statusOrdinal message:errDict]; +} + +- (void)setKeepCallbackAsBool:(BOOL)bKeepCallback +{ + [self setKeepCallback:[NSNumber numberWithBool:bKeepCallback]]; +} + +- (NSString*)argumentsAsJSON +{ + id arguments = (self.message == nil ? [NSNull null] : self.message); + NSArray* argumentsWrappedInArray = [NSArray arrayWithObject:arguments]; + + NSString* argumentsJSON = [argumentsWrappedInArray cdv_JSONString]; + + argumentsJSON = [argumentsJSON substringWithRange:NSMakeRange(1, [argumentsJSON length] - 2)]; + + return argumentsJSON; +} + +static BOOL gIsVerbose = NO; ++ (void)setVerbose:(BOOL)verbose +{ + gIsVerbose = verbose; +} + ++ (BOOL)isVerbose +{ + return gIsVerbose; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVScreenOrientationDelegate.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVScreenOrientationDelegate.h new file mode 100755 index 0000000..7226205 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVScreenOrientationDelegate.h @@ -0,0 +1,28 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@protocol CDVScreenOrientationDelegate + +- (NSUInteger)supportedInterfaceOrientations; +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; +- (BOOL)shouldAutorotate; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.h new file mode 100755 index 0000000..6d31593 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.h @@ -0,0 +1,27 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@interface CDVTimer : NSObject + ++ (void)start:(NSString*)name; ++ (void)stop:(NSString*)name; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.m new file mode 100755 index 0000000..784e94d --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVTimer.m @@ -0,0 +1,123 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVTimer.h" + +#pragma mark CDVTimerItem + +@interface CDVTimerItem : NSObject + +@property (nonatomic, strong) NSString* name; +@property (nonatomic, strong) NSDate* started; +@property (nonatomic, strong) NSDate* ended; + +- (void)log; + +@end + +@implementation CDVTimerItem + +- (void)log +{ + NSLog(@"[CDVTimer][%@] %fms", self.name, [self.ended timeIntervalSinceDate:self.started] * 1000.0); +} + +@end + +#pragma mark CDVTimer + +@interface CDVTimer () + +@property (nonatomic, strong) NSMutableDictionary* items; + +@end + +@implementation CDVTimer + +#pragma mark object methods + +- (id)init +{ + if (self = [super init]) { + self.items = [NSMutableDictionary dictionaryWithCapacity:6]; + } + + return self; +} + +- (void)add:(NSString*)name +{ + if ([self.items objectForKey:[name lowercaseString]] == nil) { + CDVTimerItem* item = [CDVTimerItem new]; + item.name = name; + item.started = [NSDate new]; + [self.items setObject:item forKey:[name lowercaseString]]; + } else { + NSLog(@"Timer called '%@' already exists.", name); + } +} + +- (void)remove:(NSString*)name +{ + CDVTimerItem* item = [self.items objectForKey:[name lowercaseString]]; + + if (item != nil) { + item.ended = [NSDate new]; + [item log]; + [self.items removeObjectForKey:[name lowercaseString]]; + } else { + NSLog(@"Timer called '%@' does not exist.", name); + } +} + +- (void)removeAll +{ + [self.items removeAllObjects]; +} + +#pragma mark class methods + ++ (void)start:(NSString*)name +{ + [[CDVTimer sharedInstance] add:name]; +} + ++ (void)stop:(NSString*)name +{ + [[CDVTimer sharedInstance] remove:name]; +} + ++ (void)clearAll +{ + [[CDVTimer sharedInstance] removeAll]; +} + ++ (CDVTimer*)sharedInstance +{ + static dispatch_once_t pred = 0; + __strong static CDVTimer* _sharedObject = nil; + + dispatch_once(&pred, ^{ + _sharedObject = [[self alloc] init]; + }); + + return _sharedObject; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.h new file mode 100755 index 0000000..0561e04 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.h @@ -0,0 +1,27 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDVAvailability.h" + +@class CDVViewController; + +@interface CDVURLProtocol : NSURLProtocol {} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.m new file mode 100755 index 0000000..7b2c5ce --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVURLProtocol.m @@ -0,0 +1,113 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import +#import +#import +#import "CDVURLProtocol.h" +#import "CDVCommandQueue.h" +#import "CDVViewController.h" + +// Contains a set of NSNumbers of addresses of controllers. It doesn't store +// the actual pointer to avoid retaining. +static NSMutableSet* gRegisteredControllers = nil; + +NSString* const kCDVAssetsLibraryPrefixes = @"assets-library://"; + +@implementation CDVURLProtocol + + ++ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest +{ + NSURL* theUrl = [theRequest URL]; + + if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefixes]) { + return YES; + } + + return NO; +} + ++ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request +{ + // NSLog(@"%@ received %@", self, NSStringFromSelector(_cmd)); + return request; +} + +- (void)startLoading +{ + // NSLog(@"%@ received %@ - start", self, NSStringFromSelector(_cmd)); + NSURL* url = [[self request] URL]; + + if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefixes]) { + ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) { + if (asset) { + // We have the asset! Get the data and send it along. + ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; + NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType); + Byte* buffer = (Byte*)malloc((unsigned long)[assetRepresentation size]); + NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:(NSUInteger)[assetRepresentation size] error:nil]; + NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; + [self sendResponseWithResponseCode:200 data:data mimeType:MIMEType]; + } else { + // Retrieving the asset failed for some reason. Send an error. + [self sendResponseWithResponseCode:404 data:nil mimeType:nil]; + } + }; + ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) { + // Retrieving the asset failed for some reason. Send an error. + [self sendResponseWithResponseCode:401 data:nil mimeType:nil]; + }; + + ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; + [assetsLibrary assetForURL:url resultBlock:resultBlock failureBlock:failureBlock]; + return; + } + + NSString* body = [NSString stringWithFormat:@"Access not allowed to URL: %@", url]; + [self sendResponseWithResponseCode:401 data:[body dataUsingEncoding:NSASCIIStringEncoding] mimeType:nil]; +} + +- (void)stopLoading +{ + // do any cleanup here +} + ++ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)requestA toRequest:(NSURLRequest*)requestB +{ + return NO; +} + +- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType +{ + if (mimeType == nil) { + mimeType = @"text/plain"; + } + + NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] initWithURL:[[self request] URL] statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:@{@"Content-Type" : mimeType}]; + + [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + if (data != nil) { + [[self client] URLProtocol:self didLoadData:data]; + } + [[self client] URLProtocolDidFinishLoading:self]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.h new file mode 100755 index 0000000..4de382f --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.h @@ -0,0 +1,27 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@interface CDVUserAgentUtil : NSObject ++ (NSString*)originalUserAgent; ++ (void)acquireLock:(void (^)(NSInteger lockToken))block; ++ (void)releaseLock:(NSInteger*)lockToken; ++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken; +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.m new file mode 100755 index 0000000..c3402d0 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVUserAgentUtil.m @@ -0,0 +1,122 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVUserAgentUtil.h" + +#import + +// #define VerboseLog NSLog +#define VerboseLog(...) do {} while (0) + +static NSString* const kCdvUserAgentKey = @"Cordova-User-Agent"; +static NSString* const kCdvUserAgentVersionKey = @"Cordova-User-Agent-Version"; + +static NSString* gOriginalUserAgent = nil; +static NSInteger gNextLockToken = 0; +static NSInteger gCurrentLockToken = 0; +static NSMutableArray* gPendingSetUserAgentBlocks = nil; + +@implementation CDVUserAgentUtil + ++ (NSString*)originalUserAgent +{ + if (gOriginalUserAgent == nil) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppLocaleDidChange:) + name:NSCurrentLocaleDidChangeNotification object:nil]; + + NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; + NSString* systemVersion = [[UIDevice currentDevice] systemVersion]; + NSString* localeStr = [[NSLocale currentLocale] localeIdentifier]; + // Record the model since simulator can change it without re-install (CB-5420). + NSString* model = [UIDevice currentDevice].model; + NSString* systemAndLocale = [NSString stringWithFormat:@"%@ %@ %@", model, systemVersion, localeStr]; + + NSString* cordovaUserAgentVersion = [userDefaults stringForKey:kCdvUserAgentVersionKey]; + gOriginalUserAgent = [userDefaults stringForKey:kCdvUserAgentKey]; + BOOL cachedValueIsOld = ![systemAndLocale isEqualToString:cordovaUserAgentVersion]; + + if ((gOriginalUserAgent == nil) || cachedValueIsOld) { + UIWebView* sampleWebView = [[UIWebView alloc] initWithFrame:CGRectZero]; + gOriginalUserAgent = [sampleWebView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; + + [userDefaults setObject:gOriginalUserAgent forKey:kCdvUserAgentKey]; + [userDefaults setObject:systemAndLocale forKey:kCdvUserAgentVersionKey]; + + [userDefaults synchronize]; + } + } + return gOriginalUserAgent; +} + ++ (void)onAppLocaleDidChange:(NSNotification*)notification +{ + // TODO: We should figure out how to update the user-agent of existing UIWebViews when this happens. + // Maybe use the PDF bug (noted in setUserAgent:). + gOriginalUserAgent = nil; +} + ++ (void)acquireLock:(void (^)(NSInteger lockToken))block +{ + if (gCurrentLockToken == 0) { + gCurrentLockToken = ++gNextLockToken; + VerboseLog(@"Gave lock %d", gCurrentLockToken); + block(gCurrentLockToken); + } else { + if (gPendingSetUserAgentBlocks == nil) { + gPendingSetUserAgentBlocks = [[NSMutableArray alloc] initWithCapacity:4]; + } + VerboseLog(@"Waiting for lock"); + [gPendingSetUserAgentBlocks addObject:block]; + } +} + ++ (void)releaseLock:(NSInteger*)lockToken +{ + if (*lockToken == 0) { + return; + } + NSAssert(gCurrentLockToken == *lockToken, @"Got token %ld, expected %ld", (long)*lockToken, (long)gCurrentLockToken); + + VerboseLog(@"Released lock %d", *lockToken); + if ([gPendingSetUserAgentBlocks count] > 0) { + void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0]; + [gPendingSetUserAgentBlocks removeObjectAtIndex:0]; + gCurrentLockToken = ++gNextLockToken; + NSLog(@"Gave lock %ld", (long)gCurrentLockToken); + block(gCurrentLockToken); + } else { + gCurrentLockToken = 0; + } + *lockToken = 0; +} + ++ (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken +{ + NSAssert(gCurrentLockToken == lockToken, @"Got token %ld, expected %ld", (long)lockToken, (long)gCurrentLockToken); + VerboseLog(@"User-Agent set to: %@", value); + + // Setting the UserAgent must occur before a UIWebView is instantiated. + // It is read per instantiation, so it does not affect previously created views. + // Except! When a PDF is loaded, all currently active UIWebViews reload their + // User-Agent from the NSUserDefaults some time after the DidFinishLoad of the PDF bah! + NSDictionary* dict = [[NSDictionary alloc] initWithObjectsAndKeys:value, @"UserAgent", nil]; + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.h new file mode 100755 index 0000000..90d33d2 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.h @@ -0,0 +1,91 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import +#import "CDVAvailability.h" +#import "CDVInvokedUrlCommand.h" +#import "CDVCommandDelegate.h" +#import "CDVCommandQueue.h" +#import "CDVScreenOrientationDelegate.h" +#import "CDVPlugin.h" +#import "CDVWebViewEngineProtocol.h" + +@interface CDVViewController : UIViewController { + @protected + id _webViewEngine; + @protected + id _commandDelegate; + @protected + CDVCommandQueue* _commandQueue; + NSString* _userAgent; +} + +@property (nonatomic, readonly, weak) IBOutlet UIView* webView; + +@property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects; +@property (nonatomic, readonly, strong) NSDictionary* pluginsMap; +@property (nonatomic, readonly, strong) NSMutableDictionary* settings; +@property (nonatomic, readonly, strong) NSXMLParser* configParser; + +@property (nonatomic, readwrite, copy) NSString* configFile; +@property (nonatomic, readwrite, copy) NSString* wwwFolderName; +@property (nonatomic, readwrite, copy) NSString* startPage; +@property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue; +@property (nonatomic, readonly, strong) id webViewEngine; +@property (nonatomic, readonly, strong) id commandDelegate; + +/** + The complete user agent that Cordova will use when sending web requests. + */ +@property (nonatomic, readonly) NSString* userAgent; + +/** + The base user agent data that Cordova will use to build its user agent. If this + property isn't set, Cordova will use the standard web view user agent as its + base. + */ +@property (nonatomic, readwrite, copy) NSString* baseUserAgent; + +/** + Takes/Gives an array of UIInterfaceOrientation (int) objects + ex. UIInterfaceOrientationPortrait +*/ +@property (nonatomic, readwrite, strong) NSArray* supportedOrientations; + +/** + The address of the lock token used for controlling access to setting the user-agent + */ +@property (nonatomic, readonly) NSInteger* userAgentLockToken; + +- (UIView*)newCordovaViewWithFrame:(CGRect)bounds; + +- (NSString*)appURLScheme; +- (NSURL*)errorURL; + +- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations; +- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation; + +- (id)getCommandInstance:(NSString*)pluginName; +- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className; +- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName; + +- (void)parseSettingsWithParser:(NSObject *)delegate; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.m new file mode 100755 index 0000000..4019c20 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVViewController.m @@ -0,0 +1,719 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import "CDV.h" +#import "CDVPlugin+Private.h" +#import "CDVUIWebViewDelegate.h" +#import "CDVConfigParser.h" +#import "CDVUserAgentUtil.h" +#import +#import "NSDictionary+CordovaPreferences.h" +#import "CDVLocalStorage.h" +#import "CDVCommandDelegateImpl.h" + +@interface CDVViewController () { + NSInteger _userAgentLockToken; +} + +@property (nonatomic, readwrite, strong) NSXMLParser* configParser; +@property (nonatomic, readwrite, strong) NSMutableDictionary* settings; +@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects; +@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames; +@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap; +@property (nonatomic, readwrite, strong) id webViewEngine; + +@property (readwrite, assign) BOOL initialized; + +@property (atomic, strong) NSURL* openURL; + +@end + +@implementation CDVViewController + +@synthesize supportedOrientations; +@synthesize pluginObjects, pluginsMap, startupPluginNames; +@synthesize configParser, settings; +@synthesize wwwFolderName, startPage, initialized, openURL, baseUserAgent; +@synthesize commandDelegate = _commandDelegate; +@synthesize commandQueue = _commandQueue; +@synthesize webViewEngine = _webViewEngine; +@dynamic webView; + +- (void)__init +{ + if ((self != nil) && !self.initialized) { + _commandQueue = [[CDVCommandQueue alloc] initWithViewController:self]; + _commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:) + name:UIApplicationWillTerminateNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:) + name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidBecomeActive:) + name:UIApplicationDidBecomeActiveNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification object:nil]; + + // read from UISupportedInterfaceOrientations (or UISupportedInterfaceOrientations~iPad, if its iPad) from -Info.plist + self.supportedOrientations = [self parseInterfaceOrientations: + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UISupportedInterfaceOrientations"]]; + + [self printVersion]; + [self printMultitaskingInfo]; + [self printPlatformVersionWarning]; + self.initialized = YES; + } +} + +- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + [self __init]; + return self; +} + +- (id)initWithCoder:(NSCoder*)aDecoder +{ + self = [super initWithCoder:aDecoder]; + [self __init]; + return self; +} + +- (id)init +{ + self = [super init]; + [self __init]; + return self; +} + +- (void)printVersion +{ + NSLog(@"Apache Cordova native platform version %@ is starting.", CDV_VERSION); +} + +- (void)printPlatformVersionWarning +{ + if (!IsAtLeastiOSVersion(@"8.0")) { + NSLog(@"CRITICAL: For Cordova 4.0.0 and above, you will need to upgrade to at least iOS 8.0 or greater. Your current version of iOS is %@.", + [[UIDevice currentDevice] systemVersion] + ); + } +} + +- (void)printMultitaskingInfo +{ + UIDevice* device = [UIDevice currentDevice]; + BOOL backgroundSupported = NO; + + if ([device respondsToSelector:@selector(isMultitaskingSupported)]) { + backgroundSupported = device.multitaskingSupported; + } + + NSNumber* exitsOnSuspend = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIApplicationExitsOnSuspend"]; + if (exitsOnSuspend == nil) { // if it's missing, it should be NO (i.e. multi-tasking on by default) + exitsOnSuspend = [NSNumber numberWithBool:NO]; + } + + NSLog(@"Multi-tasking -> Device: %@, App: %@", (backgroundSupported ? @"YES" : @"NO"), (![exitsOnSuspend intValue]) ? @"YES" : @"NO"); +} + +-(NSString*)configFilePath{ + NSString* path = self.configFile ?: @"config.xml"; + + // if path is relative, resolve it against the main bundle + if(![path isAbsolutePath]){ + NSString* absolutePath = [[NSBundle mainBundle] pathForResource:path ofType:nil]; + if(!absolutePath){ + NSAssert(NO, @"ERROR: %@ not found in the main bundle!", path); + } + path = absolutePath; + } + + // Assert file exists + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + NSAssert(NO, @"ERROR: %@ does not exist. Please run cordova-ios/bin/cordova_plist_to_config_xml path/to/project.", path); + return nil; + } + + return path; +} + +- (void)parseSettingsWithParser:(NSObject *)delegate +{ + // read from config.xml in the app bundle + NSString* path = [self configFilePath]; + + NSURL* url = [NSURL fileURLWithPath:path]; + + self.configParser = [[NSXMLParser alloc] initWithContentsOfURL:url]; + if (self.configParser == nil) { + NSLog(@"Failed to initialize XML parser."); + return; + } + [self.configParser setDelegate:((id < NSXMLParserDelegate >)delegate)]; + [self.configParser parse]; +} + +- (void)loadSettings +{ + CDVConfigParser* delegate = [[CDVConfigParser alloc] init]; + + [self parseSettingsWithParser:delegate]; + + // Get the plugin dictionary, whitelist and settings from the delegate. + self.pluginsMap = delegate.pluginsDict; + self.startupPluginNames = delegate.startupPluginNames; + self.settings = delegate.settings; + + // And the start folder/page. + if(self.wwwFolderName == nil){ + self.wwwFolderName = @"www"; + } + if(delegate.startPage && self.startPage == nil){ + self.startPage = delegate.startPage; + } + if (self.startPage == nil) { + self.startPage = @"index.html"; + } + + // Initialize the plugin objects dict. + self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20]; +} + +- (NSURL*)appUrl +{ + NSURL* appURL = nil; + + if ([self.startPage rangeOfString:@"://"].location != NSNotFound) { + appURL = [NSURL URLWithString:self.startPage]; + } else if ([self.wwwFolderName rangeOfString:@"://"].location != NSNotFound) { + appURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.wwwFolderName, self.startPage]]; + } else if([self.wwwFolderName hasSuffix:@".bundle"]){ + // www folder is actually a bundle + NSBundle* bundle = [NSBundle bundleWithPath:self.wwwFolderName]; + appURL = [bundle URLForResource:self.startPage withExtension:nil]; + } else if([self.wwwFolderName hasSuffix:@".framework"]){ + // www folder is actually a framework + NSBundle* bundle = [NSBundle bundleWithPath:self.wwwFolderName]; + appURL = [bundle URLForResource:self.startPage withExtension:nil]; + } else { + // CB-3005 strip parameters from start page to check if page exists in resources + NSURL* startURL = [NSURL URLWithString:self.startPage]; + NSString* startFilePath = [self.commandDelegate pathForResource:[startURL path]]; + + if (startFilePath == nil) { + appURL = nil; + } else { + appURL = [NSURL fileURLWithPath:startFilePath]; + // CB-3005 Add on the query params or fragment. + NSString* startPageNoParentDirs = self.startPage; + NSRange r = [startPageNoParentDirs rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"?#"] options:0]; + if (r.location != NSNotFound) { + NSString* queryAndOrFragment = [self.startPage substringFromIndex:r.location]; + appURL = [NSURL URLWithString:queryAndOrFragment relativeToURL:appURL]; + } + } + } + + return appURL; +} + +- (NSURL*)errorURL +{ + NSURL* errorUrl = nil; + + id setting = [self.settings cordovaSettingForKey:@"ErrorUrl"]; + + if (setting) { + NSString* errorUrlString = (NSString*)setting; + if ([errorUrlString rangeOfString:@"://"].location != NSNotFound) { + errorUrl = [NSURL URLWithString:errorUrlString]; + } else { + NSURL* url = [NSURL URLWithString:(NSString*)setting]; + NSString* errorFilePath = [self.commandDelegate pathForResource:[url path]]; + if (errorFilePath) { + errorUrl = [NSURL fileURLWithPath:errorFilePath]; + } + } + } + + return errorUrl; +} + +- (UIView*)webView +{ + if (self.webViewEngine != nil) { + return self.webViewEngine.engineWebView; + } + + return nil; +} + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Load settings + [self loadSettings]; + + NSString* backupWebStorageType = @"cloud"; // default value + + id backupWebStorage = [self.settings cordovaSettingForKey:@"BackupWebStorage"]; + if ([backupWebStorage isKindOfClass:[NSString class]]) { + backupWebStorageType = backupWebStorage; + } + [self.settings setCordovaSetting:backupWebStorageType forKey:@"BackupWebStorage"]; + + [CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType]; + + // // Instantiate the WebView /////////////// + + if (!self.webView) { + [self createGapView]; + } + + // ///////////////// + + /* + * Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup. + With minimum iOS 7/8 supported, only first clause applies. + */ + if ([backupWebStorageType isEqualToString:@"local"]) { + NSString* localStorageFeatureName = @"localstorage"; + if ([self.pluginsMap objectForKey:localStorageFeatureName]) { // plugin specified in config + [self.startupPluginNames addObject:localStorageFeatureName]; + } + } + + if ([self.startupPluginNames count] > 0) { + [CDVTimer start:@"TotalPluginStartup"]; + + for (NSString* pluginName in self.startupPluginNames) { + [CDVTimer start:pluginName]; + [self getCommandInstance:pluginName]; + [CDVTimer stop:pluginName]; + } + + [CDVTimer stop:@"TotalPluginStartup"]; + } + + // ///////////////// + NSURL* appURL = [self appUrl]; + + [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) { + _userAgentLockToken = lockToken; + [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken]; + if (appURL) { + NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0]; + [self.webViewEngine loadRequest:appReq]; + } else { + NSString* loadErr = [NSString stringWithFormat:@"ERROR: Start Page at '%@/%@' was not found.", self.wwwFolderName, self.startPage]; + NSLog(@"%@", loadErr); + + NSURL* errorUrl = [self errorURL]; + if (errorUrl) { + errorUrl = [NSURL URLWithString:[NSString stringWithFormat:@"?error=%@", [loadErr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] relativeToURL:errorUrl]; + NSLog(@"%@", [errorUrl absoluteString]); + [self.webViewEngine loadRequest:[NSURLRequest requestWithURL:errorUrl]]; + } else { + NSString* html = [NSString stringWithFormat:@" %@ ", loadErr]; + [self.webViewEngine loadHTMLString:html baseURL:nil]; + } + } + }]; +} + +-(void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillAppearNotification object:nil]]; +} + +-(void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidAppearNotification object:nil]]; +} + +-(void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillDisappearNotification object:nil]]; +} + +-(void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidDisappearNotification object:nil]]; +} + +-(void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillLayoutSubviewsNotification object:nil]]; +} + +-(void)viewDidLayoutSubviews +{ + [super viewDidLayoutSubviews]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewDidLayoutSubviewsNotification object:nil]]; +} + +-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator +{ + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVViewWillTransitionToSizeNotification object:[NSValue valueWithCGSize:size]]]; +} + +- (NSArray*)parseInterfaceOrientations:(NSArray*)orientations +{ + NSMutableArray* result = [[NSMutableArray alloc] init]; + + if (orientations != nil) { + NSEnumerator* enumerator = [orientations objectEnumerator]; + NSString* orientationString; + + while (orientationString = [enumerator nextObject]) { + if ([orientationString isEqualToString:@"UIInterfaceOrientationPortrait"]) { + [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]]; + } else if ([orientationString isEqualToString:@"UIInterfaceOrientationPortraitUpsideDown"]) { + [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortraitUpsideDown]]; + } else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeLeft"]) { + [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft]]; + } else if ([orientationString isEqualToString:@"UIInterfaceOrientationLandscapeRight"]) { + [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationLandscapeRight]]; + } + } + } + + // default + if ([result count] == 0) { + [result addObject:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]]; + } + + return result; +} + +- (BOOL)shouldAutorotate +{ + return YES; +} + +- (NSUInteger)supportedInterfaceOrientations +{ + NSUInteger ret = 0; + + if ([self supportsOrientation:UIInterfaceOrientationPortrait]) { + ret = ret | (1 << UIInterfaceOrientationPortrait); + } + if ([self supportsOrientation:UIInterfaceOrientationPortraitUpsideDown]) { + ret = ret | (1 << UIInterfaceOrientationPortraitUpsideDown); + } + if ([self supportsOrientation:UIInterfaceOrientationLandscapeRight]) { + ret = ret | (1 << UIInterfaceOrientationLandscapeRight); + } + if ([self supportsOrientation:UIInterfaceOrientationLandscapeLeft]) { + ret = ret | (1 << UIInterfaceOrientationLandscapeLeft); + } + + return ret; +} + +- (BOOL)supportsOrientation:(UIInterfaceOrientation)orientation +{ + return [self.supportedOrientations containsObject:[NSNumber numberWithInt:orientation]]; +} + +- (UIView*)newCordovaViewWithFrame:(CGRect)bounds +{ + NSString* defaultWebViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaDefaultWebViewEngine"]; + NSString* webViewEngineClass = [self.settings cordovaSettingForKey:@"CordovaWebViewEngine"]; + + if (!defaultWebViewEngineClass) { + defaultWebViewEngineClass = @"CDVUIWebViewEngine"; + } + if (!webViewEngineClass) { + webViewEngineClass = defaultWebViewEngineClass; + } + + // Find webViewEngine + if (NSClassFromString(webViewEngineClass)) { + self.webViewEngine = [[NSClassFromString(webViewEngineClass) alloc] initWithFrame:bounds]; + // if a webView engine returns nil (not supported by the current iOS version) or doesn't conform to the protocol, or can't load the request, we use UIWebView + if (!self.webViewEngine || ![self.webViewEngine conformsToProtocol:@protocol(CDVWebViewEngineProtocol)] || ![self.webViewEngine canLoadRequest:[NSURLRequest requestWithURL:self.appUrl]]) { + self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds]; + } + } else { + self.webViewEngine = [[NSClassFromString(defaultWebViewEngineClass) alloc] initWithFrame:bounds]; + } + + if ([self.webViewEngine isKindOfClass:[CDVPlugin class]]) { + [self registerPlugin:(CDVPlugin*)self.webViewEngine withClassName:webViewEngineClass]; + } + + return self.webViewEngine.engineWebView; +} + +- (NSString*)userAgent +{ + if (_userAgent != nil) { + return _userAgent; + } + + NSString* localBaseUserAgent; + if (self.baseUserAgent != nil) { + localBaseUserAgent = self.baseUserAgent; + } else if ([self.settings cordovaSettingForKey:@"OverrideUserAgent"] != nil) { + localBaseUserAgent = [self.settings cordovaSettingForKey:@"OverrideUserAgent"]; + } else { + localBaseUserAgent = [CDVUserAgentUtil originalUserAgent]; + } + NSString* appendUserAgent = [self.settings cordovaSettingForKey:@"AppendUserAgent"]; + if (appendUserAgent) { + _userAgent = [NSString stringWithFormat:@"%@ %@", localBaseUserAgent, appendUserAgent]; + } else { + // Use our address as a unique number to append to the User-Agent. + _userAgent = [NSString stringWithFormat:@"%@ (%lld)", localBaseUserAgent, (long long)self]; + } + return _userAgent; +} + +- (void)createGapView +{ + CGRect webViewBounds = self.view.bounds; + + webViewBounds.origin = self.view.bounds.origin; + + UIView* view = [self newCordovaViewWithFrame:webViewBounds]; + + view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self.view addSubview:view]; + [self.view sendSubviewToBack:view]; +} + +- (void)didReceiveMemoryWarning +{ + // iterate through all the plugin objects, and call hasPendingOperation + // if at least one has a pending operation, we don't call [super didReceiveMemoryWarning] + + NSEnumerator* enumerator = [self.pluginObjects objectEnumerator]; + CDVPlugin* plugin; + + BOOL doPurge = YES; + + while ((plugin = [enumerator nextObject])) { + if (plugin.hasPendingOperation) { + NSLog(@"Plugin '%@' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class])); + doPurge = NO; + } + } + + if (doPurge) { + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + } + + // Release any cached data, images, etc. that aren't in use. +} + +- (void)viewDidUnload +{ + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; + + [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; + + [super viewDidUnload]; +} + +#pragma mark CordovaCommands + +- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className +{ + if ([plugin respondsToSelector:@selector(setViewController:)]) { + [plugin setViewController:self]; + } + + if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) { + [plugin setCommandDelegate:_commandDelegate]; + } + + [self.pluginObjects setObject:plugin forKey:className]; + [plugin pluginInitialize]; +} + +- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName +{ + if ([plugin respondsToSelector:@selector(setViewController:)]) { + [plugin setViewController:self]; + } + + if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) { + [plugin setCommandDelegate:_commandDelegate]; + } + + NSString* className = NSStringFromClass([plugin class]); + [self.pluginObjects setObject:plugin forKey:className]; + [self.pluginsMap setValue:className forKey:[pluginName lowercaseString]]; + [plugin pluginInitialize]; +} + +/** + Returns an instance of a CordovaCommand object, based on its name. If one exists already, it is returned. + */ +- (id)getCommandInstance:(NSString*)pluginName +{ + // first, we try to find the pluginName in the pluginsMap + // (acts as a whitelist as well) if it does not exist, we return nil + // NOTE: plugin names are matched as lowercase to avoid problems - however, a + // possible issue is there can be duplicates possible if you had: + // "org.apache.cordova.Foo" and "org.apache.cordova.foo" - only the lower-cased entry will match + NSString* className = [self.pluginsMap objectForKey:[pluginName lowercaseString]]; + + if (className == nil) { + return nil; + } + + id obj = [self.pluginObjects objectForKey:className]; + if (!obj) { + obj = [[NSClassFromString(className)alloc] initWithWebViewEngine:_webViewEngine]; + + if (obj != nil) { + [self registerPlugin:obj withClassName:className]; + } else { + NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName); + } + } + return obj; +} + +#pragma mark - + +- (NSString*)appURLScheme +{ + NSString* URLScheme = nil; + + NSArray* URLTypes = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleURLTypes"]; + + if (URLTypes != nil) { + NSDictionary* dict = [URLTypes objectAtIndex:0]; + if (dict != nil) { + NSArray* URLSchemes = [dict objectForKey:@"CFBundleURLSchemes"]; + if (URLSchemes != nil) { + URLScheme = [URLSchemes objectAtIndex:0]; + } + } + } + + return URLScheme; +} + +#pragma mark - +#pragma mark UIApplicationDelegate impl + +/* + This method lets your application know that it is about to be terminated and purged from memory entirely + */ +- (void)onAppWillTerminate:(NSNotification*)notification +{ + // empty the tmp directory + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + NSError* __autoreleasing err = nil; + + // clear contents of NSTemporaryDirectory + NSString* tempDirectoryPath = NSTemporaryDirectory(); + NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath]; + NSString* fileName = nil; + BOOL result; + + while ((fileName = [directoryEnumerator nextObject])) { + NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName]; + result = [fileMgr removeItemAtPath:filePath error:&err]; + if (!result && err) { + NSLog(@"Failed to delete: %@ (error: %@)", filePath, err); + } + } +} + +/* + This method is called to let your application know that it is about to move from the active to inactive state. + You should use this method to pause ongoing tasks, disable timer, ... + */ +- (void)onAppWillResignActive:(NSNotification*)notification +{ + // NSLog(@"%@",@"applicationWillResignActive"); + [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resign');" scheduledOnRunLoop:NO]; +} + +/* + In iOS 4.0 and later, this method is called as part of the transition from the background to the inactive state. + You can use this method to undo many of the changes you made to your application upon entering the background. + invariably followed by applicationDidBecomeActive + */ +- (void)onAppWillEnterForeground:(NSNotification*)notification +{ + // NSLog(@"%@",@"applicationWillEnterForeground"); + [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('resume');"]; + + /** Clipboard fix **/ + UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; + NSString* string = pasteboard.string; + if (string) { + [pasteboard setValue:string forPasteboardType:@"public.text"]; + } +} + +// This method is called to let your application know that it moved from the inactive to active state. +- (void)onAppDidBecomeActive:(NSNotification*)notification +{ + // NSLog(@"%@",@"applicationDidBecomeActive"); + [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('active');"]; +} + +/* + In iOS 4.0 and later, this method is called instead of the applicationWillTerminate: method + when the user quits an application that supports background execution. + */ +- (void)onAppDidEnterBackground:(NSNotification*)notification +{ + // NSLog(@"%@",@"applicationDidEnterBackground"); + [self.commandDelegate evalJs:@"cordova.fireDocumentEvent('pause', null, true);" scheduledOnRunLoop:NO]; +} + +// /////////////////////// + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [CDVUserAgentUtil releaseLock:&_userAgentLockToken]; + [_commandQueue dispose]; + [[self.pluginObjects allValues] makeObjectsPerformSelector:@selector(dispose)]; +} + +- (NSInteger*)userAgentLockToken +{ + return &_userAgentLockToken; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWebViewEngineProtocol.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWebViewEngineProtocol.h new file mode 100755 index 0000000..34d07f3 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWebViewEngineProtocol.h @@ -0,0 +1,42 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +#define kCDVWebViewEngineScriptMessageHandlers @"kCDVWebViewEngineScriptMessageHandlers" +#define kCDVWebViewEngineUIWebViewDelegate @"kCDVWebViewEngineUIWebViewDelegate" +#define kCDVWebViewEngineWKNavigationDelegate @"kCDVWebViewEngineWKNavigationDelegate" +#define kCDVWebViewEngineWKUIDelegate @"kCDVWebViewEngineWKUIDelegate" +#define kCDVWebViewEngineWebViewPreferences @"kCDVWebViewEngineWebViewPreferences" + +@protocol CDVWebViewEngineProtocol + +@property (nonatomic, strong, readonly) UIView* engineWebView; + +- (id)loadRequest:(NSURLRequest*)request; +- (id)loadHTMLString:(NSString*)string baseURL:(NSURL*)baseURL; +- (void)evaluateJavaScript:(NSString*)javaScriptString completionHandler:(void (^)(id, NSError*))completionHandler; + +- (NSURL*)URL; +- (BOOL)canLoadRequest:(NSURLRequest*)request; + +- (instancetype)initWithFrame:(CGRect)frame; +- (void)updateWithInfo:(NSDictionary*)info; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.h new file mode 100755 index 0000000..9165097 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.h @@ -0,0 +1,34 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +extern NSString* const kCDVDefaultWhitelistRejectionString; + +@interface CDVWhitelist : NSObject + +@property (nonatomic, copy) NSString* whitelistRejectionFormatString; + +- (id)initWithArray:(NSArray*)array; +- (BOOL)schemeIsAllowed:(NSString*)scheme; +- (BOOL)URLIsAllowed:(NSURL*)url; +- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure; +- (NSString*)errorStringForURL:(NSURL*)url; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.m new file mode 100755 index 0000000..552ea95 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/CDVWhitelist.m @@ -0,0 +1,285 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVWhitelist.h" + +NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'"; +NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme"; + +@interface CDVWhitelistPattern : NSObject { + @private + NSRegularExpression* _scheme; + NSRegularExpression* _host; + NSNumber* _port; + NSRegularExpression* _path; +} + ++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards; +- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path; +- (bool)matches:(NSURL*)url; + +@end + +@implementation CDVWhitelistPattern + ++ (NSString*)regexFromPattern:(NSString*)pattern allowWildcards:(bool)allowWildcards +{ + NSString* regex = [NSRegularExpression escapedPatternForString:pattern]; + + if (allowWildcards) { + regex = [regex stringByReplacingOccurrencesOfString:@"\\*" withString:@".*"]; + + /* [NSURL path] has the peculiarity that a trailing slash at the end of a path + * will be omitted. This regex tweak compensates for that. + */ + if ([regex hasSuffix:@"\\/.*"]) { + regex = [NSString stringWithFormat:@"%@(\\/.*)?", [regex substringToIndex:([regex length] - 4)]]; + } + } + return [NSString stringWithFormat:@"%@$", regex]; +} + +- (id)initWithScheme:(NSString*)scheme host:(NSString*)host port:(NSString*)port path:(NSString*)path +{ + self = [super init]; // Potentially change "self" + if (self) { + if ((scheme == nil) || [scheme isEqualToString:@"*"]) { + _scheme = nil; + } else { + _scheme = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:scheme allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil]; + } + if ([host isEqualToString:@"*"] || host == nil) { + _host = nil; + } else if ([host hasPrefix:@"*."]) { + _host = [NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"([a-z0-9.-]*\\.)?%@", [CDVWhitelistPattern regexFromPattern:[host substringFromIndex:2] allowWildcards:false]] options:NSRegularExpressionCaseInsensitive error:nil]; + } else { + _host = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:host allowWildcards:NO] options:NSRegularExpressionCaseInsensitive error:nil]; + } + if ((port == nil) || [port isEqualToString:@"*"]) { + _port = nil; + } else { + _port = [[NSNumber alloc] initWithInteger:[port integerValue]]; + } + if ((path == nil) || [path isEqualToString:@"/*"]) { + _path = nil; + } else { + _path = [NSRegularExpression regularExpressionWithPattern:[CDVWhitelistPattern regexFromPattern:path allowWildcards:YES] options:0 error:nil]; + } + } + return self; +} + +- (bool)matches:(NSURL*)url +{ + return (_scheme == nil || [_scheme numberOfMatchesInString:[url scheme] options:NSMatchingAnchored range:NSMakeRange(0, [[url scheme] length])]) && + (_host == nil || ([url host] != nil && [_host numberOfMatchesInString:[url host] options:NSMatchingAnchored range:NSMakeRange(0, [[url host] length])])) && + (_port == nil || [[url port] isEqualToNumber:_port]) && + (_path == nil || [_path numberOfMatchesInString:[url path] options:NSMatchingAnchored range:NSMakeRange(0, [[url path] length])]) + ; +} + +@end + +@interface CDVWhitelist () + +@property (nonatomic, readwrite, strong) NSMutableArray* whitelist; +@property (nonatomic, readwrite, strong) NSMutableSet* permittedSchemes; + +- (void)addWhiteListEntry:(NSString*)pattern; + +@end + +@implementation CDVWhitelist + +@synthesize whitelist, permittedSchemes, whitelistRejectionFormatString; + +- (id)initWithArray:(NSArray*)array +{ + self = [super init]; + if (self) { + self.whitelist = [[NSMutableArray alloc] init]; + self.permittedSchemes = [[NSMutableSet alloc] init]; + self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString; + + for (NSString* pattern in array) { + [self addWhiteListEntry:pattern]; + } + } + return self; +} + +- (BOOL)isIPv4Address:(NSString*)externalHost +{ + // an IPv4 address has 4 octets b.b.b.b where b is a number between 0 and 255. + // for our purposes, b can also be the wildcard character '*' + + // we could use a regex to solve this problem but then I would have two problems + // anyways, this is much clearer and maintainable + NSArray* octets = [externalHost componentsSeparatedByString:@"."]; + NSUInteger num_octets = [octets count]; + + // quick check + if (num_octets != 4) { + return NO; + } + + // restrict number parsing to 0-255 + NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init]; + [numberFormatter setMinimum:[NSNumber numberWithUnsignedInteger:0]]; + [numberFormatter setMaximum:[NSNumber numberWithUnsignedInteger:255]]; + + // iterate through each octet, and test for a number between 0-255 or if it equals '*' + for (NSUInteger i = 0; i < num_octets; ++i) { + NSString* octet = [octets objectAtIndex:i]; + + if ([octet isEqualToString:@"*"]) { // passes - check next octet + continue; + } else if ([numberFormatter numberFromString:octet] == nil) { // fails - not a number and not within our range, return + return NO; + } + } + + return YES; +} + +- (void)addWhiteListEntry:(NSString*)origin +{ + if (self.whitelist == nil) { + return; + } + + if ([origin isEqualToString:@"*"]) { + NSLog(@"Unlimited access to network resources"); + self.whitelist = nil; + self.permittedSchemes = nil; + } else { // specific access + NSRegularExpression* parts = [NSRegularExpression regularExpressionWithPattern:@"^((\\*|[A-Za-z-]+):/?/?)?(((\\*\\.)?[^*/:]+)|\\*)?(:(\\d+))?(/.*)?" options:0 error:nil]; + NSTextCheckingResult* m = [parts firstMatchInString:origin options:NSMatchingAnchored range:NSMakeRange(0, [origin length])]; + if (m != nil) { + NSRange r; + NSString* scheme = nil; + r = [m rangeAtIndex:2]; + if (r.location != NSNotFound) { + scheme = [origin substringWithRange:r]; + } + + NSString* host = nil; + r = [m rangeAtIndex:3]; + if (r.location != NSNotFound) { + host = [origin substringWithRange:r]; + } + + // Special case for two urls which are allowed to have empty hosts + if (([scheme isEqualToString:@"file"] || [scheme isEqualToString:@"content"]) && (host == nil)) { + host = @"*"; + } + + NSString* port = nil; + r = [m rangeAtIndex:7]; + if (r.location != NSNotFound) { + port = [origin substringWithRange:r]; + } + + NSString* path = nil; + r = [m rangeAtIndex:8]; + if (r.location != NSNotFound) { + path = [origin substringWithRange:r]; + } + + if (scheme == nil) { + // XXX making it stupid friendly for people who forget to include protocol/SSL + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"http" host:host port:port path:path]]; + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:@"https" host:host port:port path:path]]; + } else { + [self.whitelist addObject:[[CDVWhitelistPattern alloc] initWithScheme:scheme host:host port:port path:path]]; + } + + if (self.permittedSchemes != nil) { + if ([scheme isEqualToString:@"*"]) { + self.permittedSchemes = nil; + } else if (scheme != nil) { + [self.permittedSchemes addObject:scheme]; + } + } + } + } +} + +- (BOOL)schemeIsAllowed:(NSString*)scheme +{ + if ([scheme isEqualToString:@"http"] || + [scheme isEqualToString:@"https"] || + [scheme isEqualToString:@"ftp"] || + [scheme isEqualToString:@"ftps"]) { + return YES; + } + + return (self.permittedSchemes == nil) || [self.permittedSchemes containsObject:scheme]; +} + +- (BOOL)URLIsAllowed:(NSURL*)url +{ + return [self URLIsAllowed:url logFailure:YES]; +} + +- (BOOL)URLIsAllowed:(NSURL*)url logFailure:(BOOL)logFailure +{ + // Shortcut acceptance: Are all urls whitelisted ("*" in whitelist)? + if (whitelist == nil) { + return YES; + } + + // Shortcut rejection: Check that the scheme is supported + NSString* scheme = [[url scheme] lowercaseString]; + if (![self schemeIsAllowed:scheme]) { + if (logFailure) { + NSLog(@"%@", [self errorStringForURL:url]); + } + return NO; + } + + // http[s] and ftp[s] should also validate against the common set in the kCDVDefaultSchemeName list + if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) { + NSURL* newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@%@", kCDVDefaultSchemeName, [url host], [[url path] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; + // If it is allowed, we are done. If not, continue to check for the actual scheme-specific list + if ([self URLIsAllowed:newUrl logFailure:NO]) { + return YES; + } + } + + // Check the url against patterns in the whitelist + for (CDVWhitelistPattern* p in self.whitelist) { + if ([p matches:url]) { + return YES; + } + } + + if (logFailure) { + NSLog(@"%@", [self errorStringForURL:url]); + } + // if we got here, the url host is not in the white-list, do nothing + return NO; +} + +- (NSString*)errorStringForURL:(NSURL*)url +{ + return [NSString stringWithFormat:self.whitelistRejectionFormatString, [url absoluteString]]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.h new file mode 100755 index 0000000..9be2be2 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.h @@ -0,0 +1,35 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import +#import + +@interface NSDictionary (CordovaPreferences) + +- (id)cordovaSettingForKey:(NSString*)key; +- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue; +- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue; + +@end + +@interface NSMutableDictionary (CordovaPreferences) + +- (void)setCordovaSetting:(id)value forKey:(NSString*)key; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.m new file mode 100755 index 0000000..dcac40f --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSDictionary+CordovaPreferences.m @@ -0,0 +1,63 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "NSDictionary+CordovaPreferences.h" +#import + +@implementation NSDictionary (CordovaPreferences) + +- (id)cordovaSettingForKey:(NSString*)key +{ + return [self objectForKey:[key lowercaseString]]; +} + +- (BOOL)cordovaBoolSettingForKey:(NSString*)key defaultValue:(BOOL)defaultValue +{ + BOOL value = defaultValue; + id prefObj = [self cordovaSettingForKey:key]; + + if (prefObj != nil) { + value = [(NSNumber*)prefObj boolValue]; + } + + return value; +} + +- (CGFloat)cordovaFloatSettingForKey:(NSString*)key defaultValue:(CGFloat)defaultValue +{ + CGFloat value = defaultValue; + id prefObj = [self cordovaSettingForKey:key]; + + if (prefObj != nil) { + value = [prefObj floatValue]; + } + + return value; +} + +@end + +@implementation NSMutableDictionary (CordovaPreferences) + +- (void)setCordovaSetting:(id)value forKey:(NSString*)key +{ + [self setObject:value forKey:[key lowercaseString]]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.h b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.h new file mode 100755 index 0000000..79e6516 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.h @@ -0,0 +1,29 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import + +@interface NSMutableArray (QueueAdditions) + +- (id)cdv_pop; +- (id)cdv_queueHead; +- (id)cdv_dequeue; +- (void)cdv_enqueue:(id)obj; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.m b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.m new file mode 100755 index 0000000..2b3acdc --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/Public/NSMutableArray+QueueAdditions.m @@ -0,0 +1,58 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "NSMutableArray+QueueAdditions.h" + +@implementation NSMutableArray (QueueAdditions) + +- (id)cdv_queueHead +{ + if ([self count] == 0) { + return nil; + } + + return [self objectAtIndex:0]; +} + +- (__autoreleasing id)cdv_dequeue +{ + if ([self count] == 0) { + return nil; + } + + id head = [self objectAtIndex:0]; + if (head != nil) { + // [[head retain] autorelease]; ARC - the __autoreleasing on the return value should so the same thing + [self removeObjectAtIndex:0]; + } + + return head; +} + +- (id)cdv_pop +{ + return [self cdv_dequeue]; +} + +- (void)cdv_enqueue:(id)object +{ + [self addObject:object]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/config.xml b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/config.xml new file mode 100755 index 0000000..8538adf --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/CordovaLib/config.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + HelloCordova + + A sample Apache Cordova application that responds to the deviceready event. + + + Apache Cordova Team + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.h b/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.h new file mode 100644 index 0000000..c4c5904 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.h @@ -0,0 +1,25 @@ +// +// HLAudioPlayer.h +// 音效播放器 +// +// Created by Harvey on 14/6/2. +// Copyright © 2014年 Haley. All rights reserved. +// + +#import +#import + +@interface HLAudioPlayer : NSObject + ++ (AVAudioPlayer *)playMusic:(NSString *)fileName; + ++ (void)pauseMusic:(NSString *)fileName; + ++ (void)stopMusic:(NSString *)fileName; + + ++ (void)playSound:(NSString *)soundName; + ++ (void)disposeSound:(NSString *)soundName; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.m b/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.m new file mode 100644 index 0000000..413543f --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/HLAudioPlayer.m @@ -0,0 +1,134 @@ +// +// HLAudioPlayer.m +// 音效播放器 +// +// Created by Harvey on 14/6/2. +// Copyright © 2014年 Haley. All rights reserved. +// + +#import "HLAudioPlayer.h" + +@implementation HLAudioPlayer + ++ (void)initialize +{ + // 音频会话 + AVAudioSession *session = [AVAudioSession sharedInstance]; + // 设置会话类型 + [session setCategory:AVAudioSessionCategoryPlayback error:nil]; + // 激活会话 + [session setActive:YES error:nil]; +} + +// 音效Id +static NSMutableDictionary *_soundIDs; + ++ (NSMutableDictionary *)soundIDs +{ + if (!_soundIDs) { + _soundIDs = [NSMutableDictionary dictionary]; + } + return _soundIDs; +} + + +// 所有的播放器 +static NSMutableDictionary *_musicPlayers; ++ (NSMutableDictionary *)musicPlayers +{ + if (!_musicPlayers) { + _musicPlayers = [NSMutableDictionary dictionary]; + } + return _musicPlayers; +} + ++ (AVAudioPlayer *)playMusic:(NSString *)fileName +{ + if (!fileName) { + return nil; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + if (!player) { + NSURL *URL = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil]; + if (!URL) { + return nil; + } + player = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:nil]; + + if (![player prepareToPlay]) { + return nil; + } + + [self musicPlayers][fileName] = player; + } + + if (!player.isPlaying) { + [player play]; + } + + return player; +} + ++ (void)pauseMusic:(NSString *)fileName +{ + if (!fileName) { + return; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + + [player pause]; +} + ++ (void)stopMusic:(NSString *)fileName +{ + if (!fileName) { + return; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + + [player stop]; + + [[self musicPlayers] removeObjectForKey:fileName]; +} + ++ (void)playSound:(NSString *)soundName +{ + if (!soundName) { + return; + } + + SystemSoundID soundID = [[self soundIDs][soundName] unsignedIntValue]; + + if (!soundID) { + NSURL *URL = [[NSBundle mainBundle] URLForResource:soundName withExtension:nil]; + if (!URL) { + return; + } + + AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(URL), &soundID); + + [self soundIDs][soundName] = @(soundID); + } + + AudioServicesPlaySystemSound(soundID); +} + ++ (void)disposeSound:(NSString *)soundName +{ + if (!soundName) { + return; + } + + SystemSoundID soundID = [[self soundIDs][soundName] unsignedIntValue]; + + if (soundID) { + AudioServicesDisposeSystemSoundID(soundID); + + [[self soundIDs] removeObjectForKey:soundName]; + } +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/Info.plist b/JS_OC_Cordova/JS_OC_Cordova/Info.plist new file mode 100644 index 0000000..44b6f27 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.h b/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.h new file mode 100644 index 0000000..9e968d8 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.h @@ -0,0 +1,27 @@ +// +// HaleyPlugin.h +// HelloCordova +// +// Created by Harvey on 16/9/28. +// +// + +#import "CDV.h" + +@interface HaleyPlugin : CDVPlugin + +- (void)scan:(CDVInvokedUrlCommand *)command; + +- (void)location:(CDVInvokedUrlCommand *)command; + +- (void)pay:(CDVInvokedUrlCommand *)command; + +- (void)share:(CDVInvokedUrlCommand *)command; + +- (void)changeColor:(CDVInvokedUrlCommand *)command; + +- (void)shake:(CDVInvokedUrlCommand *)command; + +- (void)playSound:(CDVInvokedUrlCommand *)command; + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.m b/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.m new file mode 100644 index 0000000..ea2ed67 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/Plugins/HaleyPlugin.m @@ -0,0 +1,123 @@ +// +// HaleyPlugin.m +// HelloCordova +// +// Created by Harvey on 16/9/28. +// +// + +#import + +#import "HaleyPlugin.h" +#import "HLAudioPlayer.h" + +@implementation HaleyPlugin + +- (void)scan:(CDVInvokedUrlCommand *)command +{ + [self.commandDelegate runInBackground:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"原生弹窗" message:nil delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]; + [alertView show]; + }); + }]; +} + +- (void)location:(CDVInvokedUrlCommand *)command +{ + // 获取定位信息...... + + // 下一行代码以后可以删除 +// NSString *locationStr = @"广东省深圳市南山区学府路XXXX号"; + NSString *locationStr = @"错误信息"; + +// NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",locationStr]; +// [self.commandDelegate evalJs:jsStr]; + + [self.commandDelegate runInBackground:^{ + CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:locationStr]; + [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; + }]; +} + +- (void)pay:(CDVInvokedUrlCommand *)command +{ + // 这里是支付的相关代码...... + + // 以下代码以后可以删除 + NSUInteger code = 1; + NSString *tip = @"支付成功"; + NSArray *arguments = command.arguments; + if (arguments.count < 4) {; + code = 2; + tip = @"参数错误"; + } else { + NSLog(@"从H5获取的支付参数:%@",arguments); + } + + NSString *jsStr = [NSString stringWithFormat:@"payResult('%@',%lu)",tip,(unsigned long)code]; + [self.commandDelegate evalJs:jsStr]; +} + +- (void)share:(CDVInvokedUrlCommand *)command +{ + NSUInteger code = 1; + NSString *tip = @"分享成功"; + NSArray *arguments = command.arguments; + if (arguments.count < 3) {; + code = 2; + tip = @"参数错误"; + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@')",tip]; + [self.commandDelegate evalJs:jsStr]; + return; + } + + NSLog(@"从H5获取的分享参数:%@",arguments); + NSString *title = arguments[0]; + NSString *content = arguments[1]; + NSString *url = arguments[2]; + + // 这里是分享的相关代码...... + + // 将分享结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; + [self.commandDelegate evalJs:jsStr]; +} + +- (void)changeColor:(CDVInvokedUrlCommand *)command +{ + NSArray *arguments = command.arguments; + if (arguments.count < 4) { + return; + } + + CGFloat r = [arguments[0] floatValue]; + CGFloat g = [arguments[1] floatValue]; + CGFloat b = [arguments[2] floatValue]; + CGFloat a = [arguments[3] floatValue]; + + self.viewController.view.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; +} + +- (void)shake:(CDVInvokedUrlCommand *)command +{ + [self.commandDelegate runInBackground:^{ + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); + [HLAudioPlayer playMusic:@"shake_sound_male.wav"]; + }]; +} + +- (void)playSound:(CDVInvokedUrlCommand *)command +{ + NSArray *arguments = command.arguments; + if (arguments.count < 1) { + return; + } + + [self.commandDelegate runInBackground:^{ + NSString *fileName = arguments[0]; + [HLAudioPlayer playMusic:fileName]; + }]; +} + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/PrefixHeader.pch b/JS_OC_Cordova/JS_OC_Cordova/PrefixHeader.pch new file mode 100644 index 0000000..e2bfb06 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/PrefixHeader.pch @@ -0,0 +1,20 @@ +// +// PrefixHeader.pch +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#ifndef PrefixHeader_pch +#define PrefixHeader_pch + +// Include any system framework and library headers here that should be included in all compilation units. +// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. + +#ifdef __OBJC__ + #import + +#endif + +#endif /* PrefixHeader_pch */ diff --git a/JS_OC_Cordova/JS_OC_Cordova/ViewController.h b/JS_OC_Cordova/JS_OC_Cordova/ViewController.h new file mode 100644 index 0000000..ad49f52 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/ViewController.h @@ -0,0 +1,16 @@ +// +// ViewController.h +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "CDVViewController.h" + +@interface ViewController : CDVViewController + + +@end + diff --git a/JS_OC_Cordova/JS_OC_Cordova/ViewController.m b/JS_OC_Cordova/JS_OC_Cordova/ViewController.m new file mode 100644 index 0000000..18b92b0 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/ViewController.m @@ -0,0 +1,46 @@ +// +// ViewController.m +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "ViewController.h" + +@interface ViewController () + +@end + +@implementation ViewController + +- (void)viewDidLoad { + +// self.startPage = @"http://www.baidu.com"; + + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + // 这里空出的20,是为了不显示使用导航控制器时,控制背景色来改变状态栏背景色 + self.webView.frame = CGRectMake(0, 20, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) - 20); + + UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"测试" style:UIBarButtonItemStylePlain target:self action:@selector(testClick)]; + self.navigationItem.rightBarButtonItem = rightItem; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + [self.navigationController setNavigationBarHidden:YES]; + +} + +- (void)testClick +{ + NSString *jsStr = @"asyncAlert('哈哈啊哈')"; + [self.commandDelegate evalJs:jsStr]; +} + + +@end diff --git a/JS_OC_Cordova/JS_OC_Cordova/main.m b/JS_OC_Cordova/JS_OC_Cordova/main.m new file mode 100644 index 0000000..53792f9 --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/main.m @@ -0,0 +1,16 @@ +// +// main.m +// JS_OC_Cordova +// +// Created by Harvey on 16/9/28. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/JS_OC_Cordova/JS_OC_Cordova/shake_sound_male.wav b/JS_OC_Cordova/JS_OC_Cordova/shake_sound_male.wav new file mode 100755 index 0000000..a353d66 Binary files /dev/null and b/JS_OC_Cordova/JS_OC_Cordova/shake_sound_male.wav differ diff --git a/JS_OC_Cordova/JS_OC_Cordova/www/cordova.js b/JS_OC_Cordova/JS_OC_Cordova/www/cordova.js new file mode 100644 index 0000000..dc4731e --- /dev/null +++ b/JS_OC_Cordova/JS_OC_Cordova/www/cordova.js @@ -0,0 +1,1911 @@ +// Platform: ios +// d403ce434788ffe1937711d6ebcbcc837fcbcb14 +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +;(function() { +var PLATFORM_VERSION_BUILD_LABEL = '4.2.1'; +// file: src/scripts/require.js + +/*jshint -W079 */ +/*jshint -W020 */ + +var require, + define; + +(function () { + var modules = {}, + // Stack of moduleIds currently being built. + requireStack = [], + // Map of module ID -> index into requireStack of modules currently being built. + inProgressModules = {}, + SEPARATOR = "."; + + + + function build(module) { + var factory = module.factory, + localRequire = function (id) { + var resultantId = id; + //Its a relative path, so lop off the last portion and add the id (minus "./") + if (id.charAt(0) === ".") { + resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2); + } + return require(resultantId); + }; + module.exports = {}; + delete module.factory; + factory(localRequire, module.exports, module); + return module.exports; + } + + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; + } + if (modules[id].factory) { + try { + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); + } + } + return modules[id].exports; + }; + + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: src/cordova.js +define("cordova", function(require, exports, module) { + +// Workaround for Windows 10 in hosted environment case +// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object +if (window.cordova && !(window.cordova instanceof HTMLElement)) { + throw new Error("cordova already defined"); +} + + +var channel = require('cordova/channel'); +var platform = require('cordova/platform'); + + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + + +var cordova = { + define:define, + require:require, + version:PLATFORM_VERSION_BUILD_LABEL, + platformVersion:PLATFORM_VERSION_BUILD_LABEL, + platformId:platform.id, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + // Fire deviceready on listeners that were registered before cordova.js was loaded. + if (type == 'deviceready') { + document.dispatchEvent(evt); + } + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + callbackStatus: { + NO_RESULT: 0, + OK: 1, + CLASS_NOT_FOUND_EXCEPTION: 2, + ILLEGAL_ACCESS_EXCEPTION: 3, + INSTANTIATION_EXCEPTION: 4, + MALFORMED_URL_EXCEPTION: 5, + IO_EXCEPTION: 6, + INVALID_ACTION: 7, + JSON_EXCEPTION: 8, + ERROR: 9 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) { + try { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (isSuccess && status == cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else if (!isSuccess) { + callback.fail && callback.fail.apply(null, args); + } + /* + else + Note, this case is intentionally not caught. + this can happen if isSuccess is true, but callbackStatus is NO_RESULT + which is used to remove a callback from the list without calling the callbacks + typically keepCallback is false in this case + */ + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } + catch (err) { + var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err; + console && console.log && console.log(msg); + cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg }); + throw err; + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + + +module.exports = cordova; + +}); + +// file: src/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var utils = require('cordova/utils'); + +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running unit tests. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: src/common/base64.js +define("cordova/base64", function(require, exports, module) { + +var base64 = exports; + +base64.fromArrayBuffer = function(arrayBuffer) { + var array = new Uint8Array(arrayBuffer); + return uint8ToBase64(array); +}; + +base64.toArrayBuffer = function(str) { + var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary'); + var arrayBuffer = new ArrayBuffer(decodedStr.length); + var array = new Uint8Array(arrayBuffer); + for (var i=0, len=decodedStr.length; i < len; i++) { + array[i] = decodedStr.charCodeAt(i); + } + return arrayBuffer; +}; + +//------------------------------------------------------------------------------ + +/* This code is based on the performance tests at http://jsperf.com/b64tests + * This 12-bit-at-a-time algorithm was the best performing version on all + * platforms tested. + */ + +var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +var b64_12bit; + +var b64_12bitTable = function() { + b64_12bit = []; + for (var i=0; i<64; i++) { + for (var j=0; j<64; j++) { + b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j]; + } + } + b64_12bitTable = function() { return b64_12bit; }; + return b64_12bit; +}; + +function uint8ToBase64(rawData) { + var numBytes = rawData.byteLength; + var output=""; + var segment; + var table = b64_12bitTable(); + for (var i=0;i> 12]; + output += table[segment & 0xfff]; + } + if (numBytes - i == 2) { + segment = (rawData[i] << 16) + (rawData[i+1] << 8); + output += table[segment >> 12]; + output += b64_6bit[(segment & 0xfff) >> 6]; + output += '='; + } else if (numBytes - i == 1) { + segment = (rawData[i] << 16); + output += table[segment >> 12]; + output += '=='; + } + return output; +} + +}); + +// file: src/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + var needsProperty = false; + try { + obj[key] = value; + } catch (e) { + needsProperty = true; + } + // Getters can only be overridden by getters. + if (needsProperty || obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + +function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; + } else { + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; + } + } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"'); + } + }); +} + +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} + +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; + +}); + +// file: src/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { + /** + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. + */ + join: function(h, c) { + var len = c.length, + i = len, + f = function() { + if (!(--i)) h(); + }; + for (var j=0; jNative messages. + isInContextOfEvalJs = 0, + failSafeTimerId = 0; + +function massageArgsJsToNative(args) { + if (!args || utils.typeName(args) != 'Array') { + return args; + } + var ret = []; + args.forEach(function(arg, i) { + if (utils.typeName(arg) == 'ArrayBuffer') { + ret.push({ + 'CDVType': 'ArrayBuffer', + 'data': base64.fromArrayBuffer(arg) + }); + } else { + ret.push(arg); + } + }); + return ret; +} + +function massageMessageNativeToJs(message) { + if (message.CDVType == 'ArrayBuffer') { + var stringToArrayBuffer = function(str) { + var ret = new Uint8Array(str.length); + for (var i = 0; i < str.length; i++) { + ret[i] = str.charCodeAt(i); + } + return ret.buffer; + }; + var base64ToArrayBuffer = function(b64) { + return stringToArrayBuffer(atob(b64)); + }; + message = base64ToArrayBuffer(message.data); + } + return message; +} + +function convertMessageToArgsNativeToJs(message) { + var args = []; + if (!message || !message.hasOwnProperty('CDVType')) { + args.push(message); + } else if (message.CDVType == 'MultiPart') { + message.messages.forEach(function(e) { + args.push(massageMessageNativeToJs(e)); + }); + } else { + args.push(massageMessageNativeToJs(message)); + } + return args; +} + +function iOSExec() { + + var successCallback, failCallback, service, action, actionArgs; + var callbackId = null; + if (typeof arguments[0] !== 'string') { + // FORMAT ONE + successCallback = arguments[0]; + failCallback = arguments[1]; + service = arguments[2]; + action = arguments[3]; + actionArgs = arguments[4]; + + // Since we need to maintain backwards compatibility, we have to pass + // an invalid callbackId even if no callback was provided since plugins + // will be expecting it. The Cordova.exec() implementation allocates + // an invalid callbackId and passes it even if no callbacks were given. + callbackId = 'INVALID'; + } else { + throw new Error('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' + + 'cordova.exec(null, null, \'Service\', \'action\', [ arg1, arg2 ]);' + ); + } + + // If actionArgs is not provided, default to an empty array + actionArgs = actionArgs || []; + + // Register the callbacks and add the callbackId to the positional + // arguments if given. + if (successCallback || failCallback) { + callbackId = service + cordova.callbackId++; + cordova.callbacks[callbackId] = + {success:successCallback, fail:failCallback}; + } + + actionArgs = massageArgsJsToNative(actionArgs); + + var command = [callbackId, service, action, actionArgs]; + + // Stringify and queue the command. We stringify to command now to + // effectively clone the command arguments in case they are mutated before + // the command is executed. + commandQueue.push(JSON.stringify(command)); + + // If we're in the context of a stringByEvaluatingJavaScriptFromString call, + // then the queue will be flushed when it returns; no need for a poke. + // Also, if there is already a command in the queue, then we've already + // poked the native side, so there is no reason to do so again. + if (!isInContextOfEvalJs && commandQueue.length == 1) { + pokeNative(); + } +} + +// CB-10530 +function proxyChanged() { + var cexec = cordovaExec(); + + return (execProxy !== cexec && // proxy objects are different + iOSExec !== cexec // proxy object is not the current iOSExec + ); +} + +// CB-10106 +function handleBridgeChange() { + if (proxyChanged()) { + var commandString = commandQueue.shift(); + while(commandString) { + var command = JSON.parse(commandString); + var callbackId = command[0]; + var service = command[1]; + var action = command[2]; + var actionArgs = command[3]; + var callbacks = cordova.callbacks[callbackId] || {}; + + execProxy(callbacks.success, callbacks.fail, service, action, actionArgs); + + commandString = commandQueue.shift(); + }; + return true; + } + + return false; +} + +function pokeNative() { + // CB-5488 - Don't attempt to create iframe before document.body is available. + if (!document.body) { + setTimeout(pokeNative); + return; + } + + // Check if they've removed it from the DOM, and put it back if so. + if (execIframe && execIframe.contentWindow) { + execIframe.contentWindow.location = 'gap://ready'; + } else { + execIframe = document.createElement('iframe'); + execIframe.style.display = 'none'; + execIframe.src = 'gap://ready'; + document.body.appendChild(execIframe); + } + // Use a timer to protect against iframe being unloaded during the poke (CB-7735). + // This makes the bridge ~ 7% slower, but works around the poke getting lost + // when the iframe is removed from the DOM. + // An onunload listener could be used in the case where the iframe has just been + // created, but since unload events fire only once, it doesn't work in the normal + // case of iframe reuse (where unload will have already fired due to the attempted + // navigation of the page). + failSafeTimerId = setTimeout(function() { + if (commandQueue.length) { + // CB-10106 - flush the queue on bridge change + if (!handleBridgeChange()) { + pokeNative(); + } + } + }, 50); // Making this > 0 improves performance (marginally) in the normal case (where it doesn't fire). +} + +iOSExec.nativeFetchMessages = function() { + // Stop listing for window detatch once native side confirms poke. + if (failSafeTimerId) { + clearTimeout(failSafeTimerId); + failSafeTimerId = 0; + } + // Each entry in commandQueue is a JSON string already. + if (!commandQueue.length) { + return ''; + } + var json = '[' + commandQueue.join(',') + ']'; + commandQueue.length = 0; + return json; +}; + +iOSExec.nativeCallback = function(callbackId, status, message, keepCallback, debug) { + return iOSExec.nativeEvalAndFetch(function() { + var success = status === 0 || status === 1; + var args = convertMessageToArgsNativeToJs(message); + function nc2() { + cordova.callbackFromNative(callbackId, success, status, args, keepCallback); + } + setTimeout(nc2, 0); + }); +}; + +iOSExec.nativeEvalAndFetch = function(func) { + // This shouldn't be nested, but better to be safe. + isInContextOfEvalJs++; + try { + func(); + return iOSExec.nativeFetchMessages(); + } finally { + isInContextOfEvalJs--; + } +}; + +// Proxy the exec for bridge changes. See CB-10106 + +function cordovaExec() { + var cexec = require('cordova/exec'); + var cexec_valid = (typeof cexec.nativeFetchMessages === 'function') && (typeof cexec.nativeEvalAndFetch === 'function') && (typeof cexec.nativeCallback === 'function'); + return (cexec_valid && execProxy !== cexec)? cexec : iOSExec; +} + +function execProxy() { + cordovaExec().apply(null, arguments); +}; + +execProxy.nativeFetchMessages = function() { + return cordovaExec().nativeFetchMessages.apply(null, arguments); +}; + +execProxy.nativeEvalAndFetch = function() { + return cordovaExec().nativeEvalAndFetch.apply(null, arguments); +}; + +execProxy.nativeCallback = function() { + return cordovaExec().nativeCallback.apply(null, arguments); +}; + +module.exports = execProxy; + +}); + +// file: src/common/exec/proxy.js +define("cordova/exec/proxy", function(require, exports, module) { + + +// internal map of proxy function +var CommandProxyMap = {}; + +module.exports = { + + // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...); + add:function(id,proxyObj) { + console.log("adding proxy for " + id); + CommandProxyMap[id] = proxyObj; + return proxyObj; + }, + + // cordova.commandProxy.remove("Accelerometer"); + remove:function(id) { + var proxy = CommandProxyMap[id]; + delete CommandProxyMap[id]; + CommandProxyMap[id] = null; + return proxy; + }, + + get:function(service,action) { + return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null ); + } +}; +}); + +// file: src/common/init.js +define("cordova/init", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var modulemapper = require('cordova/modulemapper'); +var platform = require('cordova/platform'); +var pluginloader = require('cordova/pluginloader'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// Replace navigator before any modules are required(), to ensure it happens as soon as possible. +// We replace it so that properties that can't be clobbered can instead be overridden. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; +} + +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} + +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onActivated = cordova.addDocumentEventHandler('activated'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +modulemapper.clobbers('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. +// The delay allows the attached modules to be defined before the plugin loader looks for them. +setTimeout(function() { + pluginloader.load(function() { + channel.onPluginsReady.fire(); + }); +}, 0); + +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + modulemapper.mapModules(window); + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + +}, platformInitChannelsArray); + + +}); + +// file: src/common/init_b.js +define("cordova/init_b", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var modulemapper = require('cordova/modulemapper'); +var platform = require('cordova/platform'); +var pluginloader = require('cordova/pluginloader'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady]; + +// setting exec +cordova.exec = require('cordova/exec'); + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// Replace navigator before any modules are required(), to ensure it happens as soon as possible. +// We replace it so that properties that can't be clobbered can instead be overridden. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; +} +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} + +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onActivated = cordova.addDocumentEventHandler('activated'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. +// The delay allows the attached modules to be defined before the plugin loader looks for them. +setTimeout(function() { + pluginloader.load(function() { + channel.onPluginsReady.fire(); + }); +}, 0); + +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + modulemapper.mapModules(window); + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + +}, platformInitChannelsArray); + +}); + +// file: src/common/modulemapper.js +define("cordova/modulemapper", function(require, exports, module) { + +var builder = require('cordova/builder'), + moduleMap = define.moduleMap, + symbolList, + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.runs = function(moduleName) { + addEntry('r', moduleName, null); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy == 'r') { + continue; + } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.reset(); + + +}); + +// file: src/common/modulemapper_b.js +define("cordova/modulemapper_b", function(require, exports, module) { + +var builder = require('cordova/builder'), + symbolList = [], + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.runs = function(moduleName) { + addEntry('r', moduleName, null); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy == 'r') { + continue; + } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.reset(); + + +}); + +// file: /Users/steveng/repo/cordova/cordova-ios/cordova-js-src/platform.js +define("cordova/platform", function(require, exports, module) { + +module.exports = { + id: 'ios', + bootstrap: function() { + require('cordova/channel').onNativeReady.fire(); + } +}; + + +}); + +// file: src/common/pluginloader.js +define("cordova/pluginloader", function(require, exports, module) { + +var modulemapper = require('cordova/modulemapper'); +var urlutil = require('cordova/urlutil'); + +// Helper function to inject a + + + + +

这是按钮调用

+ + + + + + + + +

这是文件上传

+ + + +

这是回调结果展示区

+ + +

竖直方向的表头:

+ + + + + + + + + + + + + +
姓名Bill Gates
电话555 77 854
传真555 77 855
+ + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.pbxproj b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.pbxproj new file mode 100644 index 0000000..73fae28 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.pbxproj @@ -0,0 +1,324 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B9BCE6451D6BEB4A002CCCFB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE6441D6BEB4A002CCCFB /* main.m */; }; + B9BCE6481D6BEB4A002CCCFB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE6471D6BEB4A002CCCFB /* AppDelegate.m */; }; + B9BCE6501D6BEB4A002CCCFB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B9BCE64F1D6BEB4A002CCCFB /* Assets.xcassets */; }; + B9BCE6531D6BEB4A002CCCFB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9BCE6511D6BEB4A002CCCFB /* LaunchScreen.storyboard */; }; + B9BCE6621D6BF252002CCCFB /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE65B1D6BF252002CCCFB /* MainViewController.m */; }; + B9BCE6631D6BF252002CCCFB /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B9BCE65C1D6BF252002CCCFB /* MainViewController.xib */; }; + B9BCE6641D6BF252002CCCFB /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B9BCE65E1D6BF252002CCCFB /* WebViewController.m */; }; + B9BCE6661D6BF252002CCCFB /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = B9BCE6611D6BF252002CCCFB /* index.html */; }; + B9BCE6691D6BF4AA002CCCFB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9BCE6681D6BF4AA002CCCFB /* JavaScriptCore.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B9BCE6401D6BEB49002CCCFB /* JS_OC_JavaScriptCore.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JS_OC_JavaScriptCore.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B9BCE6441D6BEB4A002CCCFB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B9BCE6461D6BEB4A002CCCFB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B9BCE6471D6BEB4A002CCCFB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B9BCE64F1D6BEB4A002CCCFB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B9BCE6521D6BEB4A002CCCFB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B9BCE6541D6BEB4A002CCCFB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B9BCE65A1D6BF252002CCCFB /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; + B9BCE65B1D6BF252002CCCFB /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; + B9BCE65C1D6BF252002CCCFB /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; + B9BCE65D1D6BF252002CCCFB /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = ""; }; + B9BCE65E1D6BF252002CCCFB /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; + B9BCE6611D6BF252002CCCFB /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; + B9BCE6681D6BF4AA002CCCFB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B9BCE63D1D6BEB49002CCCFB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B9BCE6691D6BF4AA002CCCFB /* JavaScriptCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B9BCE6371D6BEB49002CCCFB = { + isa = PBXGroup; + children = ( + B9BCE6421D6BEB4A002CCCFB /* JS_OC_JavaScriptCore */, + B9BCE6671D6BF49A002CCCFB /* Frameworks */, + B9BCE6411D6BEB49002CCCFB /* Products */, + ); + sourceTree = ""; + }; + B9BCE6411D6BEB49002CCCFB /* Products */ = { + isa = PBXGroup; + children = ( + B9BCE6401D6BEB49002CCCFB /* JS_OC_JavaScriptCore.app */, + ); + name = Products; + sourceTree = ""; + }; + B9BCE6421D6BEB4A002CCCFB /* JS_OC_JavaScriptCore */ = { + isa = PBXGroup; + children = ( + B9BCE6461D6BEB4A002CCCFB /* AppDelegate.h */, + B9BCE6471D6BEB4A002CCCFB /* AppDelegate.m */, + B9BCE65A1D6BF252002CCCFB /* MainViewController.h */, + B9BCE65B1D6BF252002CCCFB /* MainViewController.m */, + B9BCE65C1D6BF252002CCCFB /* MainViewController.xib */, + B9BCE65D1D6BF252002CCCFB /* WebViewController.h */, + B9BCE65E1D6BF252002CCCFB /* WebViewController.m */, + B9BCE6611D6BF252002CCCFB /* index.html */, + B9BCE6431D6BEB4A002CCCFB /* Supporting Files */, + ); + path = JS_OC_JavaScriptCore; + sourceTree = ""; + }; + B9BCE6431D6BEB4A002CCCFB /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B9BCE64F1D6BEB4A002CCCFB /* Assets.xcassets */, + B9BCE6511D6BEB4A002CCCFB /* LaunchScreen.storyboard */, + B9BCE6541D6BEB4A002CCCFB /* Info.plist */, + B9BCE6441D6BEB4A002CCCFB /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B9BCE6671D6BF49A002CCCFB /* Frameworks */ = { + isa = PBXGroup; + children = ( + B9BCE6681D6BF4AA002CCCFB /* JavaScriptCore.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B9BCE63F1D6BEB49002CCCFB /* JS_OC_JavaScriptCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = B9BCE6571D6BEB4A002CCCFB /* Build configuration list for PBXNativeTarget "JS_OC_JavaScriptCore" */; + buildPhases = ( + B9BCE63C1D6BEB49002CCCFB /* Sources */, + B9BCE63D1D6BEB49002CCCFB /* Frameworks */, + B9BCE63E1D6BEB49002CCCFB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JS_OC_JavaScriptCore; + productName = JS_OC_JavaScriptCore; + productReference = B9BCE6401D6BEB49002CCCFB /* JS_OC_JavaScriptCore.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B9BCE6381D6BEB49002CCCFB /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Haley; + TargetAttributes = { + B9BCE63F1D6BEB49002CCCFB = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = B9BCE63B1D6BEB49002CCCFB /* Build configuration list for PBXProject "JS_OC_JavaScriptCore" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B9BCE6371D6BEB49002CCCFB; + productRefGroup = B9BCE6411D6BEB49002CCCFB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B9BCE63F1D6BEB49002CCCFB /* JS_OC_JavaScriptCore */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B9BCE63E1D6BEB49002CCCFB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B9BCE6531D6BEB4A002CCCFB /* LaunchScreen.storyboard in Resources */, + B9BCE6661D6BF252002CCCFB /* index.html in Resources */, + B9BCE6631D6BF252002CCCFB /* MainViewController.xib in Resources */, + B9BCE6501D6BEB4A002CCCFB /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B9BCE63C1D6BEB49002CCCFB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B9BCE6481D6BEB4A002CCCFB /* AppDelegate.m in Sources */, + B9BCE6621D6BF252002CCCFB /* MainViewController.m in Sources */, + B9BCE6451D6BEB4A002CCCFB /* main.m in Sources */, + B9BCE6641D6BF252002CCCFB /* WebViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B9BCE6511D6BEB4A002CCCFB /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B9BCE6521D6BEB4A002CCCFB /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B9BCE6551D6BEB4A002CCCFB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B9BCE6561D6BEB4A002CCCFB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B9BCE6581D6BEB4A002CCCFB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_JavaScriptCore/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-JavaScriptCore"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B9BCE6591D6BEB4A002CCCFB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_JavaScriptCore/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-JavaScriptCore"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B9BCE63B1D6BEB49002CCCFB /* Build configuration list for PBXProject "JS_OC_JavaScriptCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B9BCE6551D6BEB4A002CCCFB /* Debug */, + B9BCE6561D6BEB4A002CCCFB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B9BCE6571D6BEB4A002CCCFB /* Build configuration list for PBXNativeTarget "JS_OC_JavaScriptCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B9BCE6581D6BEB4A002CCCFB /* Debug */, + B9BCE6591D6BEB4A002CCCFB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B9BCE6381D6BEB49002CCCFB /* Project object */; +} diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..c056121 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..abe0dad Binary files /dev/null and b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..193a324 Binary files /dev/null and b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/haley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist similarity index 100% rename from JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist rename to JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/haley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..e11fc8b --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JS_OC_JavaScriptCore.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_JavaScriptCore.xcscheme b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_JavaScriptCore.xcscheme new file mode 100644 index 0000000..f174363 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_JavaScriptCore.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7a89a98 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JS_OC_JavaScriptCore.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B9BCE63F1D6BEB49002CCCFB + + primary + + + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.h b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.h new file mode 100644 index 0000000..40c9157 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/23. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.m b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.m new file mode 100644 index 0000000..7d9b786 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/AppDelegate.m @@ -0,0 +1,54 @@ +// +// AppDelegate.m +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/23. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "AppDelegate.h" +#import "MainViewController.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + + MainViewController *mainVC = [[MainViewController alloc] init]; + UINavigationController *NAV = [[UINavigationController alloc] initWithRootViewController:mainVC]; + self.window.rootViewController = NAV; + + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/JS_OC/Base.lproj/LaunchScreen.storyboard b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from JS_OC/Base.lproj/LaunchScreen.storyboard rename to JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Base.lproj/LaunchScreen.storyboard diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Info.plist b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Info.plist new file mode 100644 index 0000000..61861ab --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.h b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.h new file mode 100644 index 0000000..2c1b2d9 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.h @@ -0,0 +1,13 @@ +// +// MainViewController.h +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface MainViewController : UIViewController + +@end diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.m b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.m new file mode 100644 index 0000000..34bb91c --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.m @@ -0,0 +1,29 @@ +// +// MainViewController.m +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "MainViewController.h" +#import "WebViewController.h" + +@interface MainViewController () + +@end + +@implementation MainViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + self.title = @"主页"; +} + +- (IBAction)btnClick1:(id)sender { + WebViewController *webVC = [[WebViewController alloc] init]; + [self.navigationController pushViewController:webVC animated:YES]; +} + +@end diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.xib b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.xib new file mode 100644 index 0000000..89c2339 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/MainViewController.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.h b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.h new file mode 100644 index 0000000..9e152bc --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.h @@ -0,0 +1,13 @@ +// +// WebViewController.h +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WebViewController : UIViewController + +@end diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.m b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.m new file mode 100644 index 0000000..4793e04 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/WebViewController.m @@ -0,0 +1,182 @@ +// +// WebViewController.m +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import + +#import "WebViewController.h" + +@interface WebViewController () + +@property (strong, nonatomic) UIWebView *webView; + +@end + +@implementation WebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"UIWebView-JavaScriptCore"; + self.view.backgroundColor = [UIColor whiteColor]; + + self.webView = [[UIWebView alloc] initWithFrame:self.view.frame]; + self.webView.delegate = self; + NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; +// NSURL *htmlURL = [NSURL URLWithString:@"http://www.baidu.com"]; + NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL]; + + self.webView.backgroundColor = [UIColor clearColor]; + // UIWebView 滚动的比较慢,这里设置为正常速度 + self.webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; + [self.webView loadRequest:request]; + [self.view addSubview:self.webView]; +} + +- (void)dealloc +{ + NSLog(@"%s",__func__); +} + +#pragma mark - private method +- (void)addCustomActions +{ + JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; + + [context evaluateScript:@"var arr = [3, 4, 'abc'];"]; + + [self addScanWithContext:context]; + + [self addLocationWithContext:context]; + + [self addSetBGColorWithContext:context]; + + [self addShareWithContext:context]; + + [self addPayActionWithContext:context]; + + [self addShakeActionWithContext:context]; + + [self addGoBackWithContext:context]; +} + +- (void)addScanWithContext:(JSContext *)context +{ + context[@"scan"] = ^() { + NSLog(@"扫一扫啦"); + }; +} + +- (void)addLocationWithContext:(JSContext *)context +{ + context[@"getLocation"] = ^() { + // 获取位置信息 + + // 将结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"]; + [[JSContext currentContext] evaluateScript:jsStr]; + }; +} + +- (void)addShareWithContext:(JSContext *)context +{ + context[@"share"] = ^() { + NSArray *args = [JSContext currentArguments]; + + if (args.count < 3) { + return ; + } + + NSString *title = [args[0] toString]; + NSString *content = [args[1] toString]; + NSString *url = [args[2] toString]; + // 在这里执行分享的操作 + + // 将分享结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; + [[JSContext currentContext] evaluateScript:jsStr]; + }; +} + +- (void)addSetBGColorWithContext:(JSContext *)context +{ + __weak typeof(self) weakSelf = self; + context[@"setColor"] = ^() { + NSArray *args = [JSContext currentArguments]; + + if (args.count < 4) { + return ; + } + + CGFloat r = [[args[0] toNumber] floatValue]; + CGFloat g = [[args[1] toNumber] floatValue]; + CGFloat b = [[args[2] toNumber] floatValue]; + CGFloat a = [[args[3] toNumber] floatValue]; + + // 注意 现在执行JS是在WebThread的子线程(以前是在主线程),操作UI需要回到主线程。 + dispatch_async(dispatch_get_main_queue(), ^{ + // 这里是操作UI的操作 + weakSelf.view.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; + }); + }; +} + +- (void)addPayActionWithContext:(JSContext *)context +{ + context[@"payAction"] = ^() { + NSArray *args = [JSContext currentArguments]; + + if (args.count < 4) { + return ; + } + + NSString *orderNo = [args[0] toString]; + NSString *channel = [args[1] toString]; + long long amount = [[args[2] toNumber] longLongValue]; + NSString *subject = [args[3] toString]; + + // 支付操作 + NSLog(@"orderNo:%@---channel:%@---amount:%lld---subject:%@",orderNo,channel,amount,subject); + + // 将支付结果返回给js +// NSString *jsStr = [NSString stringWithFormat:@"payResult('%@')",@"支付成功"]; +// [[JSContext currentContext] evaluateScript:jsStr]; + [[JSContext currentContext][@"payResult"] callWithArguments:@[@"支付成功"]]; + }; +} + +- (void)addShakeActionWithContext:(JSContext *)context +{ + + context[@"shake"] = ^() { + dispatch_async(dispatch_get_main_queue(), ^{ + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); + }); + }; +} + +- (void)addGoBackWithContext:(JSContext *)context +{ + __weak typeof(self) weakSelf = self; + context[@"goBack"] = ^() { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.webView goBack]; + }); + }; +} + + +#pragma mark - UIWebViewDelegate +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + NSLog(@"webViewDidFinishLoad"); + + [self addCustomActions]; +} + +@end diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/index.html b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/index.html new file mode 100644 index 0000000..f7d1d76 --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/index.html @@ -0,0 +1,107 @@ + + + + + + + +

这是按钮调用

+ + + + + + + + + +

这是文件上传

+ + + +

这是回调结果展示区

+ + +

竖直方向的表头:

+ + + + + + + + + + + + + +
姓名Bill Gates
电话555 77 854
传真555 77 855
+ + + + \ No newline at end of file diff --git a/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/main.m b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/main.m new file mode 100644 index 0000000..aa5bbbb --- /dev/null +++ b/JS_OC_JavaScriptCore/JS_OC_JavaScriptCore/main.m @@ -0,0 +1,16 @@ +// +// main.m +// JS_OC_JavaScriptCore +// +// Created by Harvey on 16/8/23. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.pbxproj b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7e74afe --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.pbxproj @@ -0,0 +1,320 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B949B02F1D5586BE00DAE37C /* HLAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = B949B02E1D5586BE00DAE37C /* HLAudioPlayer.m */; }; + B949B0311D55874200DAE37C /* shake_sound_male.wav in Resources */ = {isa = PBXBuildFile; fileRef = B949B0301D55874200DAE37C /* shake_sound_male.wav */; }; + B96232A51D5494C100B2B7BB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B96232A41D5494C100B2B7BB /* main.m */; }; + B96232A81D5494C100B2B7BB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B96232A71D5494C100B2B7BB /* AppDelegate.m */; }; + B96232B01D5494C100B2B7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B96232AF1D5494C100B2B7BB /* Assets.xcassets */; }; + B96232B31D5494C100B2B7BB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B96232B11D5494C100B2B7BB /* LaunchScreen.storyboard */; }; + B96232BD1D54950700B2B7BB /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B96232BB1D54950700B2B7BB /* MainViewController.m */; }; + B96232BE1D54950700B2B7BB /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B96232BC1D54950700B2B7BB /* MainViewController.xib */; }; + B96232C11D54953E00B2B7BB /* WKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B96232C01D54953E00B2B7BB /* WKWebViewController.m */; }; + B96232C31D54958600B2B7BB /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = B96232C21D54958600B2B7BB /* index.html */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B949B02D1D5586BE00DAE37C /* HLAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLAudioPlayer.h; sourceTree = ""; }; + B949B02E1D5586BE00DAE37C /* HLAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLAudioPlayer.m; sourceTree = ""; }; + B949B0301D55874200DAE37C /* shake_sound_male.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = shake_sound_male.wav; sourceTree = ""; }; + B96232A01D5494C100B2B7BB /* JS_OC_MessageHandler.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JS_OC_MessageHandler.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B96232A41D5494C100B2B7BB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B96232A61D5494C100B2B7BB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B96232A71D5494C100B2B7BB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B96232AF1D5494C100B2B7BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B96232B21D5494C100B2B7BB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B96232B41D5494C100B2B7BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B96232BA1D54950700B2B7BB /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; + B96232BB1D54950700B2B7BB /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; + B96232BC1D54950700B2B7BB /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; + B96232BF1D54953E00B2B7BB /* WKWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewController.h; sourceTree = ""; }; + B96232C01D54953E00B2B7BB /* WKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewController.m; sourceTree = ""; }; + B96232C21D54958600B2B7BB /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B962329D1D5494C100B2B7BB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B96232971D5494C100B2B7BB = { + isa = PBXGroup; + children = ( + B96232A21D5494C100B2B7BB /* JS_OC_MessageHandler */, + B96232A11D5494C100B2B7BB /* Products */, + ); + sourceTree = ""; + }; + B96232A11D5494C100B2B7BB /* Products */ = { + isa = PBXGroup; + children = ( + B96232A01D5494C100B2B7BB /* JS_OC_MessageHandler.app */, + ); + name = Products; + sourceTree = ""; + }; + B96232A21D5494C100B2B7BB /* JS_OC_MessageHandler */ = { + isa = PBXGroup; + children = ( + B96232A61D5494C100B2B7BB /* AppDelegate.h */, + B96232A71D5494C100B2B7BB /* AppDelegate.m */, + B96232BA1D54950700B2B7BB /* MainViewController.h */, + B96232BB1D54950700B2B7BB /* MainViewController.m */, + B96232BC1D54950700B2B7BB /* MainViewController.xib */, + B96232BF1D54953E00B2B7BB /* WKWebViewController.h */, + B96232C01D54953E00B2B7BB /* WKWebViewController.m */, + B949B02D1D5586BE00DAE37C /* HLAudioPlayer.h */, + B949B02E1D5586BE00DAE37C /* HLAudioPlayer.m */, + B96232C21D54958600B2B7BB /* index.html */, + B949B0301D55874200DAE37C /* shake_sound_male.wav */, + B96232AF1D5494C100B2B7BB /* Assets.xcassets */, + B96232B11D5494C100B2B7BB /* LaunchScreen.storyboard */, + B96232B41D5494C100B2B7BB /* Info.plist */, + B96232A31D5494C100B2B7BB /* Supporting Files */, + ); + path = JS_OC_MessageHandler; + sourceTree = ""; + }; + B96232A31D5494C100B2B7BB /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B96232A41D5494C100B2B7BB /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B962329F1D5494C100B2B7BB /* JS_OC_MessageHandler */ = { + isa = PBXNativeTarget; + buildConfigurationList = B96232B71D5494C100B2B7BB /* Build configuration list for PBXNativeTarget "JS_OC_MessageHandler" */; + buildPhases = ( + B962329C1D5494C100B2B7BB /* Sources */, + B962329D1D5494C100B2B7BB /* Frameworks */, + B962329E1D5494C100B2B7BB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JS_OC_MessageHandler; + productName = JS_OC_MessageHandler; + productReference = B96232A01D5494C100B2B7BB /* JS_OC_MessageHandler.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B96232981D5494C100B2B7BB /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Haley; + TargetAttributes = { + B962329F1D5494C100B2B7BB = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = B962329B1D5494C100B2B7BB /* Build configuration list for PBXProject "JS_OC_MessageHandler" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B96232971D5494C100B2B7BB; + productRefGroup = B96232A11D5494C100B2B7BB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B962329F1D5494C100B2B7BB /* JS_OC_MessageHandler */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B962329E1D5494C100B2B7BB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B96232C31D54958600B2B7BB /* index.html in Resources */, + B96232B31D5494C100B2B7BB /* LaunchScreen.storyboard in Resources */, + B949B0311D55874200DAE37C /* shake_sound_male.wav in Resources */, + B96232BE1D54950700B2B7BB /* MainViewController.xib in Resources */, + B96232B01D5494C100B2B7BB /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B962329C1D5494C100B2B7BB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B96232A81D5494C100B2B7BB /* AppDelegate.m in Sources */, + B96232BD1D54950700B2B7BB /* MainViewController.m in Sources */, + B96232A51D5494C100B2B7BB /* main.m in Sources */, + B949B02F1D5586BE00DAE37C /* HLAudioPlayer.m in Sources */, + B96232C11D54953E00B2B7BB /* WKWebViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B96232B11D5494C100B2B7BB /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B96232B21D5494C100B2B7BB /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B96232B51D5494C100B2B7BB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B96232B61D5494C100B2B7BB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B96232B81D5494C100B2B7BB /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_MessageHandler/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-MessageHandler"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B96232B91D5494C100B2B7BB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_MessageHandler/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-MessageHandler"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B962329B1D5494C100B2B7BB /* Build configuration list for PBXProject "JS_OC_MessageHandler" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B96232B51D5494C100B2B7BB /* Debug */, + B96232B61D5494C100B2B7BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B96232B71D5494C100B2B7BB /* Build configuration list for PBXNativeTarget "JS_OC_MessageHandler" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B96232B81D5494C100B2B7BB /* Debug */, + B96232B91D5494C100B2B7BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B96232981D5494C100B2B7BB /* Project object */; +} diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..053ac75 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..72ae2f8 Binary files /dev/null and b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..bae475d Binary files /dev/null and b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..2c7c41e --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JS_OC_MessageHandler.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_MessageHandler.xcscheme b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_MessageHandler.xcscheme new file mode 100644 index 0000000..b9df748 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_MessageHandler.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8cf71da --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JS_OC_MessageHandler.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B962329F1D5494C100B2B7BB + + primary + + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.h b/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.h new file mode 100644 index 0000000..512c173 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// JS_OC_MessageHandler +// +// Created by Harvey on 16/8/5. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.m b/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.m new file mode 100644 index 0000000..24f8028 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/AppDelegate.m @@ -0,0 +1,56 @@ +// +// AppDelegate.m +// JS_OC_MessageHandler +// +// Created by Harvey on 16/8/5. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "AppDelegate.h" +#import "MainViewController.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + + MainViewController *mainVC = [[MainViewController alloc] init]; + UINavigationController *NAV = [[UINavigationController alloc] initWithRootViewController:mainVC]; + self.window.rootViewController = NAV; + + [self.window makeKeyAndVisible]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_MessageHandler/JS_OC_MessageHandler/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/Base.lproj/LaunchScreen.storyboard b/JS_OC_MessageHandler/JS_OC_MessageHandler/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.h b/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.h new file mode 100644 index 0000000..c4c5904 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.h @@ -0,0 +1,25 @@ +// +// HLAudioPlayer.h +// 音效播放器 +// +// Created by Harvey on 14/6/2. +// Copyright © 2014年 Haley. All rights reserved. +// + +#import +#import + +@interface HLAudioPlayer : NSObject + ++ (AVAudioPlayer *)playMusic:(NSString *)fileName; + ++ (void)pauseMusic:(NSString *)fileName; + ++ (void)stopMusic:(NSString *)fileName; + + ++ (void)playSound:(NSString *)soundName; + ++ (void)disposeSound:(NSString *)soundName; + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.m b/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.m new file mode 100644 index 0000000..413543f --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/HLAudioPlayer.m @@ -0,0 +1,134 @@ +// +// HLAudioPlayer.m +// 音效播放器 +// +// Created by Harvey on 14/6/2. +// Copyright © 2014年 Haley. All rights reserved. +// + +#import "HLAudioPlayer.h" + +@implementation HLAudioPlayer + ++ (void)initialize +{ + // 音频会话 + AVAudioSession *session = [AVAudioSession sharedInstance]; + // 设置会话类型 + [session setCategory:AVAudioSessionCategoryPlayback error:nil]; + // 激活会话 + [session setActive:YES error:nil]; +} + +// 音效Id +static NSMutableDictionary *_soundIDs; + ++ (NSMutableDictionary *)soundIDs +{ + if (!_soundIDs) { + _soundIDs = [NSMutableDictionary dictionary]; + } + return _soundIDs; +} + + +// 所有的播放器 +static NSMutableDictionary *_musicPlayers; ++ (NSMutableDictionary *)musicPlayers +{ + if (!_musicPlayers) { + _musicPlayers = [NSMutableDictionary dictionary]; + } + return _musicPlayers; +} + ++ (AVAudioPlayer *)playMusic:(NSString *)fileName +{ + if (!fileName) { + return nil; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + if (!player) { + NSURL *URL = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil]; + if (!URL) { + return nil; + } + player = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:nil]; + + if (![player prepareToPlay]) { + return nil; + } + + [self musicPlayers][fileName] = player; + } + + if (!player.isPlaying) { + [player play]; + } + + return player; +} + ++ (void)pauseMusic:(NSString *)fileName +{ + if (!fileName) { + return; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + + [player pause]; +} + ++ (void)stopMusic:(NSString *)fileName +{ + if (!fileName) { + return; + } + + AVAudioPlayer *player = [self musicPlayers][fileName]; + + [player stop]; + + [[self musicPlayers] removeObjectForKey:fileName]; +} + ++ (void)playSound:(NSString *)soundName +{ + if (!soundName) { + return; + } + + SystemSoundID soundID = [[self soundIDs][soundName] unsignedIntValue]; + + if (!soundID) { + NSURL *URL = [[NSBundle mainBundle] URLForResource:soundName withExtension:nil]; + if (!URL) { + return; + } + + AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(URL), &soundID); + + [self soundIDs][soundName] = @(soundID); + } + + AudioServicesPlaySystemSound(soundID); +} + ++ (void)disposeSound:(NSString *)soundName +{ + if (!soundName) { + return; + } + + SystemSoundID soundID = [[self soundIDs][soundName] unsignedIntValue]; + + if (soundID) { + AudioServicesDisposeSystemSoundID(soundID); + + [[self soundIDs] removeObjectForKey:soundName]; + } +} + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/Info.plist b/JS_OC_MessageHandler/JS_OC_MessageHandler/Info.plist new file mode 100644 index 0000000..61861ab --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.h b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.h new file mode 100644 index 0000000..bb83c67 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.h @@ -0,0 +1,13 @@ +// +// MainViewController.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface MainViewController : UIViewController + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.m b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.m new file mode 100644 index 0000000..1f18588 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.m @@ -0,0 +1,30 @@ +// +// MainViewController.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "MainViewController.h" + +#import "WKWebViewController.h" + +@interface MainViewController () + +@end + +@implementation MainViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + self.title = @"主页"; +} + +- (IBAction)btnClick2:(id)sender { + WKWebViewController *wkWebVC = [[WKWebViewController alloc] init]; + [self.navigationController pushViewController:wkWebVC animated:YES]; +} + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.xib b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.xib new file mode 100644 index 0000000..8d2da6a --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/MainViewController.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.h b/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.h new file mode 100644 index 0000000..5cdbbc5 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.h @@ -0,0 +1,13 @@ +// +// WKWebViewController.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WKWebViewController : UIViewController + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.m b/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.m new file mode 100644 index 0000000..2f034a7 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/WKWebViewController.m @@ -0,0 +1,263 @@ +// +// WKWebViewController.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import + +#import "WKWebViewController.h" +#import "HLAudioPlayer.h" + +@interface WKWebViewController () + +@property (strong, nonatomic) WKWebView *webView; +@property (strong, nonatomic) UIProgressView *progressView; + +@end + +@implementation WKWebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"MessageHandler"; + + UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(rightClick)]; + self.navigationItem.rightBarButtonItem = rightItem; + + [self initWKWebView]; + + [self initProgressView]; + + [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + // addScriptMessageHandler 很容易导致循环引用 + // 控制器 强引用了WKWebView,WKWebView copy(强引用了)configuration, configuration copy (强引用了)userContentController + // userContentController 强引用了 self (控制器) + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"ScanAction"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Location"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Share"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Color"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Pay"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"Shake"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"GoBack"]; + [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"PlaySound"]; +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + + // 因此这里要记得移除handlers + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"ScanAction"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Location"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Share"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Color"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Pay"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"Shake"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"GoBack"]; + [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"PlaySound"]; +} + +- (void)initWKWebView +{ + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + + WKPreferences *preferences = [WKPreferences new]; + preferences.javaScriptCanOpenWindowsAutomatically = YES; + preferences.minimumFontSize = 40.0; + configuration.preferences = preferences; + + self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; + + +// NSString *urlStr = @"http://www.baidu.com"; +// NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]; +// [self.webView loadRequest:request]; + + NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil]; + NSURL *fileURL = [NSURL fileURLWithPath:urlStr]; + [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL]; + + self.webView.UIDelegate = self; + [self.view addSubview:self.webView]; +} + +- (void)initProgressView +{ + CGFloat kScreenWidth = [[UIScreen mainScreen] bounds].size.width; + UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 2)]; + progressView.tintColor = [UIColor redColor]; + progressView.trackTintColor = [UIColor lightGrayColor]; + [self.view addSubview:progressView]; + self.progressView = progressView; +} + +- (void)rightClick +{ + [self goBack]; +} + +- (void)dealloc +{ + NSLog(@"%s",__FUNCTION__); + [self.webView removeObserver:self forKeyPath:@"estimatedProgress"]; +} + +#pragma mark - private method +- (void)getLocation +{ + // 获取位置信息 + + // 将结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; + + NSString *jsStr2 = @"window.ctuapp_share_img"; + [self.webView evaluateJavaScript:jsStr2 completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; +} + +- (void)shareWithParams:(NSDictionary *)tempDic +{ + if (![tempDic isKindOfClass:[NSDictionary class]]) { + return; + } + + NSString *title = [tempDic objectForKey:@"title"]; + NSString *content = [tempDic objectForKey:@"content"]; + NSString *url = [tempDic objectForKey:@"url"]; + // 在这里执行分享的操作 + + // 将分享结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; +} + +- (void)changeBGColor:(NSArray *)params +{ + if (![params isKindOfClass:[NSArray class]]) { + return; + } + + if (params.count < 4) { + return; + } + + CGFloat r = [params[0] floatValue]; + CGFloat g = [params[1] floatValue]; + CGFloat b = [params[2] floatValue]; + CGFloat a = [params[3] floatValue]; + + self.view.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; +} + +- (void)payWithParams:(NSDictionary *)tempDic +{ + if (![tempDic isKindOfClass:[NSDictionary class]]) { + return; + } + NSString *orderNo = [tempDic objectForKey:@"order_no"]; + long long amount = [[tempDic objectForKey:@"amount"] longLongValue]; + NSString *subject = [tempDic objectForKey:@"subject"]; + NSString *channel = [tempDic objectForKey:@"channel"]; + NSLog(@"%@---%lld---%@---%@",orderNo,amount,subject,channel); + + // 支付操作 + + // 将支付结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"payResult('%@')",@"支付成功"]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; +} + +- (void)shakeAction +{ + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); + [HLAudioPlayer playMusic:@"shake_sound_male.wav"]; +} + +- (void)goBack +{ + [self.webView goBack]; +} + +- (void)playSound:(NSString *)fileName +{ + if (![fileName isKindOfClass:[NSString class]]) { + return; + } + + [HLAudioPlayer playMusic:fileName]; +} + +#pragma mark - KVO +// 计算wkWebView进度条 +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) { + CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue]; + if (newprogress == 1) { + [self.progressView setProgress:1.0 animated:YES]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + self.progressView.hidden = YES; + [self.progressView setProgress:0 animated:NO]; + }); + + }else { + self.progressView.hidden = NO; + [self.progressView setProgress:newprogress animated:YES]; + } + } +} + +#pragma mark - WKUIDelegate +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + completionHandler(); + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +#pragma mark - WKScriptMessageHandler +- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message +{ +// message.body -- Allowed types are NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull. + NSLog(@"body:%@",message.body); + if ([message.name isEqualToString:@"ScanAction"]) { + NSLog(@"扫一扫"); + } else if ([message.name isEqualToString:@"Location"]) { + [self getLocation]; + } else if ([message.name isEqualToString:@"Share"]) { + [self shareWithParams:message.body]; + } else if ([message.name isEqualToString:@"Color"]) { + [self changeBGColor:message.body]; + } else if ([message.name isEqualToString:@"Pay"]) { + [self payWithParams:message.body]; + } else if ([message.name isEqualToString:@"Shake"]) { + [self shakeAction]; + } else if ([message.name isEqualToString:@"GoBack"]) { + [self goBack]; + } else if ([message.name isEqualToString:@"PlaySound"]) { + [self playSound:message.body]; + } +} + +@end diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/index.html b/JS_OC_MessageHandler/JS_OC_MessageHandler/index.html new file mode 100644 index 0000000..5c82abb --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/index.html @@ -0,0 +1,107 @@ + + + + + + + +

这是按钮调用

+ + + + + + + + + +

这是文件上传

+ + + +

这是回调结果展示区

+ + +

竖直方向的表头:

+ + + + + + + + + + + + + +
姓名Bill Gates
电话555 77 854
传真555 77 855
+ + + + diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/main.m b/JS_OC_MessageHandler/JS_OC_MessageHandler/main.m new file mode 100644 index 0000000..d1f79a4 --- /dev/null +++ b/JS_OC_MessageHandler/JS_OC_MessageHandler/main.m @@ -0,0 +1,16 @@ +// +// main.m +// JS_OC_MessageHandler +// +// Created by Harvey on 16/8/5. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/JS_OC_MessageHandler/JS_OC_MessageHandler/shake_sound_male.wav b/JS_OC_MessageHandler/JS_OC_MessageHandler/shake_sound_male.wav new file mode 100755 index 0000000..a353d66 Binary files /dev/null and b/JS_OC_MessageHandler/JS_OC_MessageHandler/shake_sound_male.wav differ diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/project.pbxproj b/JS_OC_URL/JS_OC_URL.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0abf47c --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/project.pbxproj @@ -0,0 +1,333 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B99320411D52E9EE00316A6E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B99320401D52E9EE00316A6E /* main.m */; }; + B99320441D52E9EE00316A6E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B99320431D52E9EE00316A6E /* AppDelegate.m */; }; + B993204C1D52E9EE00316A6E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B993204B1D52E9EE00316A6E /* Assets.xcassets */; }; + B993204F1D52E9EE00316A6E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B993204D1D52E9EE00316A6E /* LaunchScreen.storyboard */; }; + B99320591D52EA6300316A6E /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B99320571D52EA6300316A6E /* MainViewController.m */; }; + B993205A1D52EA6300316A6E /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B99320581D52EA6300316A6E /* MainViewController.xib */; }; + B993205D1D530C9E00316A6E /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B993205C1D530C9E00316A6E /* WebViewController.m */; }; + B99320601D530CB200316A6E /* WKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B993205F1D530CB200316A6E /* WKWebViewController.m */; }; + B99320621D530E7100316A6E /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = B99320611D530E7100316A6E /* index.html */; }; + B99320641D530F5300316A6E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B99320631D530F5300316A6E /* WebKit.framework */; }; + B99320671D5341D100316A6E /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B99320661D5341D100316A6E /* AVFoundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B993203C1D52E9EE00316A6E /* JS_OC_URL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JS_OC_URL.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B99320401D52E9EE00316A6E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B99320421D52E9EE00316A6E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B99320431D52E9EE00316A6E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B993204B1D52E9EE00316A6E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B993204E1D52E9EE00316A6E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B99320501D52E9EE00316A6E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B99320561D52EA6300316A6E /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; + B99320571D52EA6300316A6E /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; + B99320581D52EA6300316A6E /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; + B993205B1D530C9E00316A6E /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = ""; }; + B993205C1D530C9E00316A6E /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; + B993205E1D530CB200316A6E /* WKWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewController.h; sourceTree = ""; }; + B993205F1D530CB200316A6E /* WKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewController.m; sourceTree = ""; }; + B99320611D530E7100316A6E /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; + B99320631D530F5300316A6E /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + B99320661D5341D100316A6E /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B99320391D52E9EE00316A6E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B99320671D5341D100316A6E /* AVFoundation.framework in Frameworks */, + B99320641D530F5300316A6E /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B99320331D52E9EE00316A6E = { + isa = PBXGroup; + children = ( + B993203E1D52E9EE00316A6E /* JS_OC_URL */, + B99320651D530F5700316A6E /* Frameworks */, + B993203D1D52E9EE00316A6E /* Products */, + ); + sourceTree = ""; + }; + B993203D1D52E9EE00316A6E /* Products */ = { + isa = PBXGroup; + children = ( + B993203C1D52E9EE00316A6E /* JS_OC_URL.app */, + ); + name = Products; + sourceTree = ""; + }; + B993203E1D52E9EE00316A6E /* JS_OC_URL */ = { + isa = PBXGroup; + children = ( + B99320421D52E9EE00316A6E /* AppDelegate.h */, + B99320431D52E9EE00316A6E /* AppDelegate.m */, + B99320561D52EA6300316A6E /* MainViewController.h */, + B99320571D52EA6300316A6E /* MainViewController.m */, + B99320581D52EA6300316A6E /* MainViewController.xib */, + B993205B1D530C9E00316A6E /* WebViewController.h */, + B993205C1D530C9E00316A6E /* WebViewController.m */, + B993205E1D530CB200316A6E /* WKWebViewController.h */, + B993205F1D530CB200316A6E /* WKWebViewController.m */, + B99320611D530E7100316A6E /* index.html */, + B993203F1D52E9EE00316A6E /* Supporting Files */, + ); + path = JS_OC_URL; + sourceTree = ""; + }; + B993203F1D52E9EE00316A6E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B993204B1D52E9EE00316A6E /* Assets.xcassets */, + B993204D1D52E9EE00316A6E /* LaunchScreen.storyboard */, + B99320501D52E9EE00316A6E /* Info.plist */, + B99320401D52E9EE00316A6E /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B99320651D530F5700316A6E /* Frameworks */ = { + isa = PBXGroup; + children = ( + B99320661D5341D100316A6E /* AVFoundation.framework */, + B99320631D530F5300316A6E /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B993203B1D52E9EE00316A6E /* JS_OC_URL */ = { + isa = PBXNativeTarget; + buildConfigurationList = B99320531D52E9EE00316A6E /* Build configuration list for PBXNativeTarget "JS_OC_URL" */; + buildPhases = ( + B99320381D52E9EE00316A6E /* Sources */, + B99320391D52E9EE00316A6E /* Frameworks */, + B993203A1D52E9EE00316A6E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JS_OC_URL; + productName = JS_OC_URL; + productReference = B993203C1D52E9EE00316A6E /* JS_OC_URL.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B99320341D52E9EE00316A6E /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Haley; + TargetAttributes = { + B993203B1D52E9EE00316A6E = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = B99320371D52E9EE00316A6E /* Build configuration list for PBXProject "JS_OC_URL" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B99320331D52E9EE00316A6E; + productRefGroup = B993203D1D52E9EE00316A6E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B993203B1D52E9EE00316A6E /* JS_OC_URL */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B993203A1D52E9EE00316A6E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B993204F1D52E9EE00316A6E /* LaunchScreen.storyboard in Resources */, + B99320621D530E7100316A6E /* index.html in Resources */, + B993205A1D52EA6300316A6E /* MainViewController.xib in Resources */, + B993204C1D52E9EE00316A6E /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B99320381D52E9EE00316A6E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B99320601D530CB200316A6E /* WKWebViewController.m in Sources */, + B99320441D52E9EE00316A6E /* AppDelegate.m in Sources */, + B99320591D52EA6300316A6E /* MainViewController.m in Sources */, + B99320411D52E9EE00316A6E /* main.m in Sources */, + B993205D1D530C9E00316A6E /* WebViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B993204D1D52E9EE00316A6E /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B993204E1D52E9EE00316A6E /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B99320511D52E9EE00316A6E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B99320521D52E9EE00316A6E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B99320541D52E9EE00316A6E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_URL/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-URL"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B99320551D52E9EE00316A6E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_URL/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-URL"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B99320371D52E9EE00316A6E /* Build configuration list for PBXProject "JS_OC_URL" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B99320511D52E9EE00316A6E /* Debug */, + B99320521D52E9EE00316A6E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B99320531D52E9EE00316A6E /* Build configuration list for PBXNativeTarget "JS_OC_URL" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B99320541D52E9EE00316A6E /* Debug */, + B99320551D52E9EE00316A6E /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = B99320341D52E9EE00316A6E /* Project object */; +} diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1b9c5c7 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..412df61 Binary files /dev/null and b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..6a31f00 Binary files /dev/null and b/JS_OC_URL/JS_OC_URL.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..67cf702 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JS_OC_URL.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_URL.xcscheme b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_URL.xcscheme new file mode 100644 index 0000000..11a6e4e --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_URL.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7884bf9 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JS_OC_URL.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B993203B1D52E9EE00316A6E + + primary + + + + + diff --git a/JS_OC_URL/JS_OC_URL/AppDelegate.h b/JS_OC_URL/JS_OC_URL/AppDelegate.h new file mode 100644 index 0000000..fdb7583 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/JS_OC_URL/JS_OC_URL/AppDelegate.m b/JS_OC_URL/JS_OC_URL/AppDelegate.m new file mode 100644 index 0000000..530a7ba --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/AppDelegate.m @@ -0,0 +1,55 @@ +// +// AppDelegate.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "AppDelegate.h" +#import "MainViewController.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + + MainViewController *mainVC = [[MainViewController alloc] init]; + UINavigationController *NAV = [[UINavigationController alloc] initWithRootViewController:mainVC]; + self.window.rootViewController = NAV; + + [self.window makeKeyAndVisible]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/JS_OC_URL/JS_OC_URL/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_URL/JS_OC_URL/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/JS_OC_URL/JS_OC_URL/Base.lproj/LaunchScreen.storyboard b/JS_OC_URL/JS_OC_URL/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_URL/JS_OC_URL/Info.plist b/JS_OC_URL/JS_OC_URL/Info.plist new file mode 100644 index 0000000..29689d8 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/Info.plist @@ -0,0 +1,41 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/JS_OC_URL/JS_OC_URL/MainViewController.h b/JS_OC_URL/JS_OC_URL/MainViewController.h new file mode 100644 index 0000000..bb83c67 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/MainViewController.h @@ -0,0 +1,13 @@ +// +// MainViewController.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface MainViewController : UIViewController + +@end diff --git a/JS_OC_URL/JS_OC_URL/MainViewController.m b/JS_OC_URL/JS_OC_URL/MainViewController.m new file mode 100644 index 0000000..a71f0fb --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/MainViewController.m @@ -0,0 +1,36 @@ +// +// MainViewController.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "MainViewController.h" +#import "WebViewController.h" +#import "WKWebViewController.h" + +@interface MainViewController () + +@end + +@implementation MainViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + self.title = @"主页"; +} + +- (IBAction)btnClick1:(id)sender { + WebViewController *webVC = [[WebViewController alloc] init]; + [self.navigationController pushViewController:webVC animated:YES]; +} + + +- (IBAction)btnClick2:(id)sender { + WKWebViewController *wkWebVC = [[WKWebViewController alloc] init]; + [self.navigationController pushViewController:wkWebVC animated:YES]; +} + +@end diff --git a/JS_OC_URL/JS_OC_URL/MainViewController.xib b/JS_OC_URL/JS_OC_URL/MainViewController.xib new file mode 100644 index 0000000..aebb639 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/MainViewController.xib @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_URL/JS_OC_URL/WKWebViewController.h b/JS_OC_URL/JS_OC_URL/WKWebViewController.h new file mode 100644 index 0000000..5cdbbc5 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/WKWebViewController.h @@ -0,0 +1,13 @@ +// +// WKWebViewController.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WKWebViewController : UIViewController + +@end diff --git a/JS_OC_URL/JS_OC_URL/WKWebViewController.m b/JS_OC_URL/JS_OC_URL/WKWebViewController.m new file mode 100644 index 0000000..689c159 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/WKWebViewController.m @@ -0,0 +1,246 @@ +// +// WKWebViewController.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import + +#import "WKWebViewController.h" + +@interface WKWebViewController () + +@property (strong, nonatomic) WKWebView *webView; +@property (strong, nonatomic) UIProgressView *progressView; + +@end + +@implementation WKWebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"WKWebView拦截URL"; + + UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(rightClick)]; + self.navigationItem.rightBarButtonItem = rightItem; + + [self initWKWebView]; + + [self initProgressView]; + + [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; +} + +- (void)initWKWebView +{ + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + configuration.userContentController = [WKUserContentController new]; + + WKPreferences *preferences = [WKPreferences new]; + preferences.javaScriptCanOpenWindowsAutomatically = YES; + preferences.minimumFontSize = 30.0; + configuration.preferences = preferences; + + self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; + + +// NSString *urlStr = @"http://www.baidu.com"; +// NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]]; +// [self.webView loadRequest:request]; + + NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil]; + NSURL *fileURL = [NSURL fileURLWithPath:urlStr]; + [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL]; + + self.webView.navigationDelegate = self; + self.webView.UIDelegate = self; + [self.view addSubview:self.webView]; +} + +- (void)initProgressView +{ + CGFloat kScreenWidth = [[UIScreen mainScreen] bounds].size.width; + UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 2)]; + progressView.tintColor = [UIColor redColor]; + progressView.trackTintColor = [UIColor lightGrayColor]; + [self.view addSubview:progressView]; + self.progressView = progressView; +} + +- (void)rightClick +{ + [self goBack]; +} + +- (void)dealloc +{ + NSLog(@"%s",__FUNCTION__); + [self.webView removeObserver:self forKeyPath:@"estimatedProgress"]; +} + +#pragma mark - private method +- (void)handleCustomAction:(NSURL *)URL +{ + NSString *host = [URL host]; + if ([host isEqualToString:@"scanClick"]) { + NSLog(@"扫一扫"); + } else if ([host isEqualToString:@"shareClick"]) { + [self share:URL]; + } else if ([host isEqualToString:@"getLocation"]) { + [self getLocation]; + } else if ([host isEqualToString:@"setColor"]) { + [self changeBGColor:URL]; + } else if ([host isEqualToString:@"payAction"]) { + [self payAction:URL]; + } else if ([host isEqualToString:@"shake"]) { + [self shakeAction]; + } else if ([host isEqualToString:@"goBack"]) { + [self goBack]; + } + +} + +- (void)getLocation +{ + // 获取位置信息 + + // 将结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; + +} + +- (void)share:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } + + NSString *title = [tempDic objectForKey:@"title"]; + NSString *content = [tempDic objectForKey:@"content"]; + NSString *url = [tempDic objectForKey:@"url"]; + // 在这里执行分享的操作 + + // 将分享结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; +} + +- (void)changeBGColor:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } + CGFloat r = [[tempDic objectForKey:@"r"] floatValue]; + CGFloat g = [[tempDic objectForKey:@"g"] floatValue]; + CGFloat b = [[tempDic objectForKey:@"b"] floatValue]; + CGFloat a = [[tempDic objectForKey:@"a"] floatValue]; + + self.view.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; +} + +- (void)payAction:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } +// NSString *orderNo = [tempDic objectForKey:@"order_no"]; +// long long amount = [[tempDic objectForKey:@"amount"] longLongValue]; +// NSString *subject = [tempDic objectForKey:@"subject"]; +// NSString *channel = [tempDic objectForKey:@"channel"]; + + // 支付操作 + + // 将支付结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"payResult('%@', 1)",@"支付成功"]; + [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) { + NSLog(@"%@----%@",result, error); + }]; +} + +- (void)shakeAction +{ + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); +} + +- (void)goBack +{ + [self.webView goBack]; +} + +#pragma mark - KVO +// 计算wkWebView进度条 +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) { + CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue]; + if (newprogress == 1) { + [self.progressView setProgress:1.0 animated:YES]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + self.progressView.hidden = YES; + [self.progressView setProgress:0 animated:NO]; + }); + + }else { + self.progressView.hidden = NO; + [self.progressView setProgress:newprogress animated:YES]; + } + } +} + +#pragma mark - WKNavigationDelegate +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler +{ + NSURL *URL = navigationAction.request.URL; + NSString *scheme = [URL scheme]; + if ([scheme isEqualToString:@"haleyaction"]) { + + [self handleCustomAction:URL]; + + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + decisionHandler(WKNavigationActionPolicyAllow); +} + +#pragma mark - WKUIDelegate +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + completionHandler(); + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/JS_OC_URL/JS_OC_URL/WebViewController.h b/JS_OC_URL/JS_OC_URL/WebViewController.h new file mode 100644 index 0000000..fcc1c07 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/WebViewController.h @@ -0,0 +1,13 @@ +// +// WebViewController.h +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WebViewController : UIViewController + +@end diff --git a/JS_OC_URL/JS_OC_URL/WebViewController.m b/JS_OC_URL/JS_OC_URL/WebViewController.m new file mode 100644 index 0000000..60118c6 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/WebViewController.m @@ -0,0 +1,169 @@ +// +// WebViewController.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +#import "WebViewController.h" + +@interface WebViewController () + +@property (strong, nonatomic) UIWebView *webView; + +@end + +@implementation WebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"UIWebView拦截URL"; + self.view.backgroundColor = [UIColor whiteColor]; + + self.webView = [[UIWebView alloc] initWithFrame:self.view.frame]; + self.webView.delegate = self; + NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; +// NSURL *htmlURL = [NSURL URLWithString:@"http://www.baidu.com"]; + NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL]; + + // 如果不想要webView 的回弹效果 + self.webView.scrollView.bounces = NO; + // UIWebView 滚动的比较慢,这里设置为正常速度 + self.webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; + [self.webView loadRequest:request]; + [self.view addSubview:self.webView]; +} + +#pragma mark - private method +- (void)handleCustomAction:(NSURL *)URL +{ + NSString *host = [URL host]; + if ([host isEqualToString:@"scanClick"]) { + NSLog(@"扫一扫"); + } else if ([host isEqualToString:@"shareClick"]) { + [self share:URL]; + } else if ([host isEqualToString:@"getLocation"]) { + [self getLocation]; + } else if ([host isEqualToString:@"setColor"]) { + [self changeBGColor:URL]; + } else if ([host isEqualToString:@"payAction"]) { + [self payAction:URL]; + } else if ([host isEqualToString:@"shake"]) { + [self shakeAction]; + } else if ([host isEqualToString:@"goBack"]) { + [self goBack]; + } +} + +- (void)getLocation +{ + // 获取位置信息 + + // 将结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",@"广东省深圳市南山区学府路XXXX号"]; + [self.webView stringByEvaluatingJavaScriptFromString:jsStr]; +} + +- (void)share:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } + + NSString *title = [tempDic objectForKey:@"title"]; + NSString *content = [tempDic objectForKey:@"content"]; + NSString *url = [tempDic objectForKey:@"url"]; + // 在这里执行分享的操作 + + // 将分享结果返回给js + NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; + [self.webView stringByEvaluatingJavaScriptFromString:jsStr]; +} + +- (void)changeBGColor:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } + CGFloat r = [[tempDic objectForKey:@"r"] floatValue]; + CGFloat g = [[tempDic objectForKey:@"g"] floatValue]; + CGFloat b = [[tempDic objectForKey:@"b"] floatValue]; + CGFloat a = [[tempDic objectForKey:@"a"] floatValue]; + + // 这里修改背景色是因为有些场景没有导航栏,然后WebView 是从 状态栏下20开始布局,用于修改状态栏背景色 + self.view.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; +} + +- (void)payAction:(NSURL *)URL +{ + NSArray *params =[URL.query componentsSeparatedByString:@"&"]; + + NSMutableDictionary *tempDic = [NSMutableDictionary dictionary]; + for (NSString *paramStr in params) { + NSArray *dicArray = [paramStr componentsSeparatedByString:@"="]; + if (dicArray.count > 1) { + NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [tempDic setObject:decodeValue forKey:dicArray[0]]; + } + } +// NSString *orderNo = [tempDic objectForKey:@"order_no"]; +// long long amount = [[tempDic objectForKey:@"amount"] longLongValue]; +// NSString *subject = [tempDic objectForKey:@"subject"]; +// NSString *channel = [tempDic objectForKey:@"channel"]; + + // 支付操作 + + // 将支付结果返回给js + NSUInteger code = 1; + NSString *jsStr = [NSString stringWithFormat:@"payResult('%@',%lu)",@"支付成功",(unsigned long)code]; + [self.webView stringByEvaluatingJavaScriptFromString:jsStr]; +} + +- (void)shakeAction +{ + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); +} + +- (void)goBack +{ + [self.webView goBack]; +} + + +#pragma mark - UIWebViewDelegate +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType +{ + NSURL *URL = request.URL; + NSString *scheme = [URL scheme]; + if ([scheme isEqualToString:@"haleyaction"]) { + [self handleCustomAction:URL]; + return NO; + } + + return YES; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [webView stringByEvaluatingJavaScriptFromString:@"var arr = [3, 4, 'abc'];"]; +} + +@end diff --git a/JS_OC_URL/JS_OC_URL/index.html b/JS_OC_URL/JS_OC_URL/index.html new file mode 100644 index 0000000..4191a37 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/index.html @@ -0,0 +1,122 @@ + + + + + + + +

这是按钮调用

+ + + + + + + + +

这是文件上传

+ + + +

这是回调结果展示区

+ + +

竖直方向的表头:

+ + + + + + + + + + + + + +
姓名Bill Gates
电话555 77 854
传真555 77 855
+ + + + diff --git a/JS_OC_URL/JS_OC_URL/main.m b/JS_OC_URL/JS_OC_URL/main.m new file mode 100644 index 0000000..d9bfdf9 --- /dev/null +++ b/JS_OC_URL/JS_OC_URL/main.m @@ -0,0 +1,16 @@ +// +// main.m +// JS_OC_URL +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.pbxproj b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.pbxproj new file mode 100644 index 0000000..44071b1 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.pbxproj @@ -0,0 +1,359 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B95B2BC21D6EC32E0075119B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BC11D6EC32E0075119B /* main.m */; }; + B95B2BC51D6EC32E0075119B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BC41D6EC32E0075119B /* AppDelegate.m */; }; + B95B2BCD1D6EC32E0075119B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B95B2BCC1D6EC32E0075119B /* Assets.xcassets */; }; + B95B2BD01D6EC32E0075119B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B95B2BCE1D6EC32E0075119B /* LaunchScreen.storyboard */; }; + B95B2BDF1D6EC3750075119B /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BD81D6EC3750075119B /* MainViewController.m */; }; + B95B2BE01D6EC3750075119B /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B95B2BD91D6EC3750075119B /* MainViewController.xib */; }; + B95B2BE11D6EC3750075119B /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BDB1D6EC3750075119B /* WebViewController.m */; }; + B95B2BE21D6EC3750075119B /* WKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BDD1D6EC3750075119B /* WKWebViewController.m */; }; + B95B2BE31D6EC3750075119B /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = B95B2BDE1D6EC3750075119B /* index.html */; }; + B95B2BE61D6EC3E70075119B /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B95B2BE51D6EC3E70075119B /* WebKit.framework */; }; + B95B2BF01D6EC4840075119B /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BE91D6EC4840075119B /* WebViewJavascriptBridge.m */; }; + B95B2BF11D6EC4840075119B /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BEB1D6EC4840075119B /* WebViewJavascriptBridge_JS.m */; }; + B95B2BF21D6EC4840075119B /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BED1D6EC4840075119B /* WebViewJavascriptBridgeBase.m */; }; + B95B2BF31D6EC4840075119B /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = B95B2BEF1D6EC4840075119B /* WKWebViewJavascriptBridge.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + B95B2BBD1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JS_OC_WebViewJavascriptBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B95B2BC11D6EC32E0075119B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + B95B2BC31D6EC32E0075119B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + B95B2BC41D6EC32E0075119B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + B95B2BCC1D6EC32E0075119B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + B95B2BCF1D6EC32E0075119B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + B95B2BD11D6EC32E0075119B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B95B2BD71D6EC3750075119B /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; + B95B2BD81D6EC3750075119B /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; + B95B2BD91D6EC3750075119B /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; + B95B2BDA1D6EC3750075119B /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = ""; }; + B95B2BDB1D6EC3750075119B /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; + B95B2BDC1D6EC3750075119B /* WKWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewController.h; sourceTree = ""; }; + B95B2BDD1D6EC3750075119B /* WKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewController.m; sourceTree = ""; }; + B95B2BDE1D6EC3750075119B /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = ""; }; + B95B2BE51D6EC3E70075119B /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + B95B2BE81D6EC4840075119B /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; + B95B2BE91D6EC4840075119B /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; + B95B2BEA1D6EC4840075119B /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = ""; }; + B95B2BEB1D6EC4840075119B /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = ""; }; + B95B2BEC1D6EC4840075119B /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = ""; }; + B95B2BED1D6EC4840075119B /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; + B95B2BEE1D6EC4840075119B /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; + B95B2BEF1D6EC4840075119B /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B95B2BBA1D6EC32E0075119B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B95B2BE61D6EC3E70075119B /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B95B2BB41D6EC32E0075119B = { + isa = PBXGroup; + children = ( + B95B2BBF1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge */, + B95B2BE41D6EC3CB0075119B /* Frameworks */, + B95B2BBE1D6EC32E0075119B /* Products */, + ); + sourceTree = ""; + }; + B95B2BBE1D6EC32E0075119B /* Products */ = { + isa = PBXGroup; + children = ( + B95B2BBD1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge.app */, + ); + name = Products; + sourceTree = ""; + }; + B95B2BBF1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge */ = { + isa = PBXGroup; + children = ( + B95B2BE71D6EC4840075119B /* WebViewJavascriptBridge */, + B95B2BC31D6EC32E0075119B /* AppDelegate.h */, + B95B2BC41D6EC32E0075119B /* AppDelegate.m */, + B95B2BD71D6EC3750075119B /* MainViewController.h */, + B95B2BD81D6EC3750075119B /* MainViewController.m */, + B95B2BD91D6EC3750075119B /* MainViewController.xib */, + B95B2BDA1D6EC3750075119B /* WebViewController.h */, + B95B2BDB1D6EC3750075119B /* WebViewController.m */, + B95B2BDC1D6EC3750075119B /* WKWebViewController.h */, + B95B2BDD1D6EC3750075119B /* WKWebViewController.m */, + B95B2BDE1D6EC3750075119B /* index.html */, + B95B2BC01D6EC32E0075119B /* Supporting Files */, + ); + path = JS_OC_WebViewJavascriptBridge; + sourceTree = ""; + }; + B95B2BC01D6EC32E0075119B /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B95B2BCC1D6EC32E0075119B /* Assets.xcassets */, + B95B2BCE1D6EC32E0075119B /* LaunchScreen.storyboard */, + B95B2BD11D6EC32E0075119B /* Info.plist */, + B95B2BC11D6EC32E0075119B /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B95B2BE41D6EC3CB0075119B /* Frameworks */ = { + isa = PBXGroup; + children = ( + B95B2BE51D6EC3E70075119B /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B95B2BE71D6EC4840075119B /* WebViewJavascriptBridge */ = { + isa = PBXGroup; + children = ( + B95B2BE81D6EC4840075119B /* WebViewJavascriptBridge.h */, + B95B2BE91D6EC4840075119B /* WebViewJavascriptBridge.m */, + B95B2BEA1D6EC4840075119B /* WebViewJavascriptBridge_JS.h */, + B95B2BEB1D6EC4840075119B /* WebViewJavascriptBridge_JS.m */, + B95B2BEC1D6EC4840075119B /* WebViewJavascriptBridgeBase.h */, + B95B2BED1D6EC4840075119B /* WebViewJavascriptBridgeBase.m */, + B95B2BEE1D6EC4840075119B /* WKWebViewJavascriptBridge.h */, + B95B2BEF1D6EC4840075119B /* WKWebViewJavascriptBridge.m */, + ); + path = WebViewJavascriptBridge; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B95B2BBC1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge */ = { + isa = PBXNativeTarget; + buildConfigurationList = B95B2BD41D6EC32E0075119B /* Build configuration list for PBXNativeTarget "JS_OC_WebViewJavascriptBridge" */; + buildPhases = ( + B95B2BB91D6EC32E0075119B /* Sources */, + B95B2BBA1D6EC32E0075119B /* Frameworks */, + B95B2BBB1D6EC32E0075119B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = JS_OC_WebViewJavascriptBridge; + productName = JS_OC_WebViewJavascriptBridge; + productReference = B95B2BBD1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B95B2BB51D6EC32E0075119B /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = Haley; + TargetAttributes = { + B95B2BBC1D6EC32E0075119B = { + CreatedOnToolsVersion = 7.3; + }; + }; + }; + buildConfigurationList = B95B2BB81D6EC32E0075119B /* Build configuration list for PBXProject "JS_OC_WebViewJavascriptBridge" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B95B2BB41D6EC32E0075119B; + productRefGroup = B95B2BBE1D6EC32E0075119B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B95B2BBC1D6EC32E0075119B /* JS_OC_WebViewJavascriptBridge */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + B95B2BBB1D6EC32E0075119B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B95B2BD01D6EC32E0075119B /* LaunchScreen.storyboard in Resources */, + B95B2BE31D6EC3750075119B /* index.html in Resources */, + B95B2BE01D6EC3750075119B /* MainViewController.xib in Resources */, + B95B2BCD1D6EC32E0075119B /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B95B2BB91D6EC32E0075119B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B95B2BF21D6EC4840075119B /* WebViewJavascriptBridgeBase.m in Sources */, + B95B2BE21D6EC3750075119B /* WKWebViewController.m in Sources */, + B95B2BF01D6EC4840075119B /* WebViewJavascriptBridge.m in Sources */, + B95B2BC51D6EC32E0075119B /* AppDelegate.m in Sources */, + B95B2BF11D6EC4840075119B /* WebViewJavascriptBridge_JS.m in Sources */, + B95B2BF31D6EC4840075119B /* WKWebViewJavascriptBridge.m in Sources */, + B95B2BDF1D6EC3750075119B /* MainViewController.m in Sources */, + B95B2BC21D6EC32E0075119B /* main.m in Sources */, + B95B2BE11D6EC3750075119B /* WebViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + B95B2BCE1D6EC32E0075119B /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B95B2BCF1D6EC32E0075119B /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B95B2BD21D6EC32E0075119B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B95B2BD31D6EC32E0075119B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B95B2BD51D6EC32E0075119B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_WebViewJavascriptBridge/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-WebViewJavascriptBridge"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B95B2BD61D6EC32E0075119B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = JS_OC_WebViewJavascriptBridge/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.suneee.JS-OC-WebViewJavascriptBridge"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B95B2BB81D6EC32E0075119B /* Build configuration list for PBXProject "JS_OC_WebViewJavascriptBridge" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B95B2BD21D6EC32E0075119B /* Debug */, + B95B2BD31D6EC32E0075119B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B95B2BD41D6EC32E0075119B /* Build configuration list for PBXNativeTarget "JS_OC_WebViewJavascriptBridge" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B95B2BD51D6EC32E0075119B /* Debug */, + B95B2BD61D6EC32E0075119B /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = B95B2BB51D6EC32E0075119B /* Project object */; +} diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b018ca1 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..4d24413 Binary files /dev/null and b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/project.xcworkspace/xcuserdata/harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..07bae77 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_WebViewJavascriptBridge.xcscheme b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_WebViewJavascriptBridge.xcscheme new file mode 100644 index 0000000..f207f77 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/JS_OC_WebViewJavascriptBridge.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..e6ab89d --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge.xcodeproj/xcuserdata/harvey.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + JS_OC_WebViewJavascriptBridge.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + B95B2BBC1D6EC32E0075119B + + primary + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.h new file mode 100644 index 0000000..d531f86 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/25. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.m new file mode 100644 index 0000000..b3a565b --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/AppDelegate.m @@ -0,0 +1,55 @@ +// +// AppDelegate.m +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/25. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "AppDelegate.h" +#import "MainViewController.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + self.window.backgroundColor = [UIColor whiteColor]; + + MainViewController *mainVC = [[MainViewController alloc] init]; + UINavigationController *NAV = [[UINavigationController alloc] initWithRootViewController:mainVC]; + self.window.rootViewController = NAV; + + [self.window makeKeyAndVisible]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Base.lproj/LaunchScreen.storyboard b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Info.plist b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Info.plist new file mode 100644 index 0000000..61861ab --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.h new file mode 100644 index 0000000..23b74da --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.h @@ -0,0 +1,13 @@ +// +// MainViewController.h +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface MainViewController : UIViewController + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.m new file mode 100644 index 0000000..bdf8166 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.m @@ -0,0 +1,36 @@ +// +// MainViewController.m +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import "MainViewController.h" +#import "WebViewController.h" +#import "WKWebViewController.h" + +@interface MainViewController () + +@end + +@implementation MainViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + self.title = @"主页"; +} + +- (IBAction)btnClick1:(id)sender { + WebViewController *webVC = [[WebViewController alloc] init]; + [self.navigationController pushViewController:webVC animated:YES]; +} + + +- (IBAction)btnClick2:(id)sender { + WKWebViewController *wkWebVC = [[WKWebViewController alloc] init]; + [self.navigationController pushViewController:wkWebVC animated:YES]; +} + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.xib b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.xib new file mode 100644 index 0000000..2b552df --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/MainViewController.xib @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.h new file mode 100644 index 0000000..51ea874 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.h @@ -0,0 +1,13 @@ +// +// WKWebViewController.h +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WKWebViewController : UIViewController + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.m new file mode 100644 index 0000000..dcb3ca2 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WKWebViewController.m @@ -0,0 +1,233 @@ +// +// WKWebViewController.m +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import + +#import "WKWebViewController.h" +#import "WKWebViewJavascriptBridge.h" + +@interface WKWebViewController () + +@property (strong, nonatomic) WKWebView *webView; +@property (strong, nonatomic) UIProgressView *progressView; + +@property WKWebViewJavascriptBridge *webViewBridge; + +@end + +@implementation WKWebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"WKWebView--WebViewJavascriptBridge"; + self.view.backgroundColor = [UIColor whiteColor]; + + UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(rightClick)]; + self.navigationItem.rightBarButtonItem = rightItem; + + [self initWKWebView]; + + _webViewBridge = [WKWebViewJavascriptBridge bridgeForWebView:self.webView]; + [_webViewBridge setWebViewDelegate:self]; + + [self registerNativeFunctions]; + + [self initProgressView]; + + [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil]; + +} + +- (void)initWKWebView +{ + WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; + configuration.userContentController = [WKUserContentController new]; + + WKPreferences *preferences = [WKPreferences new]; + preferences.javaScriptCanOpenWindowsAutomatically = YES; + preferences.minimumFontSize = 30.0; + configuration.preferences = preferences; + + self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; + + NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil]; + NSString *localHtml = [NSString stringWithContentsOfFile:urlStr encoding:NSUTF8StringEncoding error:nil]; + NSURL *fileURL = [NSURL fileURLWithPath:urlStr]; + [self.webView loadHTMLString:localHtml baseURL:fileURL]; + + self.webView.UIDelegate = self; + [self.view addSubview:self.webView]; +} + +- (void)initProgressView +{ + CGFloat kScreenWidth = [[UIScreen mainScreen] bounds].size.width; + UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 2)]; + progressView.tintColor = [UIColor redColor]; + progressView.trackTintColor = [UIColor lightGrayColor]; + [self.view addSubview:progressView]; + self.progressView = progressView; +} + +- (void)rightClick +{ + // // 如果不需要参数,不需要回调,使用这个 + // [_webViewBridge callHandler:@"testJSFunction"]; + // // 如果需要参数,不需要回调,使用这个 + // [_webViewBridge callHandler:@"testJSFunction" data:@"一个字符串"]; + // 如果既需要参数,又需要回调,使用这个 + [_webViewBridge callHandler:@"testJSFunction" data:@"一个字符串" responseCallback:^(id responseData) { + NSLog(@"调用完JS后的回调:%@",responseData); + }]; +} + +- (void)dealloc +{ + NSLog(@"%s",__FUNCTION__); + [self.webView removeObserver:self forKeyPath:@"estimatedProgress"]; +} + +#pragma mark - private method +- (void)registerNativeFunctions +{ + [self registScanFunction]; + + [self registShareFunction]; + + [self registLocationFunction]; + + [self regitstBGColorFunction]; + + [self registPayFunction]; + + [self registShakeFunction]; +} + +- (void)registLocationFunction +{ + [_webViewBridge registerHandler:@"locationClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // 获取位置信息 + + NSString *location = @"广东省深圳市南山区学府路XXXX号"; + // 将结果返回给js + responseCallback(location); + }]; +} + +- (void)registScanFunction +{ + // 注册的handler 是供 JS调用Native 使用的。 + [_webViewBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"扫一扫"); + NSString *scanResult = @"http://www.baidu.com"; + responseCallback(scanResult); + }]; +} + +- (void)registShareFunction +{ + [_webViewBridge registerHandler:@"shareClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + // 在这里执行分享的操作 + NSString *title = [tempDic objectForKey:@"title"]; + NSString *content = [tempDic objectForKey:@"content"]; + NSString *url = [tempDic objectForKey:@"url"]; + + // 将分享的结果返回到JS中 + NSString *result = [NSString stringWithFormat:@"分享成功:%@,%@,%@",title,content,url]; + responseCallback(result); + }]; +} + +- (void)regitstBGColorFunction +{ + __weak typeof(self) weakSelf = self; + [_webViewBridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + + CGFloat r = [[tempDic objectForKey:@"r"] floatValue]; + CGFloat g = [[tempDic objectForKey:@"g"] floatValue]; + CGFloat b = [[tempDic objectForKey:@"b"] floatValue]; + CGFloat a = [[tempDic objectForKey:@"a"] floatValue]; + + weakSelf.webView.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; + }]; +} + +- (void)registPayFunction +{ + [_webViewBridge registerHandler:@"payClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + + NSString *orderNo = [tempDic objectForKey:@"order_no"]; + long long amount = [[tempDic objectForKey:@"amount"] longLongValue]; + NSString *subject = [tempDic objectForKey:@"subject"]; + NSString *channel = [tempDic objectForKey:@"channel"]; + // 支付操作... + + // 将分享的结果返回到JS中 + NSString *result = [NSString stringWithFormat:@"支付成功:%@,%@,%@",orderNo,subject,channel]; + responseCallback(result); + }]; +} + +- (void)registShakeFunction +{ + [_webViewBridge registerHandler:@"shakeClick" handler:^(id data, WVJBResponseCallback responseCallback) { + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); + }]; +} + +- (void)registGoBackFunction +{ + __weak typeof(self) weakSelf = self; + [_webViewBridge registerHandler:@"goback" handler:^(id data, WVJBResponseCallback responseCallback) { + [weakSelf.webView goBack]; + }]; +} + +#pragma mark - KVO +// 计算wkWebView进度条 +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if (object == self.webView && [keyPath isEqualToString:@"estimatedProgress"]) { + CGFloat newprogress = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue]; + if (newprogress == 1) { + [self.progressView setProgress:1.0 animated:YES]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + self.progressView.hidden = YES; + [self.progressView setProgress:0 animated:NO]; + }); + + }else { + self.progressView.hidden = NO; + [self.progressView setProgress:newprogress animated:YES]; + } + } +} + +#pragma mark - WKNavigationDelegate + + +#pragma mark - WKUIDelegate +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + completionHandler(); + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.h new file mode 100644 index 0000000..7435ff6 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.h @@ -0,0 +1,13 @@ +// +// WebViewController.h +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +@interface WebViewController : UIViewController + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.m new file mode 100644 index 0000000..3adb336 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewController.m @@ -0,0 +1,170 @@ +// +// WebViewController.m +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/4. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import + +#import "WebViewController.h" +#import "WebViewJavascriptBridge.h" + +@interface WebViewController () + +@property (strong, nonatomic) UIWebView *webView; + +@property WebViewJavascriptBridge *webViewBridge; + +@end + +@implementation WebViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.title = @"UIWebView--WebViewJavascriptBridgeL"; + self.view.backgroundColor = [UIColor whiteColor]; + + UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:self action:@selector(rightClick)]; + self.navigationItem.rightBarButtonItem = rightItem; + + self.webView = [[UIWebView alloc] initWithFrame:self.view.frame]; + [self.view addSubview:self.webView]; + + NSURL *htmlURL = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil]; + NSURLRequest *request = [NSURLRequest requestWithURL:htmlURL]; + + // UIWebView 滚动的比较慢,这里设置为正常速度 + self.webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal; + [self.webView loadRequest:request]; + + _webViewBridge = [WebViewJavascriptBridge bridgeForWebView:self.webView]; + [_webViewBridge setWebViewDelegate:self]; + + // 添加JS 要调用的Native 功能 + [self registerNativeFunctions]; +} + +- (void)dealloc +{ + NSLog(@"%s",__func__); +} + +- (void)rightClick +{ +// // 如果不需要参数,不需要回调,使用这个 +// [_webViewBridge callHandler:@"testJSFunction"]; +// // 如果需要参数,不需要回调,使用这个 +// [_webViewBridge callHandler:@"testJSFunction" data:@"一个字符串"]; + // 如果既需要参数,又需要回调,使用这个 + [_webViewBridge callHandler:@"testJSFunction" data:@"一个字符串" responseCallback:^(id responseData) { + NSLog(@"调用完JS后的回调:%@",responseData); + }]; +} + +#pragma mark - private method +- (void)registerNativeFunctions +{ + [self registScanFunction]; + + [self registShareFunction]; + + [self registLocationFunction]; + + [self regitstBGColorFunction]; + + [self registPayFunction]; + + [self registShakeFunction]; +} + +- (void)registLocationFunction +{ + [_webViewBridge registerHandler:@"locationClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // 获取位置信息 + + NSString *location = @"广东省深圳市南山区学府路XXXX号"; + // 将结果返回给js + responseCallback(location); + }]; +} + +- (void)registScanFunction +{ + // 注册的handler 是供 JS调用Native 使用的。 + [_webViewBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"扫一扫"); + NSString *scanResult = @"http://www.baidu.com"; + responseCallback(scanResult); + }]; +} + +- (void)registShareFunction +{ + [_webViewBridge registerHandler:@"shareClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + // 在这里执行分享的操作 + NSString *title = [tempDic objectForKey:@"title"]; + NSString *content = [tempDic objectForKey:@"content"]; + NSString *url = [tempDic objectForKey:@"url"]; + + // 将分享的结果返回到JS中 + NSString *result = [NSString stringWithFormat:@"分享成功:%@,%@,%@",title,content,url]; + responseCallback(result); + }]; +} + +- (void)regitstBGColorFunction +{ + __weak typeof(self) weakSelf = self; + [_webViewBridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + + CGFloat r = [[tempDic objectForKey:@"r"] floatValue]; + CGFloat g = [[tempDic objectForKey:@"g"] floatValue]; + CGFloat b = [[tempDic objectForKey:@"b"] floatValue]; + CGFloat a = [[tempDic objectForKey:@"a"] floatValue]; + + weakSelf.webView.backgroundColor = [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:a]; + }]; +} + +- (void)registPayFunction +{ + [_webViewBridge registerHandler:@"payClick" handler:^(id data, WVJBResponseCallback responseCallback) { + // data 的类型与 JS中传的参数有关 + NSDictionary *tempDic = data; + + NSString *orderNo = [tempDic objectForKey:@"order_no"]; + long long amount = [[tempDic objectForKey:@"amount"] longLongValue]; + NSString *subject = [tempDic objectForKey:@"subject"]; + NSString *channel = [tempDic objectForKey:@"channel"]; + // 支付操作... + + // 将分享的结果返回到JS中 + NSString *result = [NSString stringWithFormat:@"支付成功:%@,%@,%@",orderNo,subject,channel]; + responseCallback(result); + }]; +} + +- (void)registShakeFunction +{ + [_webViewBridge registerHandler:@"shakeClick" handler:^(id data, WVJBResponseCallback responseCallback) { + AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); + }]; +} + +- (void)registGoBackFunction +{ + __weak typeof(self) weakSelf = self; + [_webViewBridge registerHandler:@"goback" handler:^(id data, WVJBResponseCallback responseCallback) { + [weakSelf.webView goBack]; + }]; +} + + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h new file mode 100755 index 0000000..5136f8d --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h @@ -0,0 +1,33 @@ +// +// WKWebViewJavascriptBridge.h +// +// Created by @LokiMeyburg on 10/15/14. +// Copyright (c) 2014 @LokiMeyburg. All rights reserved. +// + +#if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) +#define supportsWKWebKit +#endif + +#if defined(supportsWKWebKit ) + +#import +#import "WebViewJavascriptBridgeBase.h" +#import + +@interface WKWebViewJavascriptBridge : NSObject + ++ (instancetype)bridgeForWebView:(WKWebView*)webView; ++ (void)enableLogging; + +- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; +- (void)callHandler:(NSString*)handlerName; +- (void)callHandler:(NSString*)handlerName data:(id)data; +- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; +- (void)reset; +- (void)setWebViewDelegate:(id)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; + +@end + +#endif \ No newline at end of file diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m new file mode 100755 index 0000000..31dd8c5 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m @@ -0,0 +1,185 @@ +// +// WKWebViewJavascriptBridge.m +// +// Created by @LokiMeyburg on 10/15/14. +// Copyright (c) 2014 @LokiMeyburg. All rights reserved. +// + + +#import "WKWebViewJavascriptBridge.h" + +#if defined(supportsWKWebKit) + +@implementation WKWebViewJavascriptBridge { + __weak WKWebView* _webView; + __weak id _webViewDelegate; + long _uniqueId; + WebViewJavascriptBridgeBase *_base; +} + +/* API + *****/ + ++ (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } + ++ (instancetype)bridgeForWebView:(WKWebView*)webView { + WKWebViewJavascriptBridge* bridge = [[self alloc] init]; + [bridge _setupInstance:webView]; + [bridge reset]; + return bridge; +} + +- (void)send:(id)data { + [self send:data responseCallback:nil]; +} + +- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [_base sendData:data responseCallback:responseCallback handlerName:nil]; +} + +- (void)callHandler:(NSString *)handlerName { + [self callHandler:handlerName data:nil responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data { + [self callHandler:handlerName data:data responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [_base sendData:data responseCallback:responseCallback handlerName:handlerName]; +} + +- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { + _base.messageHandlers[handlerName] = [handler copy]; +} + +- (void)reset { + [_base reset]; +} + +- (void)setWebViewDelegate:(id)webViewDelegate { + _webViewDelegate = webViewDelegate; +} + +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + +/* Internals + ***********/ + +- (void)dealloc { + _base = nil; + _webView = nil; + _webViewDelegate = nil; + _webView.navigationDelegate = nil; +} + + +/* WKWebView Specific Internals + ******************************/ + +- (void) _setupInstance:(WKWebView*)webView { + _webView = webView; + _webView.navigationDelegate = self; + _base = [[WebViewJavascriptBridgeBase alloc] init]; + _base.delegate = self; +} + + +- (void)WKFlushMessageQueue { + [_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) { + if (error != nil) { + NSLog(@"WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@", error); + } + [_base flushMessageQueue:result]; + }]; +} + +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation +{ + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) { + [strongDelegate webView:webView didFinishNavigation:navigation]; + } +} + +- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler +{ + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)]) { + [strongDelegate webView:webView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler]; + } +} + +- (void)webView:(WKWebView *)webView +decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction +decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { + if (webView != _webView) { return; } + NSURL *url = navigationAction.request.URL; + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + + if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isBridgeLoadedURL:url]) { + [_base injectJavascriptFile]; + } else if ([_base isQueueMessageURL:url]) { + [self WKFlushMessageQueue]; + } else { + [_base logUnkownMessage:url]; + } + decisionHandler(WKNavigationActionPolicyCancel); + } + + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) { + [_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]; + } else { + decisionHandler(WKNavigationActionPolicyAllow); + } +} + +- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)]) { + [strongDelegate webView:webView didStartProvisionalNavigation:navigation]; + } +} + + +- (void)webView:(WKWebView *)webView +didFailNavigation:(WKNavigation *)navigation + withError:(NSError *)error { + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) { + [strongDelegate webView:webView didFailNavigation:navigation withError:error]; + } +} + +- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { + if (webView != _webView) { return; } + + __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)]) { + [strongDelegate webView:webView didFailProvisionalNavigation:navigation withError:error]; + } +} + +- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand +{ + [_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; + return NULL; +} + + + +@end + + +#endif diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h new file mode 100755 index 0000000..0996944 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -0,0 +1,39 @@ +// +// WebViewJavascriptBridge.h +// ExampleApp-iOS +// +// Created by Marcus Westin on 6/14/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import +#import "WebViewJavascriptBridgeBase.h" + +#if defined __MAC_OS_X_VERSION_MAX_ALLOWED + #import + #define WVJB_PLATFORM_OSX + #define WVJB_WEBVIEW_TYPE WebView + #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject + #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject +#elif defined __IPHONE_OS_VERSION_MAX_ALLOWED + #import + #define WVJB_PLATFORM_IOS + #define WVJB_WEBVIEW_TYPE UIWebView + #define WVJB_WEBVIEW_DELEGATE_TYPE NSObject + #define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject +#endif + +@interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_INTERFACE + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView; ++ (void)enableLogging; ++ (void)setLogMaxLength:(int)length; + +- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; +- (void)callHandler:(NSString*)handlerName; +- (void)callHandler:(NSString*)handlerName data:(id)data; +- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; +- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate; +- (void)disableJavscriptAlertBoxSafetyTimeout; + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m new file mode 100755 index 0000000..68a6964 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -0,0 +1,190 @@ +// +// WebViewJavascriptBridge.m +// ExampleApp-iOS +// +// Created by Marcus Westin on 6/14/13. +// Copyright (c) 2013 Marcus Westin. All rights reserved. +// + +#import "WebViewJavascriptBridge.h" + +#if __has_feature(objc_arc_weak) + #define WVJB_WEAK __weak +#else + #define WVJB_WEAK __unsafe_unretained +#endif + +@implementation WebViewJavascriptBridge { + WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView; + WVJB_WEAK id _webViewDelegate; + long _uniqueId; + WebViewJavascriptBridgeBase *_base; +} + +/* API + *****/ + ++ (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } ++ (void)setLogMaxLength:(int)length { [WebViewJavascriptBridgeBase setLogMaxLength:length]; } + ++ (instancetype)bridgeForWebView:(WVJB_WEBVIEW_TYPE*)webView { + WebViewJavascriptBridge* bridge = [[self alloc] init]; + [bridge _platformSpecificSetup:webView]; + return bridge; +} + +- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate { + _webViewDelegate = webViewDelegate; +} + +- (void)send:(id)data { + [self send:data responseCallback:nil]; +} + +- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [_base sendData:data responseCallback:responseCallback handlerName:nil]; +} + +- (void)callHandler:(NSString *)handlerName { + [self callHandler:handlerName data:nil responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data { + [self callHandler:handlerName data:data responseCallback:nil]; +} + +- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { + [_base sendData:data responseCallback:responseCallback handlerName:handlerName]; +} + +- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { + _base.messageHandlers[handlerName] = [handler copy]; +} + +- (void)disableJavscriptAlertBoxSafetyTimeout { + [_base disableJavscriptAlertBoxSafetyTimeout]; +} + + +/* Platform agnostic internals + *****************************/ + +- (void)dealloc { + [self _platformSpecificDealloc]; + _base = nil; + _webView = nil; + _webViewDelegate = nil; +} + +- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand +{ + return [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand]; +} + +/* Platform specific internals: OSX + **********************************/ +#if defined WVJB_PLATFORM_OSX + +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { + _webView = webView; + + _webView.policyDelegate = self; + + _base = [[WebViewJavascriptBridgeBase alloc] init]; + _base.delegate = self; +} + +- (void) _platformSpecificDealloc { + _webView.policyDelegate = nil; +} + +- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener +{ + if (webView != _webView) { return; } + + NSURL *url = [request URL]; + if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isBridgeLoadedURL:url]) { + [_base injectJavascriptFile]; + } else if ([_base isQueueMessageURL:url]) { + NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; + [_base flushMessageQueue:messageQueueString]; + } else { + [_base logUnkownMessage:url]; + } + [listener ignore]; + } else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { + [_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; + } else { + [listener use]; + } +} + + + +/* Platform specific internals: iOS + **********************************/ +#elif defined WVJB_PLATFORM_IOS + +- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { + _webView = webView; + _webView.delegate = self; + _base = [[WebViewJavascriptBridgeBase alloc] init]; + _base.delegate = self; +} + +- (void) _platformSpecificDealloc { + _webView.delegate = nil; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + if (webView != _webView) { return; } + + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { + [strongDelegate webViewDidFinishLoad:webView]; + } +} + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + if (webView != _webView) { return; } + + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { + [strongDelegate webView:webView didFailLoadWithError:error]; + } +} + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + if (webView != _webView) { return YES; } + NSURL *url = [request URL]; + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; + if ([_base isCorrectProcotocolScheme:url]) { + if ([_base isBridgeLoadedURL:url]) { + [_base injectJavascriptFile]; + } else if ([_base isQueueMessageURL:url]) { + NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; + [_base flushMessageQueue:messageQueueString]; + } else { + [_base logUnkownMessage:url]; + } + return NO; + } else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { + return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; + } else { + return YES; + } +} + +- (void)webViewDidStartLoad:(UIWebView *)webView { + if (webView != _webView) { return; } + + __strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; + if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { + [strongDelegate webViewDidStartLoad:webView]; + } +} + +#endif + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h new file mode 100755 index 0000000..3cf5a31 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.h @@ -0,0 +1,45 @@ +// +// WebViewJavascriptBridgeBase.h +// +// Created by @LokiMeyburg on 10/15/14. +// Copyright (c) 2014 @LokiMeyburg. All rights reserved. +// + +#import + +#define kCustomProtocolScheme @"wvjbscheme" +#define kQueueHasMessage @"__WVJB_QUEUE_MESSAGE__" +#define kBridgeLoaded @"__BRIDGE_LOADED__" + +typedef void (^WVJBResponseCallback)(id responseData); +typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); +typedef NSDictionary WVJBMessage; + +@protocol WebViewJavascriptBridgeBaseDelegate +- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand; +@end + +@interface WebViewJavascriptBridgeBase : NSObject + + +@property (weak, nonatomic) id delegate; +@property (strong, nonatomic) NSMutableArray* startupMessageQueue; +@property (strong, nonatomic) NSMutableDictionary* responseCallbacks; +@property (strong, nonatomic) NSMutableDictionary* messageHandlers; +@property (strong, nonatomic) WVJBHandler messageHandler; + ++ (void)enableLogging; ++ (void)setLogMaxLength:(int)length; +- (void)reset; +- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; +- (void)flushMessageQueue:(NSString *)messageQueueString; +- (void)injectJavascriptFile; +- (BOOL)isCorrectProcotocolScheme:(NSURL*)url; +- (BOOL)isQueueMessageURL:(NSURL*)urll; +- (BOOL)isBridgeLoadedURL:(NSURL*)urll; +- (void)logUnkownMessage:(NSURL*)url; +- (NSString *)webViewJavascriptCheckCommand; +- (NSString *)webViewJavascriptFetchQueyCommand; +- (void)disableJavscriptAlertBoxSafetyTimeout; + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m new file mode 100755 index 0000000..2711914 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridgeBase.m @@ -0,0 +1,218 @@ +// +// WebViewJavascriptBridgeBase.m +// +// Created by @LokiMeyburg on 10/15/14. +// Copyright (c) 2014 @LokiMeyburg. All rights reserved. +// + +#import +#import "WebViewJavascriptBridgeBase.h" +#import "WebViewJavascriptBridge_JS.h" + +@implementation WebViewJavascriptBridgeBase { + __weak id _webViewDelegate; + long _uniqueId; +} + +static bool logging = false; +static int logMaxLength = 500; + ++ (void)enableLogging { logging = true; } ++ (void)setLogMaxLength:(int)length { logMaxLength = length;} + +-(id)init { + self = [super init]; + self.messageHandlers = [NSMutableDictionary dictionary]; + self.startupMessageQueue = [NSMutableArray array]; + self.responseCallbacks = [NSMutableDictionary dictionary]; + _uniqueId = 0; + return(self); +} + +- (void)dealloc { + self.startupMessageQueue = nil; + self.responseCallbacks = nil; + self.messageHandlers = nil; +} + +- (void)reset { + self.startupMessageQueue = [NSMutableArray array]; + self.responseCallbacks = [NSMutableDictionary dictionary]; + _uniqueId = 0; +} + +- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { + NSMutableDictionary* message = [NSMutableDictionary dictionary]; + + if (data) { + message[@"data"] = data; + } + + if (responseCallback) { + NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId]; + self.responseCallbacks[callbackId] = [responseCallback copy]; + message[@"callbackId"] = callbackId; + } + + if (handlerName) { + message[@"handlerName"] = handlerName; + } + [self _queueMessage:message]; +} + +- (void)flushMessageQueue:(NSString *)messageQueueString{ + if (messageQueueString == nil || messageQueueString.length == 0) { + NSLog(@"WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page."); + return; + } + + id messages = [self _deserializeMessageJSON:messageQueueString]; + for (WVJBMessage* message in messages) { + if (![message isKindOfClass:[WVJBMessage class]]) { + NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); + continue; + } + [self _log:@"RCVD" json:message]; + + NSString* responseId = message[@"responseId"]; + if (responseId) { + WVJBResponseCallback responseCallback = _responseCallbacks[responseId]; + responseCallback(message[@"responseData"]); + [self.responseCallbacks removeObjectForKey:responseId]; + } else { + WVJBResponseCallback responseCallback = NULL; + NSString* callbackId = message[@"callbackId"]; + if (callbackId) { + responseCallback = ^(id responseData) { + if (responseData == nil) { + responseData = [NSNull null]; + } + + WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; + [self _queueMessage:msg]; + }; + } else { + responseCallback = ^(id ignoreResponseData) { + // Do nothing + }; + } + + WVJBHandler handler = self.messageHandlers[message[@"handlerName"]]; + + if (!handler) { + NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message); + continue; + } + + handler(message[@"data"], responseCallback); + } + } +} + +- (void)injectJavascriptFile { + NSString *js = WebViewJavascriptBridge_js(); + [self _evaluateJavascript:js]; + if (self.startupMessageQueue) { + NSArray* queue = self.startupMessageQueue; + self.startupMessageQueue = nil; + for (id queuedMessage in queue) { + [self _dispatchMessage:queuedMessage]; + } + } +} + +-(BOOL)isCorrectProcotocolScheme:(NSURL*)url { + if([[url scheme] isEqualToString:kCustomProtocolScheme]){ + return YES; + } else { + return NO; + } +} + +-(BOOL)isQueueMessageURL:(NSURL*)url { + if([[url host] isEqualToString:kQueueHasMessage]){ + return YES; + } else { + return NO; + } +} + +-(BOOL)isBridgeLoadedURL:(NSURL*)url { + return ([[url scheme] isEqualToString:kCustomProtocolScheme] && [[url host] isEqualToString:kBridgeLoaded]); +} + +-(void)logUnkownMessage:(NSURL*)url { + NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@://%@", kCustomProtocolScheme, [url path]); +} + +-(NSString *)webViewJavascriptCheckCommand { + return @"typeof WebViewJavascriptBridge == \'object\';"; +} + +-(NSString *)webViewJavascriptFetchQueyCommand { + return @"WebViewJavascriptBridge._fetchQueue();"; +} + +- (void)disableJavscriptAlertBoxSafetyTimeout { + [self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"]; +} + +// Private +// ------------------------------------------- + +- (void) _evaluateJavascript:(NSString *)javascriptCommand { + [self.delegate _evaluateJavascript:javascriptCommand]; +} + +- (void)_queueMessage:(WVJBMessage*)message { + if (self.startupMessageQueue) { + [self.startupMessageQueue addObject:message]; + } else { + [self _dispatchMessage:message]; + } +} + +- (void)_dispatchMessage:(WVJBMessage*)message { + NSString *messageJSON = [self _serializeMessage:message pretty:NO]; + [self _log:@"SEND" json:messageJSON]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; + messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; + + NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; + if ([[NSThread currentThread] isMainThread]) { + [self _evaluateJavascript:javascriptCommand]; + + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ + [self _evaluateJavascript:javascriptCommand]; + }); + } +} + +- (NSString *)_serializeMessage:(id)message pretty:(BOOL)pretty{ + return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:(NSJSONWritingOptions)(pretty ? NSJSONWritingPrettyPrinted : 0) error:nil] encoding:NSUTF8StringEncoding]; +} + +- (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON { + return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; +} + +- (void)_log:(NSString *)action json:(id)json { + if (!logging) { return; } + if (![json isKindOfClass:[NSString class]]) { + json = [self _serializeMessage:json pretty:YES]; + } + if ([json length] > logMaxLength) { + NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:logMaxLength]); + } else { + NSLog(@"WVJB %@: %@", action, json); + } +} + +@end diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.h b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.h new file mode 100755 index 0000000..6cb1cb9 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.h @@ -0,0 +1,3 @@ +#import + +NSString * WebViewJavascriptBridge_js(); \ No newline at end of file diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m new file mode 100755 index 0000000..c99b7e6 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/WebViewJavascriptBridge/WebViewJavascriptBridge_JS.m @@ -0,0 +1,139 @@ +// This file contains the source for the Javascript side of the +// WebViewJavascriptBridge. It is plaintext, but converted to an NSString +// via some preprocessor tricks. +// +// Previous implementations of WebViewJavascriptBridge loaded the javascript source +// from a resource. This worked fine for app developers, but library developers who +// included the bridge into their library, awkwardly had to ask consumers of their +// library to include the resource, violating their encapsulation. By including the +// Javascript as a string resource, the encapsulation of the library is maintained. + +#import "WebViewJavascriptBridge_JS.h" + +NSString * WebViewJavascriptBridge_js() { + #define __wvjb_js_func__(x) #x + + // BEGIN preprocessorJSCode + static NSString * preprocessorJSCode = @__wvjb_js_func__( +;(function() { + if (window.WebViewJavascriptBridge) { + return; + } + + if (!window.onerror) { + window.onerror = function(msg, url, line) { + console.log("WebViewJavascriptBridge: ERROR:" + msg + "@" + url + ":" + line); + } + } + window.WebViewJavascriptBridge = { + registerHandler: registerHandler, + callHandler: callHandler, + disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, + _fetchQueue: _fetchQueue, + _handleMessageFromObjC: _handleMessageFromObjC + }; + + var messagingIframe; + var sendMessageQueue = []; + var messageHandlers = {}; + + var CUSTOM_PROTOCOL_SCHEME = 'wvjbscheme'; + var QUEUE_HAS_MESSAGE = '__WVJB_QUEUE_MESSAGE__'; + + var responseCallbacks = {}; + var uniqueId = 1; + var dispatchMessagesWithTimeoutSafety = true; + + function registerHandler(handlerName, handler) { + messageHandlers[handlerName] = handler; + } + + function callHandler(handlerName, data, responseCallback) { + if (arguments.length == 2 && typeof data == 'function') { + responseCallback = data; + data = null; + } + _doSend({ handlerName:handlerName, data:data }, responseCallback); + } + function disableJavscriptAlertBoxSafetyTimeout() { + dispatchMessagesWithTimeoutSafety = false; + } + + function _doSend(message, responseCallback) { + if (responseCallback) { + var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime(); + responseCallbacks[callbackId] = responseCallback; + message['callbackId'] = callbackId; + } + sendMessageQueue.push(message); + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; + } + + function _fetchQueue() { + var messageQueueString = JSON.stringify(sendMessageQueue); + sendMessageQueue = []; + return messageQueueString; + } + + function _dispatchMessageFromObjC(messageJSON) { + if (dispatchMessagesWithTimeoutSafety) { + setTimeout(_doDispatchMessageFromObjC); + } else { + _doDispatchMessageFromObjC(); + } + + function _doDispatchMessageFromObjC() { + var message = JSON.parse(messageJSON); + var messageHandler; + var responseCallback; + + if (message.responseId) { + responseCallback = responseCallbacks[message.responseId]; + if (!responseCallback) { + return; + } + responseCallback(message.responseData); + delete responseCallbacks[message.responseId]; + } else { + if (message.callbackId) { + var callbackResponseId = message.callbackId; + responseCallback = function(responseData) { + _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData }); + }; + } + + var handler = messageHandlers[message.handlerName]; + if (!handler) { + console.log("WebViewJavascriptBridge: WARNING: no handler for message from ObjC:", message); + } else { + handler(message.data, responseCallback); + } + } + } + } + + function _handleMessageFromObjC(messageJSON) { + _dispatchMessageFromObjC(messageJSON); + } + + messagingIframe = document.createElement('iframe'); + messagingIframe.style.display = 'none'; + messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; + document.documentElement.appendChild(messagingIframe); + + registerHandler("_disableJavascriptAlertBoxSafetyTimeout", disableJavscriptAlertBoxSafetyTimeout); + + setTimeout(_callWVJBCallbacks, 0); + function _callWVJBCallbacks() { + var callbacks = window.WVJBCallbacks; + delete window.WVJBCallbacks; + for (var i=0; i + + + + + + +

这是按钮调用

+ + + + + + + + +

这是文件上传

+ + + +

这是回调结果展示区

+ + +

竖直方向的表头:

+ + + + + + + + + + + + + +
姓名Bill Gates
电话555 77 854
传真555 77 855
+ + + + \ No newline at end of file diff --git a/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/main.m b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/main.m new file mode 100644 index 0000000..bf0bdf8 --- /dev/null +++ b/JS_OC_WebViewJavascriptBridge/JS_OC_WebViewJavascriptBridge/main.m @@ -0,0 +1,16 @@ +// +// main.m +// JS_OC_WebViewJavascriptBridge +// +// Created by Harvey on 16/8/25. +// Copyright © 2016年 Haley. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/JS_OC.xcodeproj/project.pbxproj b/JS_OC_summary/JS_OC.xcodeproj/project.pbxproj similarity index 100% rename from JS_OC.xcodeproj/project.pbxproj rename to JS_OC_summary/JS_OC.xcodeproj/project.pbxproj diff --git a/JS_OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from JS_OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..69fce39 Binary files /dev/null and b/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/Harvey.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate b/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..7484d22 Binary files /dev/null and b/JS_OC_summary/JS_OC.xcodeproj/project.xcworkspace/xcuserdata/haley.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/JS_OC.xcscheme b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/JS_OC.xcscheme similarity index 100% rename from JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/JS_OC.xcscheme rename to JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/JS_OC.xcscheme diff --git a/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/xcschememanagement.plist rename to JS_OC_summary/JS_OC.xcodeproj/xcuserdata/Harvey.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..fb1be2a --- /dev/null +++ b/JS_OC_summary/JS_OC.xcodeproj/xcuserdata/haley.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + JS_OC.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/JS_OC/AppDelegate.h b/JS_OC_summary/JS_OC/AppDelegate.h similarity index 100% rename from JS_OC/AppDelegate.h rename to JS_OC_summary/JS_OC/AppDelegate.h diff --git a/JS_OC/AppDelegate.m b/JS_OC_summary/JS_OC/AppDelegate.m similarity index 100% rename from JS_OC/AppDelegate.m rename to JS_OC_summary/JS_OC/AppDelegate.m diff --git a/JS_OC_summary/JS_OC/Assets.xcassets/AppIcon.appiconset/Contents.json b/JS_OC_summary/JS_OC/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/JS_OC_summary/JS_OC/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/JS_OC_summary/JS_OC/Base.lproj/LaunchScreen.storyboard b/JS_OC_summary/JS_OC/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/JS_OC_summary/JS_OC/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JS_OC/Base.lproj/Main.storyboard b/JS_OC_summary/JS_OC/Base.lproj/Main.storyboard similarity index 67% rename from JS_OC/Base.lproj/Main.storyboard rename to JS_OC_summary/JS_OC/Base.lproj/Main.storyboard index c1c31e4..d5523a1 100644 --- a/JS_OC/Base.lproj/Main.storyboard +++ b/JS_OC_summary/JS_OC/Base.lproj/Main.storyboard @@ -1,8 +1,12 @@ - - + + + + + - + + @@ -14,7 +18,7 @@ - + @@ -23,7 +27,7 @@ - + @@ -33,7 +37,7 @@ - + @@ -56,12 +60,18 @@ - + - + - + + + + + + + @@ -82,7 +92,7 @@ - + @@ -102,17 +112,25 @@ - + - - - + + + - + + + + + + + + + diff --git a/JS_OC/First.html b/JS_OC_summary/JS_OC/First.html similarity index 100% rename from JS_OC/First.html rename to JS_OC_summary/JS_OC/First.html diff --git a/JS_OC/FirstViewController.h b/JS_OC_summary/JS_OC/FirstViewController.h similarity index 100% rename from JS_OC/FirstViewController.h rename to JS_OC_summary/JS_OC/FirstViewController.h diff --git a/JS_OC/FirstViewController.m b/JS_OC_summary/JS_OC/FirstViewController.m similarity index 100% rename from JS_OC/FirstViewController.m rename to JS_OC_summary/JS_OC/FirstViewController.m diff --git a/JS_OC/Info.plist b/JS_OC_summary/JS_OC/Info.plist similarity index 100% rename from JS_OC/Info.plist rename to JS_OC_summary/JS_OC/Info.plist diff --git a/JS_OC/Second.html b/JS_OC_summary/JS_OC/Second.html similarity index 100% rename from JS_OC/Second.html rename to JS_OC_summary/JS_OC/Second.html diff --git a/JS_OC/SeondViewController.h b/JS_OC_summary/JS_OC/SeondViewController.h similarity index 100% rename from JS_OC/SeondViewController.h rename to JS_OC_summary/JS_OC/SeondViewController.h diff --git a/JS_OC/SeondViewController.m b/JS_OC_summary/JS_OC/SeondViewController.m similarity index 85% rename from JS_OC/SeondViewController.m rename to JS_OC_summary/JS_OC/SeondViewController.m index 5464571..d6259d2 100644 --- a/JS_OC/SeondViewController.m +++ b/JS_OC_summary/JS_OC/SeondViewController.m @@ -34,8 +34,10 @@ - (void)viewDidLoad { NSLog(@"+++++++Begin Log+++++++"); NSArray *args = [JSContext currentArguments]; - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式二" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil]; - [alertView show]; + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"方式二" message:@"这是OC原生的弹出窗" delegate:self cancelButtonTitle:@"收到" otherButtonTitles:nil]; + [alertView show]; + }); for (JSValue *jsVal in args) { NSLog(@"%@", jsVal.toString); diff --git a/JS_OC/main.m b/JS_OC_summary/JS_OC/main.m similarity index 100% rename from JS_OC/main.m rename to JS_OC_summary/JS_OC/main.m diff --git a/Simulator Screen 11.png b/JS_OC_summary/Simulator Screen 11.png similarity index 100% rename from Simulator Screen 11.png rename to JS_OC_summary/Simulator Screen 11.png diff --git a/Simulator Screen 12.png b/JS_OC_summary/Simulator Screen 12.png similarity index 100% rename from Simulator Screen 12.png rename to JS_OC_summary/Simulator Screen 12.png diff --git a/Simulator Screen 21.png b/JS_OC_summary/Simulator Screen 21.png similarity index 100% rename from Simulator Screen 21.png rename to JS_OC_summary/Simulator Screen 21.png diff --git a/Simulator Screen 22.png b/JS_OC_summary/Simulator Screen 22.png similarity index 100% rename from Simulator Screen 22.png rename to JS_OC_summary/Simulator Screen 22.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c333c0 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# JS_OC +JS与原生OC互相调用的Demo(持续更新中),如果帮助到你理解JS与iOS Native的交互,麻烦给个star ⭐️ ⭐️。
+计划整理的JS与OC调用的系列包括: +* 1.在JS 中做一次URL跳转,然后在OC中拦截跳转。(这里分为UIWebView 和 WKWebView两种,去年因为还要兼容iOS 6,所以没办法只能采用UIWebView来做。) +* 2.利用WKWebView 的MessageHandler。 +* 3.利用系统库JavaScriptCore,来做相互调用。(iOS 7推出的) +* 4.利用第三方库WebViewJavascriptBridge。 +* 5.利用第三方cordova库,以前叫PhoneGap。(这是一个库平台的库) +* 6.当下盛行的React Native。 + +## JS_OC_summary +[JS_OC_summary](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_summary)是2015年中整理的两种调用方式,包括通过URL和JavaScriptCore来实现调用
+在最新的示例中都有做更新和优化。
+相关文章地址:
+[iOS下JS与原生OC互相调用(总结)](http://www.jianshu.com/p/d19689e0ed83) + +## JS_OC_URL +[JS_OC_URL](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_URL)展示了UIWebView和WKWebView通过URL来实现JS调用原生OC的示例。 +在JS_OC_summary的基础上有了点小小的优化。
+相关文章地址:
+[iOS下JS与OC互相调用(一)--UIWebView 拦截URL](http://www.jianshu.com/p/7151987f012d)
+[iOS下JS与OC互相调用(二)--WKWebView 拦截URL](http://www.jianshu.com/p/99c3af6894f4) + +## JS_OC_MessageHandler +[JS_OC_MessageHandler](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_MessageHandler)是利用WKWebView提供的新的API实现的JS调用原生OC,更简洁和方便。
+相关文章地址:
+[iOS下JS与OC互相调用(三)--MessageHandler](http://www.jianshu.com/p/433e59c5a9eb) + +## JS_OC_JavaScriptCore +[JS_OC_JavaScriptCore](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_JavaScriptCore)是利用JavaScriptCore框架来实现JS与OC相互调用的示例。
+相关文章地址:
+[iOS下JS与OC互相调用(四)--JavaScriptCore](http://www.jianshu.com/p/4db513ed2c1a) + +## JS_OC_WebViewJavascriptBridge +[JS_OC_WebViewJavascriptBridge](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_WebViewJavascriptBridge)是通过第三方框架[WebViewJavascriptBridge]()来实现JS与OC交互的示例。
+相关文章地址:
+[iOS下JS与OC互相调用(五)--UIWebView + WebViewJavascriptBridge](http://www.jianshu.com/p/2be213e3f673)
+[iOS下JS与OC互相调用(六)--WKWebView + WebViewJavascriptBridge](http://www.jianshu.com/p/e951af9e5e74)
+ +> 目前我Demo中的WebViewJavascriptBridge库不是最新版本,在最新的iOS系统有崩溃,各位在使用该第三方库时,记得先更新到最新版本。 + +## JS_OC_Cordova +[JS_OC_Cordova](https://github.com/Haley-Wong/JS_OC/tree/master/JS_OC_Cordova)是通过第三方框架Cordova来实现JS与OC交互的示例。
+相关文章地址:
+[iOS下JS与OC互相调用(七)--Cordova 基础](http://www.jianshu.com/p/78e486b31953)
+[iOS下JS与OC互相调用(八)--Cordova详解+实战](http://www.jianshu.com/p/e74bc7abac8d)
+ +简书和csdn 下分别有一个专题,还在持续更新中:
+简书:[JS与OC交互](http://www.jianshu.com/notebooks/5513092/latest) + +csdn:[iOS 原生与 JS 交互](http://blog.csdn.net/column/details/12696.html) + + +其他几篇待续。