diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..81a6b69c --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ +# WVJB Bug Report + +Thanks for reporting an issue with WebViewJavascriptBridge. + +### Do these 4 things and I will fix your problem! + +1. Go to https://github.com/marcuswestin/WebViewJavascriptBridge and click Fork. +2. Clone your fork, `cd` into it and run `make test`. All tests should pass! +3. Edit `Tests/WebViewJavascriptBridgeTests/BridgeTests.m` and create a new, failing test which demostrates your issue. +4. Create a pull request for https://github.com/marcuswestin/WebViewJavascriptBridge + +#### That's it! + +I will take it from there and promise that I'll fix your problem ASAP. + +#### If you don't do this then I can't help you! + +And I probably won't :) + +Cheers, +@marcuswestin diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..920af1c5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## Before your create your PR: + +#### Please add tests for any new or changed functionality! + +1. Edit `Tests/WebViewJavascriptBridgeTests/BridgeTests.m` +2. Create a new test which demostrates your changes. +3. Run `make test` and make sure your test is passing +4. That's it! + +#### Thanks for improving WebViewJavascriptBridge! + +Cheers, +@marcuswestin diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 00000000..ddda54c3 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1 @@ +Copyright (c) 2023 - Marcus Westin \ No newline at end of file diff --git a/Changelog b/Changelog index a7fb8544..af90a6d3 100644 --- a/Changelog +++ b/Changelog @@ -13,9 +13,33 @@ Release Checklist Version History --------------- -Intended v5.0.0 +v5.1.1 ++ Swift unit tests and examples ++ Implement removeHandler + +v5.1.0 ++ A single instantiation function for all webview types. ++ Improved test runner. ++ New instructions & templates for github issues and pull requests. + +v5.0.5 ++ Run all tests for both UIWebView and WKWebView webviews/bridges. ++ Allow for calling handlers from JS with just a handler name and responseCallback function (#184). + +v5.0.3 & v5.0.4 ++ Recalled builds :) + +v5.0.2 ++ Fix bug that could cause a crash if the webview loads a new page immediately after JS sends a message. + +v5.0.1 + Removed `WebViewJavascriptBridge -reset`. It should never have been exposed as a public API. + Fixed compilation in C99 mode ++ Inline JS source code. WVJB no longer requires `WebViewJavascriptBridge.js.txt` to be included as a resource. ++ Automated testing: see `make test` ++ Added Makefile with common commands ++ Significantly simplified and improved wvjb load detection ++ Simplify API by focusing on explicitly named handlers instead of a default handler and plain `send`. v4.1.4 + Improve how WVJB handles the case when there is no ObjC handler for a message received from js. diff --git a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj index 0e947166..d08ca0ab 100644 --- a/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-OSX.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 0ECB01491A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB01461A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.m */; }; + 0ECB014A1A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB01481A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.m */; }; 2C136A2517641106004C7401 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A2417641106004C7401 /* Cocoa.framework */; }; 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A2D17641106004C7401 /* InfoPlist.strings */; }; 2C136A3117641106004C7401 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3017641106004C7401 /* main.m */; }; @@ -14,12 +16,16 @@ 2C136A3817641106004C7401 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C136A3717641106004C7401 /* AppDelegate.m */; }; 2C136A4217641236004C7401 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C136A4117641236004C7401 /* WebKit.framework */; }; 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2C136A5917642704004C7401 /* ExampleApp.html */; }; - 2C1562C5176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */; }; 2C1562C6176BA9FF00B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */; }; + 2C3E7C491C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C3E7C481C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.m */; }; 2CF17F5317D8AACF006E828B /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CF17F5217D8AACF006E828B /* MainMenu.xib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0ECB01451A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = ""; }; + 0ECB01461A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; + 0ECB01471A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; + 0ECB01481A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; 2C136A2117641106004C7401 /* ExampleApp-OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ExampleApp-OSX.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2C136A2417641106004C7401 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 2C136A2717641106004C7401 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -35,8 +41,9 @@ 2C136A4117641236004C7401 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 2C136A5917642704004C7401 /* ExampleApp.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = ExampleApp.html; sourceTree = SOURCE_ROOT; }; 2C1562C2176BA9FF00B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; - 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; + 2C3E7C471C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = ""; }; + 2C3E7C481C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = ""; }; 2CF17F5217D8AACF006E828B /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -118,8 +125,13 @@ 2C1562C1176BA9FF00B4AE50 /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( + 2C3E7C471C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.h */, + 2C3E7C481C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.m */, + 0ECB01451A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.h */, + 0ECB01461A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.m */, + 0ECB01471A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.h */, + 0ECB01481A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.m */, 2C1562C2176BA9FF00B4AE50 /* WebViewJavascriptBridge.h */, - 2C1562C3176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt */, 2C1562C4176BA9FF00B4AE50 /* WebViewJavascriptBridge.m */, ); name = WebViewJavascriptBridge; @@ -152,7 +164,7 @@ 2C136A1917641106004C7401 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Marcus Westin"; }; buildConfigurationList = 2C136A1C17641106004C7401 /* Build configuration list for PBXProject "ExampleApp-OSX" */; @@ -177,7 +189,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C1562C5176BA9FF00B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */, 2C136A2F17641106004C7401 /* InfoPlist.strings in Resources */, 2C136A3517641106004C7401 /* Credits.rtf in Resources */, 2C136A5A17642704004C7401 /* ExampleApp.html in Resources */, @@ -192,6 +203,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0ECB01491A0EEB3A0037FF4E /* WebViewJavascriptBridgeBase.m in Sources */, + 0ECB014A1A0EEB3A0037FF4E /* WKWebViewJavascriptBridge.m in Sources */, + 2C3E7C491C5A8B8D00A1E322 /* WebViewJavascriptBridge_JS.m in Sources */, 2C136A3117641106004C7401 /* main.m in Sources */, 2C1562C6176BA9FF00B4AE50 /* WebViewJavascriptBridge.m in Sources */, 2C136A3817641106004C7401 /* AppDelegate.m in Sources */, @@ -227,15 +241,22 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -244,7 +265,9 @@ GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.8; ONLY_ACTIVE_ARCH = YES; @@ -259,18 +282,26 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.8; SDKROOT = macosx; @@ -285,6 +316,7 @@ GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = "WebViewJavascriptBridge.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -298,6 +330,7 @@ GCC_PREFIX_HEADER = "ExampleApp-OSX/ExampleApp-OSX-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-OSX/ExampleApp-OSX-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = "WebViewJavascriptBridge.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/Example Apps/ExampleApp-OSX/AppDelegate.m b/Example Apps/ExampleApp-OSX/AppDelegate.m index 4e77da67..5677342a 100644 --- a/Example Apps/ExampleApp-OSX/AppDelegate.m +++ b/Example Apps/ExampleApp-OSX/AppDelegate.m @@ -12,76 +12,120 @@ @implementation AppDelegate { WebView* _webView; + WKWebView *_WKWebView; WebViewJavascriptBridge* _bridge; + WebViewJavascriptBridge* _WKBridge; + NSView* _WKWebViewWrapper; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [self _createViews]; - [self _createBridge]; - [self _createObjcButtons]; - [self _loadPage]; + [self _configureWebview]; + [self _configureWKWebview]; } -- (void)_createBridge { - _bridge = [WebViewJavascriptBridge bridgeForWebView:_webView handler:^(id data, WVJBResponseCallback responseCallback) { - NSLog(@"ObjC received message from JS: %@", data); - responseCallback(@"Response for message from ObjC"); - }]; +- (void)_configureWebview { + // Create Bridge + _bridge = [WebViewJavascriptBridge bridgeForWebView:_webView]; [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"testObjcCallback called: %@", data); responseCallback(@"Response from testObjcCallback"); }]; - [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) { - NSLog(@"objc got response! %@", responseData); - }]; - [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; -} - -- (void)_createObjcButtons { - NSButton *messageButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)]; - [messageButton setTitle:@"Send message"]; - [messageButton setBezelStyle:NSRoundedBezelStyle]; - [messageButton setTarget:self]; - [messageButton setAction:@selector(_sendMessage)]; - [_webView addSubview:messageButton]; - NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 120, 40)]; + // Create Buttons + NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)]; [callbackButton setTitle:@"Call handler"]; [callbackButton setBezelStyle:NSRoundedBezelStyle]; [callbackButton setTarget:self]; [callbackButton setAction:@selector(_callHandler)]; [_webView addSubview:callbackButton]; + + NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 180, 40)]; + [webViewToggleButton setTitle:@"Switch to WKWebView"]; + [webViewToggleButton setBezelStyle:NSRoundedBezelStyle]; + [webViewToggleButton setTarget:self]; + [webViewToggleButton setAction:@selector(_toggleExample)]; + [_webView addSubview:webViewToggleButton]; + + + // Load Page + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* html = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [[_webView mainFrame] loadHTMLString:html baseURL: baseURL]; } -- (void)_sendMessage { - [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { - NSLog(@"sendMessage got response: %@", response); + +- (void)_configureWKWebview { + // Create Bridge + _WKBridge = [WebViewJavascriptBridge bridgeForWebView:_WKWebView]; + + [_WKBridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"testObjcCallback called: %@", data); + responseCallback(@"Response from testObjcCallback"); }]; + + [_WKBridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; + + // Create Buttons + NSButton *callbackButton = [[NSButton alloc] initWithFrame:NSMakeRect(5, 0, 120, 40)]; + [callbackButton setTitle:@"Call handler"]; + [callbackButton setBezelStyle:NSRoundedBezelStyle]; + [callbackButton setTarget:self]; + [callbackButton setAction:@selector(_WKCallHandler)]; + [_WKWebView addSubview:callbackButton]; + + NSButton *webViewToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(120, 0, 180, 40)]; + [webViewToggleButton setTitle:@"Switch to WebView"]; + [webViewToggleButton setBezelStyle:NSRoundedBezelStyle]; + [webViewToggleButton setTarget:self]; + [webViewToggleButton setAction:@selector(_toggleExample)]; + [_WKWebView addSubview:webViewToggleButton]; + + // Load Page + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* html = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [_WKWebView loadHTMLString:html baseURL:baseURL]; +} + +-(void)_toggleExample { + _WKWebView.hidden = !_WKWebView.isHidden; + _webView.hidden = !_webView.isHidden; } - (void)_callHandler { id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { NSLog(@"testJavascriptHandler responded: %@", response); - }]; + }]; +} + +- (void)_WKCallHandler { + id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; + [_WKBridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { + NSLog(@"testJavascriptHandler responded: %@", response); + }]; } - (void)_createViews { NSView* contentView = _window.contentView; + // WebView _webView = [[WebView alloc] initWithFrame:contentView.frame]; [_webView setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; + _webView.hidden = YES; + + // WKWebView + _WKWebView = [[WKWebView alloc] initWithFrame:contentView.frame]; + [_WKWebView setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)]; + + [contentView addSubview:_WKWebView]; [contentView addSubview:_webView]; } -- (void)_loadPage { - NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; - NSString* html = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; - [[_webView mainFrame] loadHTMLString:html baseURL:nil]; -} - @end diff --git a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist index 14097880..b9f1feaa 100644 --- a/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist +++ b/Example Apps/ExampleApp-OSX/ExampleApp-OSX-Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile CFBundleIdentifier - WebViewJavascriptBridge.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index 4834adaf..324a5b06 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -7,25 +7,35 @@ objects = { /* Begin PBXBuildFile section */ - 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */; }; + 0E4E9D4C1A101E0B00043087 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E8082DC19EDD98700479452 /* WebKit.framework */; }; + 0E50601C1A01B442000BEEEA /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E50601B1A01B442000BEEEA /* WebViewJavascriptBridgeBase.m */; }; + 0E8082DB19EDC32300479452 /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */; }; + 0ECB01441A0EE1F20037FF4E /* ExampleWKWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB01431A0EE1F20037FF4E /* ExampleWKWebViewController.m */; }; 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */; }; - 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */; }; + 2C3E7C461C5A890A00A1E322 /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C3E7C451C5A890A00A1E322 /* WebViewJavascriptBridge_JS.m */; }; + 2C45CA2C1884AD520002A4E2 /* ExampleUIWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C45CA2B1884AD520002A4E2 /* ExampleUIWebViewController.m */; }; 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CA045B717117439006DEE8B /* InfoPlist.strings */; }; 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */; }; 2CA045C317117439006DEE8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2CA045BE17117439006DEE8B /* main.m */; }; 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */; }; 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CAB869A1727684300BD9ED1 /* Default-568h@2x.png */; }; 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EBF1602563600548120 /* UIKit.framework */; }; - 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC11602563600548120 /* Foundation.framework */; }; - 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CEB3EC31602563600548120 /* CoreGraphics.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0E50601B1A01B442000BEEEA /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = ""; }; + 0E50601D1A01B44C000BEEEA /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = ""; }; + 0E8082D919EDC32300479452 /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = ""; }; + 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = ""; }; + 0E8082DC19EDD98700479452 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 0ECB01421A0EE1BA0037FF4E /* ExampleWKWebViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExampleWKWebViewController.h; sourceTree = ""; }; + 0ECB01431A0EE1F20037FF4E /* ExampleWKWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleWKWebViewController.m; sourceTree = ""; }; 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = ""; }; 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = ""; }; - 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebViewJavascriptBridge.js.txt; sourceTree = ""; }; - 2C45CA2A1884AD520002A4E2 /* ExampleAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleAppViewController.h; sourceTree = ""; }; - 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleAppViewController.m; sourceTree = ""; }; + 2C3E7C441C5A890A00A1E322 /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = ""; }; + 2C3E7C451C5A890A00A1E322 /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = ""; }; + 2C45CA2A1884AD520002A4E2 /* ExampleUIWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleUIWebViewController.h; sourceTree = ""; }; + 2C45CA2B1884AD520002A4E2 /* ExampleUIWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleUIWebViewController.m; sourceTree = ""; }; 2CA045B817117439006DEE8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 2CA045B917117439006DEE8B /* ExampleApp-iOS-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ExampleApp-iOS-Info.plist"; sourceTree = ""; }; 2CA045BA17117439006DEE8B /* ExampleApp-iOS-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ExampleApp-iOS-Prefix.pch"; sourceTree = ""; }; @@ -45,9 +55,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0E4E9D4C1A101E0B00043087 /* WebKit.framework in Frameworks */, 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */, - 2CEB3EC21602563600548120 /* Foundation.framework in Frameworks */, - 2CEB3EC41602563600548120 /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -57,9 +66,14 @@ 2C1562A7176B9F5400B4AE50 /* WebViewJavascriptBridge */ = { isa = PBXGroup; children = ( - 2C1562B4176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt */, + 2C3E7C441C5A890A00A1E322 /* WebViewJavascriptBridge_JS.h */, + 2C3E7C451C5A890A00A1E322 /* WebViewJavascriptBridge_JS.m */, 2C1562A8176B9F6200B4AE50 /* WebViewJavascriptBridge.h */, 2C1562A9176B9F6200B4AE50 /* WebViewJavascriptBridge.m */, + 0E8082DA19EDC32300479452 /* WKWebViewJavascriptBridge.m */, + 0E8082D919EDC32300479452 /* WKWebViewJavascriptBridge.h */, + 0E50601B1A01B442000BEEEA /* WebViewJavascriptBridgeBase.m */, + 0E50601D1A01B44C000BEEEA /* WebViewJavascriptBridgeBase.h */, ); name = WebViewJavascriptBridge; path = ../../WebViewJavascriptBridge; @@ -71,8 +85,10 @@ 2CA0465B1711AC8D006DEE8B /* ExampleApp.html */, 2CA045BC17117439006DEE8B /* ExampleAppDelegate.h */, 2CA045BD17117439006DEE8B /* ExampleAppDelegate.m */, - 2C45CA2A1884AD520002A4E2 /* ExampleAppViewController.h */, - 2C45CA2B1884AD520002A4E2 /* ExampleAppViewController.m */, + 2C45CA2A1884AD520002A4E2 /* ExampleUIWebViewController.h */, + 2C45CA2B1884AD520002A4E2 /* ExampleUIWebViewController.m */, + 0ECB01421A0EE1BA0037FF4E /* ExampleWKWebViewController.h */, + 0ECB01431A0EE1F20037FF4E /* ExampleWKWebViewController.m */, 2C1562A7176B9F5400B4AE50 /* WebViewJavascriptBridge */, 2CA046211711A94E006DEE8B /* Supporting Files */, ); @@ -97,6 +113,7 @@ 2CA045B617117439006DEE8B /* ExampleApp-iOS */, 2CEB3EBE1602563600548120 /* Frameworks */, 2CEB3EBC1602563600548120 /* Products */, + 81A733051B2F9C5795D856E4 /* Pods */, ); sourceTree = ""; }; @@ -111,6 +128,7 @@ 2CEB3EBE1602563600548120 /* Frameworks */ = { isa = PBXGroup; children = ( + 0E8082DC19EDD98700479452 /* WebKit.framework */, 2CEB3EBF1602563600548120 /* UIKit.framework */, 2CEB3EC11602563600548120 /* Foundation.framework */, 2CEB3EC31602563600548120 /* CoreGraphics.framework */, @@ -118,6 +136,13 @@ name = Frameworks; sourceTree = ""; }; + 81A733051B2F9C5795D856E4 /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -144,8 +169,13 @@ 2CEB3EB21602563600548120 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0500; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = "Marcus Westin"; + TargetAttributes = { + 2CEB3EBA1602563600548120 = { + LastSwiftMigration = 0820; + }; + }; }; buildConfigurationList = 2CEB3EB51602563600548120 /* Build configuration list for PBXProject "ExampleApp-iOS" */; compatibilityVersion = "Xcode 3.2"; @@ -169,7 +199,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C1562B5176B9F8400B4AE50 /* WebViewJavascriptBridge.js.txt in Resources */, 2CA045BF17117439006DEE8B /* InfoPlist.strings in Resources */, 2CA0465C1711AC8E006DEE8B /* ExampleApp.html in Resources */, 2CAB869B1727684300BD9ED1 /* Default-568h@2x.png in Resources */, @@ -183,9 +212,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C3E7C461C5A890A00A1E322 /* WebViewJavascriptBridge_JS.m in Sources */, 2C1562C0176BA63500B4AE50 /* WebViewJavascriptBridge.m in Sources */, - 2C45CA2C1884AD520002A4E2 /* ExampleAppViewController.m in Sources */, + 0E8082DB19EDC32300479452 /* WKWebViewJavascriptBridge.m in Sources */, + 2C45CA2C1884AD520002A4E2 /* ExampleUIWebViewController.m in Sources */, + 0ECB01441A0EE1F20037FF4E /* ExampleWKWebViewController.m in Sources */, 2CA045C217117439006DEE8B /* ExampleAppDelegate.m in Sources */, + 0E50601C1A01B442000BEEEA /* WebViewJavascriptBridgeBase.m in Sources */, 2CA045C317117439006DEE8B /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -211,21 +244,35 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + 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_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; @@ -238,14 +285,27 @@ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; + 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; + GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -255,10 +315,16 @@ 2CEB3ED41602563600548120 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ExampleApp-iOS/ExampleApp-iOS-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-iOS/ExampleApp-iOS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.example.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "ExampleApp-iOS"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; WRAPPER_EXTENSION = app; }; name = Debug; @@ -266,10 +332,15 @@ 2CEB3ED51602563600548120 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ExampleApp-iOS/ExampleApp-iOS-Prefix.pch"; INFOPLIST_FILE = "ExampleApp-iOS/ExampleApp-iOS-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.example.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "ExampleApp-iOS"; + SWIFT_VERSION = 3.0; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist index 81d25998..3eb70251 100644 --- a/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist +++ b/Example Apps/ExampleApp-iOS/ExampleApp-iOS-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.example.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m index 72f35ded..ff9f5bef 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m +++ b/Example Apps/ExampleApp-iOS/ExampleAppDelegate.m @@ -1,11 +1,28 @@ #import "ExampleAppDelegate.h" -#import "ExampleAppViewController.h" +#import "ExampleUIWebViewController.h" +#import "ExampleWKWebViewController.h" @implementation ExampleAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + // 1. Create the UIWebView example + ExampleUIWebViewController* UIWebViewExampleController = [[ExampleUIWebViewController alloc] init]; + UIWebViewExampleController.tabBarItem.title = @"UIWebView"; + + // 2. Create the tab footer and add the UIWebView example + UITabBarController *tabBarController = [[UITabBarController alloc] init]; + [tabBarController addChildViewController:UIWebViewExampleController]; + + // 3. Create the WKWebView example for devices >= iOS 8 + if([WKWebView class]) { + ExampleWKWebViewController* WKWebViewExampleController = [[ExampleWKWebViewController alloc] init]; + WKWebViewExampleController.tabBarItem.title = @"WKWebView"; + [tabBarController addChildViewController:WKWebViewExampleController]; + } + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - self.window.rootViewController = [ExampleAppViewController new]; + self.window.rootViewController = tabBarController; [self.window makeKeyAndVisible]; return YES; } diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.h b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.h similarity index 56% rename from Example Apps/ExampleApp-iOS/ExampleAppViewController.h rename to Example Apps/ExampleApp-iOS/ExampleUIWebViewController.h index d2e25c2d..71364e80 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.h +++ b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.h @@ -1,5 +1,5 @@ // -// ExampleAppViewController.h +// ExampleUIWebViewController.h // ExampleApp-iOS // // Created by Marcus Westin on 1/13/14. @@ -8,6 +8,6 @@ #import -@interface ExampleAppViewController : UINavigationController +@interface ExampleUIWebViewController : UINavigationController -@end +@end \ No newline at end of file diff --git a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m similarity index 62% rename from Example Apps/ExampleApp-iOS/ExampleAppViewController.m rename to Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m index 3f1f7794..f988a014 100644 --- a/Example Apps/ExampleApp-iOS/ExampleAppViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m @@ -1,48 +1,40 @@ // -// ExampleAppViewController.m +// ExampleUIWebViewController.m // ExampleApp-iOS // // Created by Marcus Westin on 1/13/14. // Copyright (c) 2014 Marcus Westin. All rights reserved. // -#import "ExampleAppViewController.h" +#import "ExampleUIWebViewController.h" #import "WebViewJavascriptBridge.h" -@interface ExampleAppViewController () +@interface ExampleUIWebViewController () @property WebViewJavascriptBridge* bridge; @end -@implementation ExampleAppViewController +@implementation ExampleUIWebViewController - (void)viewWillAppear:(BOOL)animated { if (_bridge) { return; } - + UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:webView]; [WebViewJavascriptBridge enableLogging]; - _bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) { - NSLog(@"ObjC received message from JS: %@", data); - responseCallback(@"Response for message from ObjC"); - }]; + _bridge = [WebViewJavascriptBridge bridgeForWebView:webView]; + [_bridge setWebViewDelegate:self]; [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"testObjcCallback called: %@", data); responseCallback(@"Response from testObjcCallback"); }]; - [_bridge send:@"A string sent from ObjC before Webview has loaded." responseCallback:^(id responseData) { - NSLog(@"objc got response! %@", responseData); - }]; - [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; [self renderButtons:webView]; [self loadExamplePage:webView]; - - [_bridge send:@"A string sent from ObjC after Webview has loaded."]; } - (void)webViewDidStartLoad:(UIWebView *)webView { @@ -54,35 +46,32 @@ - (void)webViewDidFinishLoad:(UIWebView *)webView { } - (void)renderButtons:(UIWebView*)webView { - UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; + UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:11.0]; - UIButton *messageButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [messageButton setTitle:@"Send message" forState:UIControlStateNormal]; - [messageButton addTarget:self action:@selector(sendMessage:) forControlEvents:UIControlEventTouchUpInside]; - [self.view insertSubview:messageButton aboveSubview:webView]; - messageButton.frame = CGRectMake(10, 414, 100, 35); - messageButton.titleLabel.font = font; - messageButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.75]; - UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [callbackButton setTitle:@"Call handler" forState:UIControlStateNormal]; [callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside]; [self.view insertSubview:callbackButton aboveSubview:webView]; - callbackButton.frame = CGRectMake(110, 414, 100, 35); + callbackButton.frame = CGRectMake(0, 400, 100, 35); callbackButton.titleLabel.font = font; UIButton* reloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [reloadButton setTitle:@"Reload webview" forState:UIControlStateNormal]; [reloadButton addTarget:webView action:@selector(reload) forControlEvents:UIControlEventTouchUpInside]; [self.view insertSubview:reloadButton aboveSubview:webView]; - reloadButton.frame = CGRectMake(210, 414, 100, 35); + reloadButton.frame = CGRectMake(90, 400, 100, 35); reloadButton.titleLabel.font = font; + + UIButton* safetyTimeoutButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [safetyTimeoutButton setTitle:@"Disable safety timeout" forState:UIControlStateNormal]; + [safetyTimeoutButton addTarget:self action:@selector(disableSafetyTimeout) forControlEvents:UIControlEventTouchUpInside]; + [self.view insertSubview:safetyTimeoutButton aboveSubview:webView]; + safetyTimeoutButton.frame = CGRectMake(190, 400, 120, 35); + safetyTimeoutButton.titleLabel.font = font; } -- (void)sendMessage:(id)sender { - [_bridge send:@"A string sent from ObjC to JS" responseCallback:^(id response) { - NSLog(@"sendMessage got response: %@", response); - }]; +- (void)disableSafetyTimeout { + [self.bridge disableJavscriptAlertBoxSafetyTimeout]; } - (void)callHandler:(id)sender { diff --git a/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.h b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.h new file mode 100644 index 00000000..7dd92b8e --- /dev/null +++ b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.h @@ -0,0 +1,14 @@ +// +// ExampleWKWebViewController.h +// ExampleApp-iOS +// +// Created by Marcus Westin on 1/13/14. +// Copyright (c) 2014 Marcus Westin. All rights reserved. +// + +#import +#import + +@interface ExampleWKWebViewController : UINavigationController + +@end \ No newline at end of file diff --git a/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m new file mode 100644 index 00000000..f9d4ac79 --- /dev/null +++ b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m @@ -0,0 +1,80 @@ +// +// ExampleWKWebViewController.m +// ExampleApp-iOS +// +// Created by Marcus Westin on 1/13/14. +// Copyright (c) 2014 Marcus Westin. All rights reserved. +// + +#import "ExampleWKWebViewController.h" +#import "WebViewJavascriptBridge.h" + +@interface ExampleWKWebViewController () + +@property WebViewJavascriptBridge* bridge; + +@end + +@implementation ExampleWKWebViewController + +- (void)viewWillAppear:(BOOL)animated { + if (_bridge) { return; } + + WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds]; + webView.navigationDelegate = self; + [self.view addSubview:webView]; + [WebViewJavascriptBridge enableLogging]; + _bridge = [WebViewJavascriptBridge bridgeForWebView:webView]; + [_bridge setWebViewDelegate:self]; + + [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { + NSLog(@"testObjcCallback called: %@", data); + responseCallback(@"Response from testObjcCallback"); + }]; + + [_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }]; + + [self renderButtons:webView]; + [self loadExamplePage:webView]; +} + +- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { + NSLog(@"webViewDidStartLoad"); +} + +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { + NSLog(@"webViewDidFinishLoad"); +} + +- (void)renderButtons:(WKWebView*)webView { + UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0]; + + UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [callbackButton setTitle:@"Call handler" forState:UIControlStateNormal]; + [callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside]; + [self.view insertSubview:callbackButton aboveSubview:webView]; + callbackButton.frame = CGRectMake(10, 400, 100, 35); + callbackButton.titleLabel.font = font; + + UIButton* reloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [reloadButton setTitle:@"Reload webview" forState:UIControlStateNormal]; + [reloadButton addTarget:webView action:@selector(reload) forControlEvents:UIControlEventTouchUpInside]; + [self.view insertSubview:reloadButton aboveSubview:webView]; + reloadButton.frame = CGRectMake(110, 400, 100, 35); + reloadButton.titleLabel.font = font; +} + +- (void)callHandler:(id)sender { + id data = @{ @"greetingFromObjC": @"Hi there, JS!" }; + [_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) { + NSLog(@"testJavascriptHandler responded: %@", response); + }]; +} + +- (void)loadExamplePage:(WKWebView*)webView { + NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"ExampleApp" ofType:@"html"]; + NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; + NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; + [webView loadHTMLString:appHtml baseURL:baseURL]; +} +@end diff --git a/Example Apps/ExampleApp-iOS/main.m b/Example Apps/ExampleApp-iOS/main.m index 5887dbf1..003d3a8f 100644 --- a/Example Apps/ExampleApp-iOS/main.m +++ b/Example Apps/ExampleApp-iOS/main.m @@ -1,10 +1,26 @@ #import - +#import +#import #import "ExampleAppDelegate.h" -int main(int argc, char *argv[]) +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) + +int main(int argc, char * argv[]) { @autoreleasepool { + // Dynamically load WebKit if iOS version >= 8 + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) { +#if TARGET_IPHONE_SIMULATOR + NSString *frameworkPath = [[NSProcessInfo processInfo] environment][@"DYLD_FALLBACK_FRAMEWORK_PATH"]; + if (frameworkPath) { + NSString *webkitLibraryPath = [NSString pathWithComponents:@[frameworkPath, @"WebKit.framework", @"WebKit"]]; + dlopen([webkitLibraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY); + } +#else + dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", RTLD_LAZY); +#endif + } + return UIApplicationMain(argc, argv, nil, NSStringFromClass([ExampleAppDelegate class])); } -} +} \ No newline at end of file diff --git a/Example Apps/ExampleApp.html b/Example Apps/ExampleApp.html index d31f1fb1..06e7dc8a 100644 --- a/Example Apps/ExampleApp.html +++ b/Example Apps/ExampleApp.html @@ -1,5 +1,6 @@ +