I have set up an app that uses a UIWebView. The UIWebView is used to display text formatted with CSS. In the text are links (a href=...). The format of the href is like this: tags.tagname
When a user clicks a link, I'd like to intercept the request and use loadHTMLString based on the contents of the HREF.
I have successfully parsed the URL, but I'm stymied on how to tell the webview to not load the requested href and load the string I want instead.
I've tried the following within ShouldStartLoadWithRequest:
genHTML=[self genTagPage:parsedString]; // a string declared earlier
[self.noteHTML loadHTMLString:genHTML baseURL:nil];
return NO;
But when the code is executed, I receive the following error:
2011-04-19 22:39:21.088 TestApp[27026:207] *** -[_PFArray release]: message sent to deallocated instance 0xaa3cf40
genHTML is getting populated with the right data, so I'm at a loss as to how to proceed.
Thanks.
It sounds like you just need to prevent the default action for the link like the following:
<a href="somewhere.html" onClick="doSomething(); return false">
Check out quirksmode for more details.
Edit:
Re-read your original code, and it would seem you've got an infinite loop going on. shouldStartLoadWithRequest gets called once when they click on the link, then infinitely on your loadHTMLString line. Making the call conditional on the navigationType should fix your problem:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if(navigationType==UIWebViewNavigationTypeLinkClicked)
{
genHTML=[self genTagPage:parsedString]; // a string declared earlier
[self.noteHTML loadHTMLString:genHTML baseURL:nil];
return NO;
}
return YES;
}
Related
As WKWebView contents can finally be printed out in macOS 11+, I'm trying to replace old WebView dependencies.
However, with the HTML correctly loaded in WKWebView, creating PDF files using NSPrintJobDisposition: NSPrintSaveJob produces blank, empty documents. They have the correct page count and sizing, but remain empty. Using the same code without NSPrintSaveJob works just fine.
This is how I'm printing the contents:
NSPrintInfo *printInfo = NSPrintInfo.sharedPrintInfo;
[printInfo.dictionary addEntriesFromDictionary:#{
NSPrintJobDisposition: NSPrintSaveJob,
NSPrintJobSavingURL: url
}];
NSPrintOperation *printOperation =[(WKWebView*)_webView printOperationWithPrintInfo:printInfo];
printOperation.view.frame = NSMakeRect(0,0, printInfo.paperSize.width, printInfo.paperSize.height);
printOperation.showsPrintPanel = NO;
printOperation.showsProgressPanel = YES;
[printOperation runOperation];
Setting showsPrintPanel as true and uncommenting the dictionary will display a normal print dialog, and the result looks completely normal there.
I'm confused about what I am doing wrong, or is printing from WKWebView still this buggy?
Sample project:
https://www.dropbox.com/s/t220cn8orooorwb/WebkitPDFTest.zip?dl=1
Create PDF and Print buttons share the same code (found in PreviewView), but the other produces an empty file, which is then loaded into the PDFView.
Further findings
By what I've gathered online, this could be a long-running bug.
It seems that WKWebView prefers using its createPDF method when creating PDF files in the background, but that method renders what is displayed on screen, not the actual document content with page breaks and print stylization. It also appears to ignore some NSPrintInfo settings.
WKWebView printing is very badly documented. The reason for the blank pages is the run-loop code in WebKit, and all printing must happen asynchronously.
This is why [printOperation runOperation] / printOperation.runOperation() does not work. Instead, you need to call the strangely named runOperationModalForWindow. Although the method name refers to a modal window, you don't need to display the modal, but this method somehow makes the print operation asynchronous.
// Create print operation
NSPrintOperation *printOperation = [webView printOperationWithPrintInfo:printInfo];
// Set web view bounds - without this, the operation will crash
printOperation.view.frame = NSMakeRect(0,0, printInfo.paperSize.width, printInfo.paperSize.height);
// Print it out
[printOperation runOperationModalForWindow:self.window delegate:self didRunSelector:#selector(printOperationDidRun:success:contextInfo:) contextInfo:nil];
You also need to have a handler method to catch the results:
- (void)printOperationDidRun:(id)operation success:(bool)success contextInfo:(nullable void *)contextInfo {
// Do something with your print
}
I've just made the switch from UIWebView to WKWebView.
I have an HTML file (loaded as string) which includes an HTML form with one input with type text, and a submit button.
Using UIWebView, the URL included the value of the input on the URL as a query parameter. (some-url.index?key=value)
When switched to WKWebView, the URL does not include the parameters as part of the URL.
In UIWebView I was getting the URL like so:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(#"Loading URL :%#",request.URL.absoluteString);
}
In WKWebView I'm getting the URL like so:
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
decisionHandler(WKNavigationActionPolicyAllow);
NSLog(#"Loading URL :%#", navigationAction.request.URL.absoluteString);
}
Thank you all for the help.
For other users that encounter this issue in the future:
After digging a bit, it seems that in WKWebView in order to have query parameters passed in the url, the url must have a valid scheme (http://, https://, etc..)
All other ways failed for me.
I have an UIWebView embeded in my app. What I am doing is, add an header (to be specific, authorization header), to all requests made from it.
This event is fired when a URL opens from an HTML iframe BUT it does not seem to be able to add header to that request.
To be sure, I added a log entry in this event and it does well but if I monitor HTTP traffic using burpsuite, it's not adding header.
Has anybody encountered such issue ever? Any possible workaround?
Below is my code, if it helps.
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
[(NSMutableURLRequest *)request addBasicAuth:self.accountObj.Username andPassword:self.accountObj.Password];
NSLog(#"!Request URL :%#",[request URL]);
NSLog(#"!Request Header :%#",[request allHTTPHeaderFields]);
return YES;
}
Instead of adding a header to your actual request, why dont you create a new one?
Cancel that one, and throw a new one
I am trying to create a simple ipad app with a UIWebview that displays a form that a customer can fill in.. what i want to do is restrict the app so that it only allows the user to navigate to certain addresses.. (i.e. either something that allows the user to go to a specific address.. OR something that checks for specific keywords and allows/blocks them as appropriate..)
Could someone please show me how its done..
NB: its basically a googledocs form and i dont want to let the user navigate away from it.. (the user could easily click away and go elsewhere)
Thank you for reading :)
In the class that is your UIWebViewDelegate you can use something like this:
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check for your own url. You can use more advanced checking techniques of course :)
NSRange range = [urlString rangeOfString:#"http://www.yourUrl.com"];
if (range.location != NSNotFound)
return YES;
else
return NO;
}
You can use the delegate method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
to determine whether the UIWebView can load a given web page. Although that would mean knowing exactly which pages are allowed (if there are many this might not be convenient).
Use UIWebViewDelegate method webView:shouldStartLoadWithRequest:navigationType:
Then check what is the URL that the UIWebView tires to load, and act consequently.
UIWebViewDelegate Reference
On OSX, I am using XCode to make a desktop app with a webview in it. The webview loads ok, and I can dynamically load content into it - but when I click on links inside the webview, they are not followed. They change color, but no new page is loaded. If I code my links with javascript like this - then they work.
link there
Is there an Objective-C one liner that allows links to be followed inside web-views?
Is there another issue I am not aware of here?
The links at the top of Gmail open in a new window. To make them work you have to implement at least the WebUIDelegate methods webView:createWebViewWithRequest: and webViewShow:. If you simply want to open all links in the same web view, you could return it from webView:createWebViewWithRequest: instead of creating a new one.
Turns out it was because I had code I copied form the web with some custom function to ignore WebPolicyDecisionListener...
Sorry for asking question without giving all the details - all this objective-c is new to me, I don't know which bits do what yet. I do some pointing and clicking, and then some coding - I don't know exactly how that all links up. With other languages, you have the whole program in one place - it takes a bit of a learning curve to get used to... but I digress.
I fixed by adding some comments - see code below...
- (void)webView:(WebView *)aWebView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id < WebPolicyDecisionListener >)listener
{
if ([self requestIsLinkClick:actionInformation]) {
if ([#"method" isEqual:[[request URL] scheme]]) {
SEL selector = NSSelectorFromString([[request URL] resourceSpecifier]);
if ([prototypeDelegate respondsToSelector:selector]) {
[prototypeDelegate performSelector:selector];
}
}
// [listener ignore];
} // else {
[listener use];
//}
}