diff --git a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj index d351431a..76ea901a 100644 --- a/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj +++ b/Example Apps/ExampleApp-iOS.xcodeproj/project.pbxproj @@ -20,7 +20,6 @@ 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 */; }; - 6529BCFA17DEACD6F9C2E820 /* Pods_ExampleApp_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 495C20DD246029C0B2405EC9 /* Pods_ExampleApp_iOS.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -49,9 +48,6 @@ 2CEB3EBF1602563600548120 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 2CEB3EC11602563600548120 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 2CEB3EC31602563600548120 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 495C20DD246029C0B2405EC9 /* Pods_ExampleApp_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ExampleApp_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 4BCA4425A9554AF93A944458 /* Pods-ExampleApp-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleApp-iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleApp-iOS/Pods-ExampleApp-iOS.debug.xcconfig"; sourceTree = ""; }; - E4F0C608003752F273BB146F /* Pods-ExampleApp-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleApp-iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleApp-iOS/Pods-ExampleApp-iOS.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,7 +57,6 @@ files = ( 0E4E9D4C1A101E0B00043087 /* WebKit.framework in Frameworks */, 2CEB3EC01602563600548120 /* UIKit.framework in Frameworks */, - 6529BCFA17DEACD6F9C2E820 /* Pods_ExampleApp_iOS.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -118,7 +113,6 @@ 2CA045B617117439006DEE8B /* ExampleApp-iOS */, 2CEB3EBE1602563600548120 /* Frameworks */, 2CEB3EBC1602563600548120 /* Products */, - 81A733051B2F9C5795D856E4 /* Pods */, ); sourceTree = ""; }; @@ -137,20 +131,10 @@ 2CEB3EBF1602563600548120 /* UIKit.framework */, 2CEB3EC11602563600548120 /* Foundation.framework */, 2CEB3EC31602563600548120 /* CoreGraphics.framework */, - 495C20DD246029C0B2405EC9 /* Pods_ExampleApp_iOS.framework */, ); name = Frameworks; sourceTree = ""; }; - 81A733051B2F9C5795D856E4 /* Pods */ = { - isa = PBXGroup; - children = ( - 4BCA4425A9554AF93A944458 /* Pods-ExampleApp-iOS.debug.xcconfig */, - E4F0C608003752F273BB146F /* Pods-ExampleApp-iOS.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -158,12 +142,9 @@ isa = PBXNativeTarget; buildConfigurationList = 2CEB3ED31602563600548120 /* Build configuration list for PBXNativeTarget "ExampleApp-iOS" */; buildPhases = ( - 953B195B62A37FA474FD95D5 /* [CP] Check Pods Manifest.lock */, 2CEB3EB71602563600548120 /* Sources */, 2CEB3EB81602563600548120 /* Frameworks */, 2CEB3EB91602563600548120 /* Resources */, - A9D6EE0CEB388638298EBC18 /* [CP] Embed Pods Frameworks */, - 7E64B37A61F02883676CA89F /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -218,54 +199,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 7E64B37A61F02883676CA89F /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleApp-iOS/Pods-ExampleApp-iOS-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 953B195B62A37FA474FD95D5 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - A9D6EE0CEB388638298EBC18 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleApp-iOS/Pods-ExampleApp-iOS-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 2CEB3EB71602563600548120 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -373,7 +306,6 @@ }; 2CEB3ED41602563600548120 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 4BCA4425A9554AF93A944458 /* Pods-ExampleApp-iOS.debug.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -391,7 +323,6 @@ }; 2CEB3ED51602563600548120 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E4F0C608003752F273BB146F /* Pods-ExampleApp-iOS.release.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; diff --git a/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m index f988a014..59fe6647 100644 --- a/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleUIWebViewController.m @@ -20,6 +20,7 @@ - (void)viewWillAppear:(BOOL)animated { UIWebView* webView = [[UIWebView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:webView]; + NSLog(@"Is JS Bridge Did Load %@", [webView didJavascriptBridgeLoadOnWeb] ? @"YES" : @"NO"); [WebViewJavascriptBridge enableLogging]; @@ -35,6 +36,14 @@ - (void)viewWillAppear:(BOOL)animated { [self renderButtons:webView]; [self loadExamplePage:webView]; + + __weak typeof(webView) weakWebView = webView; + webView.webViewJavascriptBridgeLoadedBlock = ^{ + NSLog(@"JS Bridge Did Load"); + + __strong typeof(weakWebView) webView = weakWebView; + NSLog(@"Is JS Bridge Did Load %@", [webView didJavascriptBridgeLoadOnWeb] ? @"YES" : @"NO"); + }; } - (void)webViewDidStartLoad:(UIWebView *)webView { diff --git a/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m index f9d4ac79..298dcc9f 100644 --- a/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m +++ b/Example Apps/ExampleApp-iOS/ExampleWKWebViewController.m @@ -7,11 +7,11 @@ // #import "ExampleWKWebViewController.h" -#import "WebViewJavascriptBridge.h" +#import "WKWebViewJavascriptBridge.h" @interface ExampleWKWebViewController () -@property WebViewJavascriptBridge* bridge; +@property WKWebViewJavascriptBridge* bridge; @end @@ -23,8 +23,13 @@ - (void)viewWillAppear:(BOOL)animated { WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds]; webView.navigationDelegate = self; [self.view addSubview:webView]; - [WebViewJavascriptBridge enableLogging]; - _bridge = [WebViewJavascriptBridge bridgeForWebView:webView]; + + [webView didJavascriptBridgeLoadOnWeb:^(BOOL didLoad) { + NSLog(@"Is JS Bridge Did Load %@", didLoad ? @"YES" : @"NO"); + }]; + + [WKWebViewJavascriptBridge enableLogging]; + _bridge = [WKWebViewJavascriptBridge bridgeForWebView:webView]; [_bridge setWebViewDelegate:self]; [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) { @@ -36,6 +41,16 @@ - (void)viewWillAppear:(BOOL)animated { [self renderButtons:webView]; [self loadExamplePage:webView]; + + __weak typeof(webView) weakWebView = webView; + webView.webViewJavascriptBridgeLoadedBlock = ^{ + NSLog(@"JS Bridge Did Load"); + + __strong typeof(weakWebView) webView = weakWebView; + [webView didJavascriptBridgeLoadOnWeb:^(BOOL didLoad) { + NSLog(@"Is JS Bridge Did Load %@", didLoad ? @"YES" : @"NO"); + }]; + }; } - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h index 4e3404fc..89b6e684 100644 --- a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.h @@ -31,4 +31,12 @@ @end +@interface WKWebView (WKWebViewJavascriptBridge) + +@property (nonatomic, copy) void(^webViewJavascriptBridgeLoadedBlock)(); + +- (void)didJavascriptBridgeLoadOnWeb:(void(^)(BOOL didLoad))block; + +@end + #endif diff --git a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m index 47667df6..901a030e 100644 --- a/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WKWebViewJavascriptBridge.m @@ -7,6 +7,7 @@ #import "WKWebViewJavascriptBridge.h" +#import #if defined supportsWKWebView @@ -140,7 +141,8 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { - [_base injectJavascriptFile]; + [_base injectJavascriptFile]; + !webView.webViewJavascriptBridgeLoadedBlock ?: webView.webViewJavascriptBridgeLoadedBlock(); } else if ([_base isQueueMessageURL:url]) { [self WKFlushMessageQueue]; } else { @@ -193,5 +195,37 @@ - (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { @end +static void *kJSBridgeDidLoadBlockKey = &kJSBridgeDidLoadBlockKey; + +@implementation WKWebView (WKWebViewJavascriptBridge) + +- (void)setWebViewJavascriptBridgeLoadedBlock:(void (^)())webViewJavascriptBridgeLoadedBlock +{ + objc_setAssociatedObject(self, kJSBridgeDidLoadBlockKey, webViewJavascriptBridgeLoadedBlock, OBJC_ASSOCIATION_COPY); +} + +- (void (^)())webViewJavascriptBridgeLoadedBlock +{ + id block = objc_getAssociatedObject(self, kJSBridgeDidLoadBlockKey); + + return block; +} + +- (void)didJavascriptBridgeLoadOnWeb:(void (^)(BOOL))block +{ + __block BOOL isLoaded = NO; + + [self evaluateJavaScript:@"typeof WebViewJavascriptBridge == \'object\';" completionHandler:^(id _Nullable obj, NSError * _Nullable error) { + + if (obj && [obj respondsToSelector:@selector(boolValue)]) + { + isLoaded = [obj boolValue]; + } + + !block ?: block(isLoaded); + }]; +} + +@end #endif diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.h b/WebViewJavascriptBridge/WebViewJavascriptBridge.h index 1b64bb4e..7cf03961 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.h +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.h @@ -48,3 +48,12 @@ - (void)disableJavscriptAlertBoxSafetyTimeout; @end + + +@interface WVJB_WEBVIEW_TYPE (WebViewJavascriptBridge) + +@property (nonatomic, copy) void(^webViewJavascriptBridgeLoadedBlock)(); + +- (BOOL)didJavascriptBridgeLoadOnWeb; + +@end diff --git a/WebViewJavascriptBridge/WebViewJavascriptBridge.m b/WebViewJavascriptBridge/WebViewJavascriptBridge.m index e74a6e24..7c726c60 100755 --- a/WebViewJavascriptBridge/WebViewJavascriptBridge.m +++ b/WebViewJavascriptBridge/WebViewJavascriptBridge.m @@ -7,7 +7,7 @@ // #import "WebViewJavascriptBridge.h" - +#import #if defined(supportsWKWebView) #import "WKWebViewJavascriptBridge.h" #endif @@ -125,7 +125,8 @@ - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary NSURL *url = [request URL]; if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { - [_base injectJavascriptFile]; + [_base injectJavascriptFile]; + !webView.webViewJavascriptBridgeLoadedBlock ?: webView.webViewJavascriptBridgeLoadedBlock(); } else if ([_base isQueueMessageURL:url]) { NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; [_base flushMessageQueue:messageQueueString]; @@ -183,6 +184,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) if ([_base isWebViewJavascriptBridgeURL:url]) { if ([_base isBridgeLoadedURL:url]) { [_base injectJavascriptFile]; + !webView.webViewJavascriptBridgeLoadedBlock ?: webView.webViewJavascriptBridgeLoadedBlock(); } else if ([_base isQueueMessageURL:url]) { NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; [_base flushMessageQueue:messageQueueString]; @@ -209,3 +211,28 @@ - (void)webViewDidStartLoad:(UIWebView *)webView { #endif @end + +static void *kJSBridgeDidLoadBlockKey = &kJSBridgeDidLoadBlockKey; + +@implementation WVJB_WEBVIEW_TYPE (WebViewJavascriptBridge) + +- (void)setWebViewJavascriptBridgeLoadedBlock:(void (^)())webViewJavascriptBridgeLoadedBlock +{ + objc_setAssociatedObject(self, kJSBridgeDidLoadBlockKey, webViewJavascriptBridgeLoadedBlock, OBJC_ASSOCIATION_COPY); +} + +- (void (^)())webViewJavascriptBridgeLoadedBlock +{ + id block = objc_getAssociatedObject(self, kJSBridgeDidLoadBlockKey); + + return block; +} + +- (BOOL)didJavascriptBridgeLoadOnWeb +{ + NSString *result = [self stringByEvaluatingJavaScriptFromString:@"typeof WebViewJavascriptBridge == \'object\';"]; + + return [result boolValue]; +} + +@end