My Goal is to send data from iOS device to WkWebView. After researching on how to do this task I get to know that it can be done via executing JavaScript function via WkWebView, therefore, I tried calling just a simple alert function:
#interface UIWebViewController () <WKNavigationDelegate, WKUIDelegate>
#end
WKWebView *webView;
-(void)webView:(WKWebView )webView didFinishNavigation:(WKNavigation )navigation{
NSString* javascriptString = #"alert('Hi');";
[webView evaluateJavaScript:javascriptString completionHandler:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:theConfiguration];
webView.navigationDelegate = self;
}
Unfortunately I am not able to see any alert with that code?
Can you let me know what kind of silly mistake I am doing in the above code?
Related
I'm using a WKWebview to run javascript scripts.
I am not using JSContext et.al since I need the javascript context to be able to perform XHTTP requests which aren't possible with JSContext alone.
This view is not added to the view hierarchy and I have no interest to do so.
The WKWebview is only used for its ability to run JS code in its engine.
The javascript code is working exactly as expected on the simulator.
The exact same code will also work in the context of certain other applications which I've tested with.
But for some reason in certain applications the WKWebview will not perform the javascript unless the WKWebview is added to the view hierarchy. The following code will work as expected. If removing the #warning code , stops working as expected
-(void)connect {
//TODO: Handle multiple connect calls
WKUserContentController *userContentController = [WKUserContentController new];
[self addScriptMessageHandlersForSocketEvents:userContentController];
NSString *socketFileContent = [self.class socketIOScript];
WKUserScript *socketIOScript = [[WKUserScript alloc] initWithSource:socketFileContent
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO];
[userContentController addUserScript:socketIOScript];
NSString *bridgeJs = [self.class bridgeScript];
WKUserScript *bridgeScript = [[WKUserScript alloc] initWithSource:bridgeJs
injectionTime:WKUserScriptInjectionTimeAtDocumentStart
forMainFrameOnly:NO];
[userContentController addUserScript:bridgeScript];
NSMutableDictionary *d = [NSMutableDictionary new];
for (NSURLQueryItem *item in _parameters) {
d[item.name] = item.value;
}
NSString *params = json(d);
NSString *socketURLScript = [NSString stringWithFormat:#"createSocket(%#,%#);log('created script')",stringify(_url),params];
WKUserScript *createSocket = [[WKUserScript alloc] initWithSource:socketURLScript
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
forMainFrameOnly:NO];
[userContentController addUserScript:createSocket];
WKWebViewConfiguration * wkconfiguration = [WKWebViewConfiguration new];
wkconfiguration.userContentController = userContentController;
_wv = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0) configuration:wkconfiguration];
#warning REMOVE THIS AND THE WKWebview stops working on some devices (NOT ALL DEVICES) and works in some applications as expected
[[UIApplication sharedApplication].keyWindow addSubview:_wv];
// END REMOVE THIS
_wv.navigationDelegate = self;
dispatch_group_enter(_loadedSemaphore);
[_wv loadHTMLString:#"<h1></h1>" baseURL:nil];
}
did you implement all the delegate methods for WKWebView ?
I was wondering if anyone knew how to do this. I have a bunch of NSNotifications and I'd like to create listeners in Javascript, embedded in a UIWebView, that will get executed when the NSNotifications are received.
I know this is possible using PhoneGap and the method sendPluginResult, but I was wondering if there was another way of doing it without cordova.
Thanks
Create your listener outside the UIWebView and send the stringByEvaluatingJavaScriptFromString message to your web view.
- (void)registerObserver
{
NSArray *names = [NSArray arrayWithObjects:
#"FirstNotification", #"SecondNotification", #"ThirdNotification", nil];
for (NSString *name in names)
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(notificationReceived:)
name:#"NotificationName"
object:nil];
}
}
- (void)notificationReceived:(NSNotification *notification)
{
NSString *js = [NSString stringWithFormat:
#"notificationReceived('%#');", notification.name];
[self.webView stringByEvaluatingJavaScriptFromString:js];
}
in the call back NSNotification method call this:
[yourwebview stringByEvaluatingJavaScriptFromString:#"methodName()"];
and create that "methodname" in your javascript code
I'm trying to download a file programmly on this site, and I found that when you click the highlighted download button("下载"), it runs a Javascript: document.getElementById('downLoad').action='/download.php?fileid=11024011';downishare('0');
On my Mac, it runs fine and downloads the file when I run it on Safari. But when I use
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.getElementById('downLoad').action='/download.php?fileid=11024011'"]];
It doesn't return anything.
Does anyone know why and how can I get the download URL?
Thanks.
Well... the download url is this: http://ishare.iask.sina.com.cn/download.php?fileid=11024011
You can check it also with the 'Network' tab in chrome or firebug in firefox. BUT... when you try to access it directly, it redirects you. There might be some server side validation of the request, like the referrer url or something.
Have you tried implementing the webView delegate method shouldStartLoadWithRequest to parse through links?
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
if ([[[request URL] absoluteString] hasPrefix:#"http://ishare.iask.sina.com.cn/download.php?fileid="])
//I believe this would download everything that has a link prefix of "http://ishare.iask.sina.com.cn/download.php?fileid="
//So you should create some sort of checker to make sure it only downloads the file they select
// Determile cache file path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0],#"index.html"];
// Download and write to file
NSURL *url = [NSURL URLWithString:[[request URL] absoluteString]];
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
// Load file in UIWebView
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:filePath]]];
return NO;
}
else {
return YES;
}
I am extrating from a web page dynamic values generated by javascript and it worked fine on OS X Lion but failed on Mountain Lion 10.8.1 (I get empty string).
Here is the code in my controller :
-(void) addValue:(id) sender {
NSString *value = [webView stringByEvaluatingJavaScriptFromString: #"document.getElementById('xxx').textContent"];
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
[self addValue:self];
}
- (void) getjavascriptValue {
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"htmlPagePath"] ]]];
}
webView is declared as IBOutlet WebView *webView; and I made the connections of webView and frameLoadDelegate to my controller with Interface Builder.
Your help will be very much appreciated
<script language="javascript">
alert("Hell! UIWebView!");
</script>
I can see the alert message inside my UIWebView but can I handle this situation?
Update:
I'm loading a web-page into my UIWebView:
- (void)login {
NSString *requestText = [[NSString alloc] initWithFormat: #"%#?user=%#&password=%#", DEFAULT_URL, user.name, user.password]; // YES, I'm using GET request to send password :)
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestText]];
[webView loadRequest:request];
}
The target page contain a JS. If user name or password is incorrect this JS show alert.
I have not any access to its sources.
I want to handle it inside my UIWebViewDelegate.
A better solution to this problem is to create a Category for UIWebView for the method
webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:
So that you can handle the alert event in any way that you'd like. I did this because I don't like the default behavior of UIWebView when it puts the filename of the source in the UIAlertView title. The Category looks something like this,
#interface UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame;
#end
#implementation UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
UIAlertView* dialogue = [[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[dialogue show];
[dialogue autorelease];
}
#end
This seems to do it:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
JSContext *ctx = [webView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
ctx[#"window"][#"alert"] = ^(JSValue *message) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"JavaScript Alert" message:[message toString] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
};
}
Note: only tested on iOS 8.
If by "contain a flash" you mean the page you're loading into your web view has an Adobe Flash movie in it, you're out of luck, I'm afraid. Mobile Safari doesn't support Flash, and most likely never will.
In the general case, if you want JavaScript running in a web view to communicate with the native app hosting it, you can load fake URLs (for example: "myapp://alert?The+text+of+the+alert+goes+here."). That will trigger the webView:shouldStartLoadWithRequest:navigationType: delegate method. In that method, inspect the request, and if the URL being loaded is one of these internal communications, trigger the appropriate action in your app, and return NO.