marcuswestin / webviewjavascriptbridge Goto Github PK
View Code? Open in Web Editor NEWAn iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews
Home Page: http://marcuswest.in
License: MIT License
An iOS/OSX bridge for sending messages between Obj-C and JavaScript in UIWebViews/WebViews
Home Page: http://marcuswest.in
License: MIT License
It seems that the following leads to an exception when data == nil.
- (void)_sendData:(NSDictionary *)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName {
NSMutableDictionary* message = [NSMutableDictionary dictionaryWithObject:data forKey:@"data"];
The problem is that a dictionary can not contain "nil" as a value for a key.
First of all, thanks for this great library! It works great :)
I was wondering if you've got any idea about how to implement returning values to JS from native calls. I've not been able to come up with a good solution so far, but it'd be awesome to be able to calla a native Obj-C function and get a return value back.
It doesn't work with https
I was wondering...
I’ve recently added WebViewJavascriptBridge
to the CocoaPods package manager repo.
CocoaPods is a tool for managing dependencies for OS X and iOS Xcode projects and provides a central repository for iOS/OS X libraries. This makes adding libraries to a project and updating them extremely easy and it will help users to resolve dependencies of the libraries they use.
However, WebViewJavascriptBridge
doesn't have any version tags. I’ve added the current HEAD as version 0.0.1, but a version tag will make dependency resolution much easier.
Semantic version tags (instead of plain commit hashes/revisions) allow for resolution of cross-dependencies.
In case you didn’t know this yet; you can tag the current HEAD as, for instance, version 1.0.0, like so:
$ git tag -a 1.0.0 -m "Tag release 1.0.0"
$ git push --tags
I code the test program.
the .h file is
//
// ViewController.h
// test
//
// Created by remote roamer on 12-5-3.
// Copyright (c) 2012年 MyCompanyName. All rights reserved.
//
@Class AppDelegate;
@interface ViewController : UIViewController < WebViewJavascriptBridgeDelegate >
{
IBOutlet UIWebView * webView;
}
@Property(retain,nonatomic) UIWebView * webView;
@Property(retain,nonatomic) WebViewJavascriptBridge * javascriptBridge;
@Property(nonatomic,retain) NSBundle* bundle ;
the .m file :
//
// ViewController.m
// test
//
// Created by remote roamer on 12-5-3.
// Copyright (c) 2012年 MyCompanyName. All rights reserved.
//
@interface ViewController ()
@implementation ViewController
@synthesize webView;
@synthesize bundle;
@synthesize javascriptBridge;
-(void) javascriptBridge:(WebViewJavascriptBridge *)bridge receivedMessage:(NSString *)message fromWebView:(UIWebView *)webView
{
}
-(void) webViewDidStartLoad:(UIWebView *)webView
{
NSLog(@"loading html start");
//[MBProgressHUD showHUDAddedTo:self.webView animated:YES];
}
-(void) webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(@"load html finish.");
//[MBProgressHUD hideHUDForView:self.webView animated:YES];
}
-(void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(@"load html error:%@",error);
//[MBProgressHUD hideHUDForView:self.webView animated:YES];
}
(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
NSLog(@"initWithNibName");
//self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate: (AppDelegate *)([UIApplication sharedApplication]).delegate];
self.javascriptBridge = [WebViewJavascriptBridge javascriptBridgeWithDelegate:self];
}
return self;
}
(void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"viewDidLoad");
//self.webView.delegate = self;
self.webView.delegate = self.javascriptBridge;
self.bundle = [NSBundle mainBundle];
[webView loadHTMLString:@"aaa" baseURL:[NSURL fileURLWithPath:[bundle bundlePath]]];
// Do any additional setup after loading the view, typically from a nib.
}
(void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
When I run it , the logger info in console is :
2012-05-03 20:11:06.777 test[14860:f803] initWithNibName
2012-05-03 20:11:06.791 test[14860:f803] viewDidLoad
2012-05-03 20:11:06.813 test[14860:f803] loading html start
2012-05-03 20:11:06.836 test[14860:f803] loading html start
2012-05-03 20:11:06.837 test[14860:f803] load html finish.
2012-05-03 20:11:06.840 test[14860:f803] load html finish.
Why the html connent loaded twice?
ps: I‘m using the xcode 4.3.2 and the sdk is 5.1
I have an issue where I'd like to send a message from the page hide event. The event itself does get called however if I call WebViewJavascriptBridge.sendMessage within that the message is never received. I assume this is because the iframe doesn't reload prior to the next page being displayed so it may not be possible to get round this. Apart from restructuring so there is a wrapper page with the displayed content and an iframe in.
window.addEventListener('pagehide', function () { WebViewJavascriptBridge.sendMessage('page hide'); }, false);
For now I think I can work around it with catching the subsequent page loads.
if I use self, it occur problem. how to visit "self" in block? or may I replace the block with a delegate?thanks,
any demo or example?
[_jsb registerHandler:@"mead_action" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"mead_action called: %@", data);
CommonWebViewController* wvc = [[CommonWebViewController alloc]init];
wvc.path = [data objectForKey:@"path"];
wvc.fileName = [data objectForKey:@"fileName"];
wvc.arg = [data objectForKey:@"arg"];
wvc.navigationItem.title = [data objectForKey:@"viewTitle"];
//if I use self, it occur problem. how to visit "self" in block? or may I replace the block with a delegate?thanks,
[self.navigationController pushViewController:wvc animated:YES];
responseCallback(@"Response:OK");
}];
Hi,
first of all very good job!
So, there is a secret
string property not used. Why?
Thanks
regards
GF
Hi marcus,
i want the handler to be called only when the getNameListBttnTapped method is triggered following is the script
<script> var bridge function getNameListBttnTapped(){ alert('inside getNameListBttnTapped') bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) { log('JS got response', response) alert(response) }) } window.onerror = function(err) { log('window.onerror: ' + err) } document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false) function onBridgeReady(event) { bridge = event.bridge } </script>Here is the code, i have used for registering the handler.
[_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"testObjcCallback called: %@", data);
responseCallback(@"Response from testObjcCallback");
}];
when i tap on the GetNameList button handler is called and the response is sent to webview javascript bridge, but the function(response) is not triggered.Please help me to solve the issue.
This isn't a huge deal, but I just wanted to confirm whether anyone has experienced this issue. I'm trying to load dynamically-created HTML in my webView:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"about:blank"]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.mainFrame loadRequest:request];
[self setEditable:YES];
[self setNeedsDisplay:YES];
NSBundle *webTechBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle]
pathForResource:@"MyWebTechBundle"
ofType:@"bundle"]];
NSMutableArray *scripts = @[@"js1.js", @"js2.js", @"js3.js"].mutableCopy;
for (NSString *script in scripts.copy) {
NSString *filePath = [webTechBundle pathForResource:[script stringByDeletingPathExtension] ofType:script.pathExtension];
NSString *fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[scripts replaceObjectAtIndex:[scripts indexOfObject:script] withObject:fileContents];
}
[self.windowScriptObject evaluateWebScript:[scripts componentsJoinedByString:@";"]];
self.webViewbridge = [WebViewJavascriptBridge bridgeForWebView:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"from DOM: %@", data);
}];
Whatever I do to dynamically load scripts, WBJB never works. It only seems to work with pre-defined html files. Has any testing been done with windowScriptObject
?
This is the first time I make a push to other's project and not very successfully.
I have try push to the https://github.com/marcuswestin/WebViewJavascriptBridge.git,it tell me the Permission denied
and also the ssh way [email protected]:marcuswestin/WebViewJavascriptBridge.git
can you tell me, what's wrong? thanks
In ExampleAppViewController.m, the call to loadHTMLString:baseURL: has a nil baseURL resulting in javascripts not being loaded from ExampleApp.html. Adding NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; solves this.
Hello,
First, I would like to say that I'm new to objective-C world so I'm sorry if my question is too lame...
I'm currently trying to integrate this bridge into my C++ project and I have some issues targeting an iOS device.
What I've done is simple, I've just put the WebViewJavascriptBridge.* files to my project and compiled it with -x and objective-c++ flags.
On WebViewJavascriptBridge.h, I have a lot of semantic issue with WVJB_WEBVIEW_TYPE but after a quick search I found that adding the import of UIKit is enough to remove these errors.
But know, I have 12 semantic issues into WebViewJavascriptBridge.m with typeof and strongDelegate and I don't know how to fix that.
Do you have any idea of what can be the origin of these issues ? Did I do something wrong ?
Thanks in advance for your answer.
Has this been tested in iOS 7 and XCode 5? I've been using it the last couple of days and am not seeing any sent messages from Obj C to JS. JS calling Obj C works, but not vice versa.
Hello Marcus!
Excellent library! I'm a very new iOS developer (I only started a few days ago), and I'm trying to utilize the bridge with a UIWebView that I've got on my Storyboard. Whenever I try to use it, I get an EXEC_BAD_ACCESS error.
The trouble lines seem to be:
- (void)viewDidLoad
{
[super viewDidLoad];
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"Received message from javascript: %@", data);
responseCallback(@"Right back atcha");
}];
webView.scrollView.bounces = NO;
[[UIApplication sharedApplication] setStatusBarHidden:YES];
NSString *path = [[NSBundle mainBundle] bundlePath];
path = [NSString stringWithFormat:@"%@/%s", path, "htdocs/index.html"];
NSURL *URL = [NSURL fileURLWithPath:path];
[webView loadRequest:[[NSURLRequest alloc] initWithURL:URL]];
}
To be exact, the last line. If I don't make that request, I don't get the error. I've tried it with a UIWebView created just in Objective-C, and still gotten the error, although maybe I did it wrong.
Any suggestions?
the bridge stops working in above environment.
I step into code, and found that in WebViewJavascriptBridge.m
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"WebViewJavascriptBridge.js" ofType:@"txt"];
filePath is nil in above environment, working in other environment.
found a stackover flow thread about the nsbundle loading issue:
http://stackoverflow.com/questions/18888212/after-ios-7-update-pathforresource-returns-nil
is it possible to release a fix for that?
thanks.
sendMessage was called after onBridgeReady.
I couldn't reproduce this consistently.
it seems that _readyMessageIframe.src = customProtocol://queueHasMessage was not called correctly for some reasons.
Result:
message was pushed to sendMessageQueue
webview shouldStartLoadWithRequest was called
but the URL was about:blank
instead of customProtocol://queueHasMessage
and thus _flushMessageQueueFromWebView is not triggered.
If I call _flushMessageQueueFromWebView without checking the protocol, the flushing will work but there're extra unnecessary overheads.
Hello, the head version is 3.0.0, but the version for cocoapods is 2.1.1。
Could you update the cocoapods version?
Thank you!
I tried this from what I read in some other issues. But there seems to be no protocol defined.
@interface MyViewController : UIViewController
So I tried:
@interface MyViewController : UIViewController
this still doesn't do anything. Following your instruction worked fine from my appdelegate. but whenever I bring it over to a viewcontroller it doesn't even log any output
Hi,
I'm developing an iOS app which communicates with UIWebView. And thank you for your great library.
I'm managing all the components loaded in a WebView side with Bower.
WebViewJavascriptBridge has a text file which is injected into a webView and executed as JavaScript.
I wanted to manage the script with bower as well as other libraries, and searched for it.
There is a hit in the bower repository named WebViewJSBridge.js managed by a third party, and seems to be just a copy of your script.
https://github.com/quangpham/WebViewJsBridge
The bower entry has nothing to do with your WebViewJavascriptBridge, and may not guaranteed to be updated.
Why don't you create a bower entry yourself?
Hi,
I'm trying to build a Hybrid app using the bridge (I'm literally a few days old in iOS dev) .
have a tabbar navigation based app, and I'm using a UIViewController for each tab view, one of the tab would use the WebView.
I wast sure if I could implement WebViewJavascriptBridgeDelegate in a UIViewController class like below.
@interface CurrentTimeViewController : UIViewController <UIWebViewDelegate, WebViewJavascriptBridgeDelegate>
I get a EXC_BAD_ACC during runtime in the main class
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
Any pointer would be much appreciated.
-Imran
The OSX example app fails to run. The console offers this message:
Unable to load nib file: MainMenu, exiting
I can't see MainMenu.xib or anything related in the Examples directory. Why is it omitted?
Hi
I have been struggling with an issue for the past few days.The issue is
We have a html page which communicates wih th javascript file teh javascript file in turn communicates with the native ios code of the app using your webview javascript bridge.The problem is
in the following js function we are calling a function of another javascript file
TheApp.getAppVersion = function()
{
var vpbVersion = VestaPhoneBridge.GetUserAgent().version;
if(vpbVersion != null)
{
return ""+vpbVersion;
}
return null;
};
The above method is calling a function in another .js file which is as follows:
VestaPhoneBridge.GetUserAgent = function(_callback)
{
bridge.callHandler('initiateGetUserAgentFunc','test', function(response)
{
//getting response here from native
})
};
The problem is in the function "bridge.callHandler('initiateGetUserAgentFunc','test', function(response) " inside the above function
we are needed to return a value but we need to return the value to VestaPhoneBridge.GetUserAgent instead of "bridge.callHandler('initiateGetUserAgentFunc','test', function(response)"
The problem is we cannot use callback function in js also.The only thing is we have to return a value.
So it would be really great if you could suggest some solution for this problem.
Thanks
Murli Krishna .V
Hello,
I'm still working on an iOS project using UIWebView, and I need to use this WebViewJavascriptBridge to propagate JS events like touches events.
Until now, I didn't used the bridge, I had a event listener JS side that put each event content into an array and C++ side I just called the Objective-C function named stringByEvaluatingJavaScriptFromString of my UIWebView to access to this event content.
The problem is that I always have to check if an event has been added to my array whereas it would be much more better to use the bridge JS side to directly raise the event C++ side.
That's what I tried to do but that doesn't work very well.
First, if I take the example of touches events, when I move my fingers, there is a lot of events that are triggered very quickly and the bridge stop to transmite messages after a little moment until I release my fingers out of the surface after what the bridge send all messages that it couldn't send before.
Second, I've test a little project with a single rotating cube and a webview over it to catch events. When I move a finger over the surface, the events are sent but the cube freezes during that. I don't have this issue using my former method without the bridge.
Do you know how can I resolve these problems ?
Thank you very much in advance.
There is a problem in the podspec:
s.resource = 'WebViewJavascriptBridgeAbstract/WebViewJavascriptBridge.js.txt'
"WebViewJavascriptBridgeAbstract/..." is referenced, although it should be "WebViewJavascriptBridge/...".
This results in the JavaScript file not being included in the project and JavaScript exceptions. I think someone fixed that for the Podspec in the official repository, since that works just fine (but it's outdated).
I found that brigde code inject into the html , after webViewDidFinishLoad, as I know, this event would be called after all element load. We may wait for a minute if one image request time out.
And I want to received a message when the html did load ,and show. Not wait for image show.
How can I do?
Hello again,
I finally successfully compile the WebViewJavascriptBridge in C++ and I can now use it, but I still have a problem.
The library works well when I tried with a simple HTML page but if I put an empty iframe, I can't send messages like before, it can't find the variable WebViewJavascriptBridge.
In fact, the file WebViewJavascriptBridge.js.txt is loaded after I try to send my message instead of without the empty iframe, this file is loaded before.
Do you know why ?
Thanks in advance.
Is there an OSX version of this project?
I'm trying to add a WebViewJavascriptBridge to my existing phonegap application, but when I try to add the bridge to the webview, my application never loads past the splash screen.
I have this in didFinishLaunchingWithOptions:
WebViewJavascriptBridge* javascriptBridge = [WebViewJavascriptBridge javascriptBridgeForWebView:self.viewController.webView handler:^(id data, WVJBResponseCallback callback) {
NSLog(@"Received message from javascript: %@", data);
}];
I see that the events get fired, but my app doesn't load. Is this is an issue, or is there something I'm missing that's breaking startup?
I used AFNetWorking to fetch data from remote service API, when the data ready, I tried to transfer the data back to javascript, but it raise an error. Any advice is appreciate. My code look like this.
^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"data: %@", data);
NSString *service = [data objectForKey:@"service"];
BOOL needLogin = [[data objectForKey:@"needLogin"] boolValue];
NSDictionary *businessParams = [data objectForKey:@"businessParams"];
[[AHAPIClient sharedClient] consumeRemoteService:service
needLogin:needLogin
withParameters:businessParams
success:^(id JSON) {
responseCallback(JSON);
}
failure:^(NSError *error) {
responseCallback(error.userInfo);
}];
}
Hi,
I ran the example code for iPhone 5.1 Simulator and everything works fine.
I'm using Xcode 4.4 with the storyboard and I already have a UIWebView. I pasted this code from the example usage into the viewDidLoad event
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView handler:^(id data, WVJBResponse* response) {
NSLog(@"Received message from javascript: %@", data);
[response respondWith:@"Right back atcha"];
// or [response respondWithError:]
}];
but got this error "no known class for selector 'bridgeForWebView'
Did I do something wrong or can I not use it in the manner? Any suggestion on how to use this appropriately in my case?
Thanks for your help,
Kalvin
Hi Marcus, thanks for yours great code. I was wondering if it would be possible to trigger an UIImagePickerController from the javascript, choose a photo and give it back to the javascript? I would like to use it as a workaround for file upload which is unavailable on safari. Any guidance would be much appreciated.
Many thanks,
Leo
Shouldn't examples be in another repo, so I could without tinkering (ignoring examples), submodule your library ?
Can we set a callback for the bridge object so after your code been called, also call my own code.
Or you can call parent object's webview callback methods, detect by isRespond?
something like that.
Is WebViewJavascriptBridgeDelegate deprecated?
Then how can I use WebViewJavascriptBridge on my UIViewController?
thanks.
There is not error any more. Webview load url completely but not trigger call webViewDidFinishLoad
System: IOS7, iPhone4s
DetailViewController.h
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController<UIWebViewDelegate>
@property (strong, nonatomic) id detailId;
@property (strong, nonatomic) id detailTitle;
@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
@end
DetailViewController.m
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(@"Hide loading animation");
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
- (void)viewDidLoad
{
UIWebView *webView = [viewController webView];
[[webView scrollView] setBounces:NO];
[WebViewJavascriptBridge enableLogging];
WebViewJavascriptBridge* bridge = [WebViewJavascriptBridge bridgeForWebView:webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"Received message from javascript: %@", data);
if (responseCallback) {
responseCallback(@"Right back atcha");
}
}];
}
Example project crashes on iOS5+
CALLBACK_ARGUMENTS_KEY
in webviewJavascriptBridge
It was good to work with WVJsBrige as a component for fluid interop between native and web code. I'd love to continue using WKWebView as I port the reference WebView-based app framework for our products and client projects.
Until 10.10 becomes stable enough to develop in, we can use the iOS 8 SDK to start working on a port. I'd like to start one soon, and would love to hear from you regarding how you'd plan out an attack. Any feedback or advice would be welcome here.
Just thought I'd share. http://blog.persistent.info/2013/10/a-faster-uiwebview-communication.html
Hi!
There' a lot of a little bit dirty commits in history, so i'm unable to provide a pull request right now.
However, i want to inform all WebViewJavascriptBridge users, that there's a bug, that may lead to losing some messages from JS.
We've fixed that bug and isolated fix's diff in one commit.
Here it is: psineur@a6c39ff
Also in my develop branch i added customization to Bridge's JS Object & Method names, so probably you would like to take a look.
Cheers!
I was using 4.0.2 when this problem occured, so I upgraded to 4.1.0 to be sure. It still happens.
For some inexplicable reason I've started getting EXC_BAD_ACCESS when loading a web view that has the WVJB initialized with it.
The view controller I'm in is a basic UIViewController that is also a UIWebViewDelegate. I still need access to the webview's callbacks after WVJB has done its thing.
I initialize the bridge into the webview as follows.
// initialize webview bridge
[WebViewJavascriptBridge enableLogging];
bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView webViewDelegate:self handler:^(id data, WVJBResponseCallback responseCallback) {
NSString *type = [data valueForKey:@"type"];
if ([type isEqualToString:@"photo-upload"]) {
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate switchToCameraUI];
}
}];
Here's the back trace:
* thread #1: tid = 0x26bc1d, 0x018ca0b2 libobjc.A.dylib`objc_msgSend + 14, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=2, address=0x1a)
frame #0: 0x018ca0b2 libobjc.A.dylib`objc_msgSend + 14
frame #1: 0x00019883 HealthyU`-[WebViewJavascriptBridge webViewDidFinishLoad:](self=0x0fc20330, _cmd=0x00bce8cb, webView=0x0fcf5c70) + 595 at WebViewJavascriptBridge.m:339
frame #2: 0x0065cd54 UIKit`-[UIWebView webView:didFinishLoadForFrame:] + 388
frame #3: 0x0065ec42 UIKit`-[UIWebViewWebViewDelegate webView:didFinishLoadForFrame:] + 56
frame #4: 0x0219fd1d CoreFoundation`__invoking___ + 29
frame #5: 0x0219fc2a CoreFoundation`-[NSInvocation invoke] + 362
frame #6: 0x0219fdaa CoreFoundation`-[NSInvocation invokeWithTarget:] + 74
frame #7: 0x04cc011d WebKit`-[_WebSafeForwarder forwardInvocation:] + 157
frame #8: 0x0219b6da CoreFoundation`___forwarding___ + 458
frame #9: 0x0219b4ee CoreFoundation`_CF_forwarding_prep_0 + 14
frame #10: 0x0219fd1d CoreFoundation`__invoking___ + 29
frame #11: 0x0219fc2a CoreFoundation`-[NSInvocation invoke] + 362
frame #12: 0x05cd18a9 WebCore`SendDelegateMessage(NSInvocation*) + 201
frame #13: 0x04c40861 WebKit`CallFrameLoadDelegate(objc_object* (*)(objc_object*, objc_selector*, ...), WebView*, objc_selector, objc_object*) + 145
frame #14: 0x04c62dff WebKit`WebFrameLoaderClient::dispatchDidFinishLoad() + 207
frame #15: 0x0517bffa WebCore`WebCore::FrameLoader::checkLoadCompleteForThisFrame() + 282
frame #16: 0x051741b0 WebCore`WebCore::FrameLoader::checkLoadComplete() + 208
frame #17: 0x05017d5d WebCore`WebCore::DocumentLoader::finishedLoading(double) + 605
frame #18: 0x0501c0e8 WebCore`WebCore::DocumentLoader::maybeLoadEmpty() + 744
frame #19: 0x0501c40d WebCore`WebCore::DocumentLoader::startLoadingMainResource() + 349
frame #20: 0x0517cad7 WebCore`WebCore::FrameLoader::continueLoadAfterWillSubmitForm() + 167
frame #21: 0x05179847 WebCore`WebCore::FrameLoader::continueLoadAfterNavigationPolicy(WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool) + 695
frame #22: 0x051798e0 WebCore`WebCore::FrameLoader::callContinueLoadAfterNavigationPolicy(void*, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool) + 48
frame #23: 0x058a9f15 WebCore`WebCore::PolicyCallback::call(bool) + 69
frame #24: 0x058aac1f WebCore`WebCore::PolicyChecker::continueAfterNavigationPolicy(WebCore::PolicyAction) + 799
frame #25: 0x04c68a0c WebKit`-[WebFramePolicyListener receivedPolicyDecision:] + 92
frame #26: 0x04c68af9 WebKit`-[WebFramePolicyListener use] + 41
frame #27: 0x0065c452 UIKit`-[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 776
frame #28: 0x0065e854 UIKit`-[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 77
frame #29: 0x0219fd1d CoreFoundation`__invoking___ + 29
frame #30: 0x0219fc2a CoreFoundation`-[NSInvocation invoke] + 362
frame #31: 0x0219fdaa CoreFoundation`-[NSInvocation invokeWithTarget:] + 74
frame #32: 0x04cc011d WebKit`-[_WebSafeForwarder forwardInvocation:] + 157
frame #33: 0x0219b6da CoreFoundation`___forwarding___ + 458
frame #34: 0x0219b4ee CoreFoundation`_CF_forwarding_prep_0 + 14
frame #35: 0x04c638b1 WebKit`WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(void (WebCore::PolicyChecker::*)(WebCore::PolicyAction), WebCore::NavigationAction const&, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>) + 225
frame #36: 0x058aa73b WebCore`WebCore::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest const&, WebCore::DocumentLoader*, WTF::PassRefPtr<WebCore::FormState>, void (*)(void*, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool), void*) + 1147
frame #37: 0x051790ca WebCore`WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WTF::PassRefPtr<WebCore::FormState>) + 922
frame #38: 0x0517810d WebCore`WebCore::FrameLoader::loadWithNavigationAction(WebCore::ResourceRequest const&, WebCore::NavigationAction const&, bool, WebCore::FrameLoadType, WTF::PassRefPtr<WebCore::FormState>) + 573
frame #39: 0x05175c61 WebCore`WebCore::FrameLoader::loadURL(WebCore::KURL const&, WTF::String const&, WTF::String const&, bool, WebCore::FrameLoadType, WTF::PassRefPtr<WebCore::Event>, WTF::PassRefPtr<WebCore::FormState>) + 1297
frame #40: 0x0517450e WebCore`WebCore::FrameLoader::loadURLIntoChildFrame(WebCore::KURL const&, WTF::String const&, WebCore::Frame*) + 366
frame #41: 0x04c66482 WebKit`WebFrameLoaderClient::createFrame(WebCore::KURL const&, WTF::String const&, WebCore::HTMLFrameOwnerElement*, WTF::String const&, bool, int, int) + 354
frame #42: 0x05b5c9a1 WebCore`WebCore::SubframeLoader::loadSubframe(WebCore::HTMLFrameOwnerElement*, WebCore::KURL const&, WTF::String const&, WTF::String const&) + 289
frame #43: 0x05b5b05f WebCore`WebCore::SubframeLoader::loadOrRedirectSubframe(WebCore::HTMLFrameOwnerElement*, WebCore::KURL const&, WTF::AtomicString const&, bool, bool) + 191
frame #44: 0x05b5ae10 WebCore`WebCore::SubframeLoader::requestFrame(WebCore::HTMLFrameOwnerElement*, WTF::String const&, WTF::AtomicString const&, bool, bool) + 672
frame #45: 0x05234b4c WebCore`WebCore::HTMLFrameElementBase::openURL(bool, bool) + 188
frame #46: 0x052352ca WebCore`WebCore::HTMLFrameElementBase::setNameAndOpenURL() + 410
frame #47: 0x04ee0399 WebCore`WebCore::ChildNodeInsertionNotifier::notify(WebCore::Node*) + 249
frame #48: 0x04edcafb WebCore`WebCore::updateTreeAfterInsertion(WebCore::ContainerNode*, WebCore::Node*, WebCore::AttachBehavior) + 155
frame #49: 0x04edc73c WebCore`WebCore::ContainerNode::appendChild(WTF::PassRefPtr<WebCore::Node>, int&, WebCore::AttachBehavior) + 348
frame #50: 0x0586b12d WebCore`WebCore::Node::appendChild(WTF::PassRefPtr<WebCore::Node>, int&, WebCore::AttachBehavior) + 61
frame #51: 0x0560954b WebCore`WebCore::JSNode::appendChild(JSC::ExecState*) + 107
frame #52: 0x05606883 WebCore`WebCore::jsNodePrototypeFunctionAppendChild(JSC::ExecState*) + 115
frame #53: 0x72ce87cf
frame #54: 0x0977a1ac JavaScriptCore`JSC::Interpreter::execute(JSC::ProgramExecutable*, JSC::ExecState*, JSC::JSObject*) + 5532
frame #55: 0x0967dcad JavaScriptCore`JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, JSC::JSValue*) + 525
frame #56: 0x055d118b WebCore`WebCore::JSMainThreadExecState::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, JSC::JSValue*) + 91
frame #57: 0x05a7fdd6 WebCore`WebCore::ScriptController::evaluateInWorld(WebCore::ScriptSourceCode const&, WebCore::DOMWrapperWorld*) + 262
frame #58: 0x05a80088 WebCore`WebCore::ScriptController::evaluate(WebCore::ScriptSourceCode const&) + 40
frame #59: 0x05a82d35 WebCore`WebCore::ScriptController::executeScript(WebCore::ScriptSourceCode const&) + 101
frame #60: 0x05a82bc4 WebCore`WebCore::ScriptController::executeScript(WTF::String const&, bool) + 116
frame #61: 0x04c4ea5a WebKit`-[WebFrame(WebInternal) _stringByEvaluatingJavaScriptFromString:forceUserGesture:] + 298
frame #62: 0x04c4e920 WebKit`-[WebFrame(WebInternal) _stringByEvaluatingJavaScriptFromString:] + 48
frame #63: 0x04cc2c1b WebKit`-[WebView stringByEvaluatingJavaScriptFromString:] + 59
frame #64: 0x0065aa78 UIKit`-[UIWebView stringByEvaluatingJavaScriptFromString:] + 84
frame #65: 0x000197e0 HealthyU`-[WebViewJavascriptBridge webViewDidFinishLoad:](self=0x0fc20330, _cmd=0x00bce8cb, webView=0x0fcf5c70) + 432 at WebViewJavascriptBridge.m:335
frame #66: 0x0065cd54 UIKit`-[UIWebView webView:didFinishLoadForFrame:] + 388
frame #67: 0x0065ec42 UIKit`-[UIWebViewWebViewDelegate webView:didFinishLoadForFrame:] + 56
frame #68: 0x0219fd1d CoreFoundation`__invoking___ + 29
frame #69: 0x0219fc2a CoreFoundation`-[NSInvocation invoke] + 362
frame #70: 0x0219fdaa CoreFoundation`-[NSInvocation invokeWithTarget:] + 74
frame #71: 0x04cc011d WebKit`-[_WebSafeForwarder forwardInvocation:] + 157
frame #72: 0x0219b6da CoreFoundation`___forwarding___ + 458
frame #73: 0x0219b4ee CoreFoundation`_CF_forwarding_prep_0 + 14
frame #74: 0x0219fd1d CoreFoundation`__invoking___ + 29
frame #75: 0x0219fc2a CoreFoundation`-[NSInvocation invoke] + 362
frame #76: 0x05cd2b29 WebCore`HandleDelegateSource(void*) + 121
frame #77: 0x0213483f CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
frame #78: 0x021341cb CoreFoundation`__CFRunLoopDoSources0 + 235
frame #79: 0x0215129e CoreFoundation`__CFRunLoopRun + 910
frame #80: 0x02150ac3 CoreFoundation`CFRunLoopRunSpecific + 467
frame #81: 0x021508db CoreFoundation`CFRunLoopRunInMode + 123
frame #82: 0x02f219e2 GraphicsServices`GSEventRunModal + 192
frame #83: 0x02f21809 GraphicsServices`GSEventRun + 104
frame #84: 0x0041bd3b UIKit`UIApplicationMain + 1225
frame #85: 0x0001ecb2 HealthyU`main(argc=1, argv=0xbfffee60) + 130 at main.m:16
frame #86: 0x01d9f725 libdyld.dylib`start + 1
After load a url,the webViewDidFinishLoad called twice each time! And the webview.isLoading always is YES. In my opinion,It's error,because the page have been loaded, why it is still isLoading? can anyone explain it?
I've experienced problems connecting the page with the bridge in a couple of different instances, and in both cases it was due to the page not loading fast enough to start listening for the WebViewJavascriptBridgeReady
event.
The problem may occur when you have components that use the bridge that are executed well after the page is initially loaded, for example, I was trying to connect to the bridge in an AngularJS app which has a prolonged page load sequence.
The other problem I saw was that the webViewDidFinishLoad:
was being fired before all the scripts had loaded. In this case the scripts were at the bottom of the <body>
element so perhaps UIWebView is considering the body of the page effectively loaded since the scripts don't contribute to the initial rendering. The result was, again, that the WebViewJavascriptBridgeReady
event was being fired before the page JS could listen to it.
Anyway, long story short, the solution for me was to do something like this:
function connectToBridge(fn) {
if (window.WebViewJavascriptBridge) {
fn(WebViewJavascriptBridge);
} else {
document.addEventListener('WebViewJavascriptBridgeReady', function(ev) {
fn(ev.bridge);
});
}
}
connectToBridge(function (bridge) {
bridge.init(function (msg) {
...
});
});
Essentially, detect that bridge hasn't already loaded before listening for the event.
I wondered if you'd consider putting this on the README.md
? Might save somebody else some time.
Otherwise, WebViewJavascriptBridge is awesome, thank you!
Hi marcus,
i have a javascript method like this
phoneBridge.isAvailable=function isAvailable(featurename){
bridge.callhandler('registerIsAvailable',featurename,function(response){
return response;
})
}
Since the call to this method is asynchronous, i could not returnn the values. Javascript is not waiting untill the method is executed.Could you please suggest me a way to return the values.Please help me to solve this issue.
The following codes in WebViewJavascriptBridgeAbstract.h would not work when my project's deployment target was set to iOS 4.3
#define WEAK_FALLBACK weak
#define WEAK_FALLBACK weak
#define WEAK_FALLBACK unsafe_unretained
#define WEAK_FALLBACK weak
#define WEAK_FALLBACK unsafe_unretained
when i am trying to use the codebase in my project its giving following error
function connectWebViewJavascriptBridge(callback)
connectWebViewJavascriptBridge an anoymous function and there is no data from response callback.
Hi. I really thankyou for your Code.
But there is a issue for me.
I tried add UIActivtyIndicatorView in UIAlertView when web is loading.
in normal case I added addSubView code in webViewDidStartLoad and dismiss in webViewDidFinishLoad. It worked well.
But after add WebViewJavascriptBridge, i added addSubView in WebViewJavascriptBridge's webview delegate.. but the alertView popup 3times.
and it didn't dismiss
i think when ObjC comunicate with Javascrtipt webViewDidStartLoad is called.. everytimes
i tried
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0)
if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]])
[(UIAlertView *)[subviews objectAtIndex:0] dismissWithClickedButtonIndex:[(UIAlertView *)[subviews objectAtIndex:0] cancelButtonIndex] animated:NO];
}
in webViewDidFinishLoad but it didn't worked.
is there any solution?
sorry i'm really not good at English.
I have dealloc problem when using WVJB enable UIWebView. I think problem maybe the memory management. Right?
Without WVJB
A -> push -> B (UIWevView) -> pop back -> A (A trigger dealloc) -> B (UIWebView)
With WVJB
A -> push -> B (UIWevView) -> pop back -> A (A not trigger dealloc) -> B (UIWevView but nothing happen here)
Without WVJB
_webView = [viewController webView];
[_webView setDelegate:self];
With WVJB
_webView = [viewController 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");
}];
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.