Sharing web page url to Facebook - facebook

I try to share a web page url with NSSharingServicePicker to Facebook, but it appears on my FB wall not as a web page url(with description and so on), but just like a link.
My code is very simple.
- (IBAction)share:(id)sender
{
NSURL* url = [NSURL URLWithString:#"http://itunes.apple.com/us/app/travel-route-planner/id504536611"];
NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:[NSArray arrayWithObjects:url, nil]];
sharingServicePicker.delegate = self;
[sharingServicePicker showRelativeToRect:[shareButton bounds]
ofView:shareButton
preferredEdge:NSMinYEdge];
}
I know it could be done.
Safari shares web pages the way i need.

I took a look at the source code on the website you're trying to share, and ran it through the Facebook Object Debugger. Facebook is pretty picky when it comes to the defined protocol, so I'd recommend changing your URL from http:// to https:// as the secure URL is what iTunes has decided to set as their og:url property. See here:

I found the answer on Apple Dev forums.
You need to add image to NSURL using following NSSharingServiceDelegate methods
- (NSRect) sharingService: (NSSharingService *) sharingService
sourceFrameOnScreenForShareItem: (id<NSPasteboardWriting>) item
{
if([item isKindOfClass: [NSURL class]])
{
//return a rect from where the image will fly
return NSZeroRect;
}
return NSZeroRect;
}
- (NSImage *) sharingService: (NSSharingService *) sharingService
transitionImageForShareItem: (id <NSPasteboardWriting>) item
contentRect: (NSRect *) contentRect
{
if([item isKindOfClass: [NSURL class]])
{
return [NSImage imageNamed:#"image.png"];
}
return nil;
}
don't forget to set the delegate for your NSSharingService
- (id < NSSharingServiceDelegate >)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker delegateForSharingService:(NSSharingService *)sharingService
{
return self;
}

Related

Missing image when shared using UIActivityViewController

We've the following method to share content in the application. For each content we share:
Text
Image
URL
+ (void) generalShare:(NSString *) text withEntity:(SMEntity *) theEntity onView:(UIViewController*) theViewController withImage:(UIImage *) image completion:(void (^)(void))completion
{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:templateURL
, [SMSocialManager getAction:theEntity]
, [theEntity getId]]];
NSArray *sharingItems = #[text, url, image];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
[activityController setValue:text forKey:#"subject"];
[UINavigationBar appearance].barStyle = UIBarStyleBlack;
[UINavigationBar appearance].translucent = NO;
[UINavigationBar appearance].barTintColor = UIColorFromRGB(SMPrimaryColor);
[theViewController presentViewController:activityController animated:YES completion:^{
return completion();
}];
}
Until a few time it works perfectly, a few time ago the text was missing when you try to share in facebook (based on the new policy) but just a days ago the image, is also missing, and just the URL is included.
Any suggestions?
I could figure out generating an ad-hoc solution for each destination social network, but find a way to solve with an standard solution could be better approach.
Thank you!
It seams facebook and instagram removed the caption from the integration, and I don't know why but with facebook also the image is not working anymore.

UIWebView shouldStartLoadWithRequest only fires once when calling a modal view from inside

I have part of my app written in JS and running inside of a WebView. I'm using the UIWebView shouldStartLoadWithRequest method to capture http requests as a means of communicating between JS and obj-c. This works great until I attempt to load a Modal View Controller over my webview from inside the shouldStartLoadWithRequest method. Once this happens, shouldStartLoadWithRequest is no longer called. Sometimes I need to dismiss this modal view controller and go back to the webview and do some things and then re-present the modal controller. The modal controller comes up the first time just fine, then I dismiss it and attempt to present it again by navigating to a URL from javascript and it no longer will present itself. NSLogs inside shouldStartLoadWithRequest are never run.
In my javascript I do something like this:
window.location='myapp:whateverMethod';
objective c code looks like this:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
NSLog(#"REQUEST URL: %#", requestString);
if([requestString hasPrefix:#"myapp:"]) {
NSArray *components = [requestString componentsSeparatedByString:#":"];
NSString *function = [components objectAtIndex:1];
if([self respondsToSelector:NSSelectorFromString(function)]) {
[self performSelector:NSSelectorFromString(function)];
}
return NO;
}
return YES;
}
-(void) whateverMethod {
NSLog(#"whateverMethod called!");
// This is a quick way to grab my view controller from the storyboard, so assume it exists
UIViewController *splash = [self.storyboard instantiateViewControllerWithIdentifier:#"splashViewController"];
[self presentModalViewController:splash animated:NO];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
[self dismissModalViewController:splash animated:NO];
});
}
At this point my webview is still visible. I navigate from page to page in my webapp and all javascript works great in it but the "shouldStartLoadWithRequest" delegate method of the webview no longer is called. I cannot figure out why. Does anyone have any ideas?
I noticed that Cordova doesn't set the window.location property. Instead it has two options: it either creates an iframe and sets the src of the iframe to that url, or it creates an XMLHttpRequest object e.g. in the iOSExec() function:
if (bridgeMode) {
execXhr = execXhr || new XMLHttpRequest();
// Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
// For some reason it still doesn't work though...
execXhr.open('HEAD', "file:///!gap_exec", true);
execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
if (shouldBundleCommandJson()) {
execXhr.setRequestHeader('cmds', nativecomm());
}
execXhr.send(null);
} else {
execIframe = execIframe || createExecIframe();
execIframe.src = "gap://ready";
}
That being said, it may be beneficial to use something like Cordova instead of trying to roll it yourself (even if it's just embedding their view controller), since they handle a lot of the headaches that come up with webview delegates.
I've just had the same problem, but related to using a href="#" anchor.
This Stack Overflow answer sorted it
There are more answers on that thread that deal with widow.location, so you may have luck with them.
Checked out Cordova and they have their own queuing system, not really a help. But...
Disobedient Media's answer gave me an idea. Instead of window.location, why not try window.location.hash.
Now some JS code for logging is:
function sendMsgToNative(msg)
{
window.location.hash = '~cmd~' + msg;
}
console.log = function (msg) { sendMsgToNative('log~js ' + msg); };
and the Objective-C code is:
NSString *req = [request.URL absoluteString];
NSArray *components = [req componentsSeparatedByString:#"~"];
// Check for your protocol
if ([components count] > 1 && [(NSString *)[components objectAtIndex:1] isEqualToString:#"cmd"])
{
// Look for specific actions
if ([(NSString *)[components objectAtIndex:2] isEqualToString:#"log"])
{
NSString *logStr = [(NSString *)[components objectAtIndex:3] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
LOGI("%#", logStr);
}
}
You get the full URL including 'http:...' so I chose tilde instead of colon, and incremented the indices.
Now you can log all willy-nilly and send whatever amount of commands you want and they will all get through :-)
I (embarrassingly) spent a couple of hours working on this today, and realised that in my viewDidDisappear: I was setting the UIWebViewDelegate to nil!
All I needed to do to fix was once the modal was dismissed, re-set the UIWebViewDelegate and everything worked again.

How can I get UIWebView to open Facebook login page in response to the OAuth request on iOS 5 and iOS 6?

We have:
(1) Facebook API-based web application with Facebook OAuth functionality (“the FB web app”)
(2) UIWebView-based browser on iPad (“the Browser”)
Our objective is to open the Facebook Login page to sign in to the FB web app (1) inside the UIWebView-based Browser (2) on iPad.
There is a somewhat similar issue here:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found
However, the issue of that question happens after the user enters login and password into the Facebook form. Our problem is that we cannot get the Facebook login form displayed in the first place. Changing the app type to from “Web” to “Native/Desktop”, as suggested in that question, did not help.
Steps:
1. Open our web page (simple HTML page) with this UIWebView Browser
2. Click on “FB web app” launch button on this page
3. OnClick JavaScript tries to initiate OAuth, which should open the login screen of Facebook to sign in to the FB web app
Current outcome (issue):
On iOS 5.+ and iOS 6.+ devices
- Our web page stays unchanged
- Facebook login page is NOT shown (our web page is still displayed)
On iOS 4.3 (works as expected):
- the Facebook login page is opened in the same UIWebView object of the Browser (replaces our web page)
Expected outcome:
- Facebook login page is displayed, and the user can enter Facebook login & password
- Works on iOS 5.+ and iOS 6.+ if launched in Safari browser on iPad. Facebook login page is opened in a separate tab (in contrast, there are no separate tabs in UIWebView)
Question: How can I get UIWebView to open Facebook login page in response to the OAuth request on iOS 5+ and iOS 6+?
More technical details:
We log different NSURLRequest fields from within
-(BOOL)webView(UIWebView*)webView shouldStartLoadWithRequest(NSURLREquest*)request navigationType:…
And we notice some difference in logs for “correct” and “incorrect” behaviors. Here how execution flows look for me:
Firstly, I press “FB Web App” launch button to initiate OAuth, then some cases go
iOS 4.3, “correct”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
request to m.facebook.com/login.php?....
--here facebook login appears
iOS 5.0, “incorrect1”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
request to m.facebook.com/login.php?...
Then it may be
--a lot of m.facebook.com/login.php?...with next… in parameters
followed by sqlite error
--right now I see “Sorry, something went wrong” page from facebook (it’s a first time at all I encounter it)
iOS 6.0 “incorrect2”
request to www.facebook.com/dialog/oauth?...
request to fbwebapp.com
-(void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error is invoked with error code -999
You can see that behavior definitely depends on iOS version. But common case is that error happens on the step of obtaining m.facebook.com/login.php.. URL. But that’s all that we can detect.
We’re banging our heads against that wall for the whole day looking for solutions. Hopelessly.
Can you help us get the Facebook Login page opened in the UIWebView in response to OAuth?
just use : this code
if (![FBSDKAccessToken currentAccessToken])
{
FBSDKLoginManager *manager = [[FBSDKLoginManager alloc]init];
manager.loginBehavior = FBSDKLoginBehaviorWeb;
[manager logInWithReadPermissions:#[#"public_profile", #"email", #"user_friends"] handler:
^(FBSDKLoginManagerLoginResult *result, NSError *error) {
NSLog(#"result.token: %#",result.token.tokenString);
NSLog(#"%#",result.token.userID);
NSLog(#"%hhd",result.isCancelled);
}];
}
// here manager.loginBehavior = FBSDKLoginBehaviorWeb; is all you need to open facebook in UIWebview
Did it!
It kinda of a hack, but the js facebook sdk login on UiWebView at iOS 6 finally works.
How it could be done? It is a pure JS + Facebook JS SDK + UIWebView Delegate handling functions solution.
JS - First step)
a login button (to connect with facebook) calls this function example, that will trigger Face JS login/oauth dialogs:
function loginWithFacebookClick(){
FB.login(function(response){
//normal browsers callback
});
}
JS - Second step)
add a authResponseChange listener every time user loads the webpage ( after FB.init() ) to catch user's connected status:
FB.Event.subscribe('auth.authResponse.Change', function(response){
//UIWebView login 'callback' handler
var auth = response.authResponse;
if(auth.status == 'connected'){
//user is connected with facebook! just log him at your webapp
}
});
AND with app's UIWebView delegate functions you can handler facebook oauth responses
Objective C - Third step)
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = [[request URL] absoluteString];
//when user status == connected (has a access_token at facebook oauth response)
if([url hasPrefix:#"https://m.facebook.com/dialog/oauth"] && [url rangeOfString:#"access_token="].location != NSNotFound)
{
[self backToLastPage];
return NO;
}
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *url = [[webView.request URL] absoluteString];
if([url hasPrefix:#"https://m.facebook.com/dialog/oauth"])
{
NSString *bodyHTML = [webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
//Facebook oauth response dead end: is a blank body and a head with a script that does
//nothing. But if you got back to your last page, the handler of authResponseChange
//will catch a connected status if user did his login and auth app
if([bodyHTML isEqualToString:#""])
{
[self backToLastPage];
}
}
}
So, when 'redirect' user to the last loaded page, the second step is going to handler user action at facebook login dialogs.
If I got too fast with this answer, please ask me!
Hope it helps.
In case anyone is googling, here's what worked for me:
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)inType {
if ([request.URL.absoluteString containsString:#"m.facebook.com"]) {
if ([request.URL.absoluteString rangeOfString:#"back"].location == 0) {
[self.popUp removeFromSuperview];
self.popUp = nil;
return NO;
}
if (self.popUp) {
return YES;
}
UIWebView *wv = [self popUpWebView];
[wv loadRequest:request];
return NO;
}
return YES;
}
- (UIWebView *) popUpWebView {
toolbar height
UIWebView *webView = [[UIWebView alloc]
initWithFrame:CGRectMake(0, 0, (float)self.view.bounds.size.width,
(float)self.view.bounds.size.height)];
webView.scalesPageToFit = YES;
webView.delegate = self;
// Add to windows array and make active window
self.popUp = webView;
[self.view addSubview:webView];
return webView;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (self.popUp) {
NSError *error = nil;
NSString *jsFromFile = #"window.close=function(){window.location.assign('back://' + window.location);};";
__unused NSString *jsOverrides = [webView
stringByEvaluatingJavaScriptFromString:jsFromFile];
JSContext *openerContext = [self.webView
valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
JSContext *popupContext = [webView
valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
popupContext[#"window"][#"opener"] = openerContext[#"window"];
}
//this is the secret sauce
if (webView == self.popUp
&& [webView.request.URL.absoluteString containsString:#"m.facebook.com"]
&& [[webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"] isEqualToString:#""]) {
[webView stringByEvaluatingJavaScriptFromString:#"eval(document.getElementsByTagName('script')[0].text)"];
}
}
I snagged a bunch of this implementation from here.
Depending on your web implementation, there will likely be one extra step. The Facebook script actually executes a window.close() then a window.open() then a window.close(). For me this was causing problems because on the web side, after this login is complete, my window (i.e. for the webView that I want the user to log in to) was getting a window.close() call, coming from the Facebook SDK. I'm assuming this is because the Facebook SDK expects that window.open() call to open a new window that it will close.
Since we didn't override the functionality of window.open(), calling window.open() won't do anything, and the Facebook SDK will attempt to close your window. This could cause all kind of problems, but for me since I'm using Parse, window.localStorage was set to null so I was getting all kinds of errors.
If something like this is happening for you, you have two options to fix it:
If you have control of the web code, and your down for a small hack, throw this in window.close=function(){}
If you don't have control of the web code, you can either add an override to window.close for the main webView like we did for the popUp webView, or override the window.open function to open another popUp (which is described in more detail here)
Use the FBDialog class to prompt the user to login. This uses a webview inside of the app, therefore on successful login the user will be logged in inside of any UIWebView:
NSString *kRedirectURL = #"fbconnect://success";
NSString *kSDK = #"ios" ;
NSString *kLogin = #"oauth";
NSString *kDialogBaseURL = #"https://m.facebook.com/dialog/";
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
AE_FACEBOOK_APPID, #"client_id",
#"user_agent", #"type",
kRedirectURL, #"redirect_uri",
#"touch", #"display",
kSDK, #"sdk",
nil];
NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin];
FBLoginDialog* loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL
loginParams:params
delegate:self];
[loginDialog show];
Then make your class adhere to the FBDialogDelegate protocol, and add this function to your class:
-(void)fbDialogLogin: (NSString *)token expirationDate:(NSDate *)expirationDate{
// Store the token and expiration date into the FB SDK
self.facebook.accessToken = token;
self.facebook.expirationDate = expirationDate;
// Then persist these so the SDK picks them up on next load
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.facebook.accessToken forKey:ACCESS_TOKEN_KEY];
[defaults setObject:self.facebook.expirationDate forKey:EXPIRATION_DATE_KEY];
[defaults synchronize];
}
HTH!
How to facebook login in UIWebView.
Objective-c
Use taylorstine's answer.
He saved my day. Thank you taylorstine
But I'm using Swift 3. so I just converted code below from taylorstine's answer.
Swift 3.
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let _ = request.url?.absoluteString.range(of: "m.facebook.com" ) {
if let _ = request.url?.absoluteString.range(of: "back"){
self.popUp?.removeFromSuperview()
self.popUp = nil
return false
}
if let _ = self.popUp {
return true
}
let wv = popUpWebView()
wv.loadRequest(request)
return false
}
return true
}
func popUpWebView() -> UIWebView {
let webView = UIWebView(frame: self.view.frame)
webView.delegate = self
self.popUp = webView
self.view.addSubview(webView)
return webView
}
func webViewDidFinishLoad(_ webView: UIWebView) {
if let _ = self.popUp {
let jsFromFile = "window.close=function(){window.location.assign('back://' + window.location);};"
let _ = webView.stringByEvaluatingJavaScript(from: jsFromFile)
let openerContext = self.webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
let popupContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext
popupContext.setObject("opener", forKeyedSubscript: "window" as (NSCopying & NSObjectProtocol)!)
popupContext.setObject(openerContext.objectForKeyedSubscript("window"), forKeyedSubscript: "opener" as (NSCopying & NSObjectProtocol)!)
}
if webView == self.popUp
&& (webView.request?.url?.absoluteString.range(of:"m.facebook.com") != nil)
&& webView.stringByEvaluatingJavaScript(from: "document.body.innerHTML") == "" {
webView.stringByEvaluatingJavaScript(from: "eval(document.getElementsByTagName('script')[0].text)")
}
}

Opening popup links in UIWebView, possible?

I have a UIWebView which I'm using as an embedded browser within my app.
I've noticed that links in webpages that open new windows are ignored without any call into my code.
I've tried breakpointing on
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
and then selecting a link that would open a popup window, and the breakpoint is never hit.
Is there anything I can do to intercept that selection of the popup link and get the URL and just load it normally?
I'm not interested in displaying a popup window in the app itself, I just want the URL of whatever is going to be loaded in the popup window to load in the main webview itself.
Is this possible?
Thanks!
I ran into this as well, and HTML rewriting was the best solution I could come up with. The biggest issue that I ran into with that approach is that the web browser is interactive for up to a couple of seconds until the webViewDidFinishLoad: method is called, so the links seem to be broken for a few seconds until they're rewritten.
There's three areas that I rewrote: links, form posts, and calls to window.open().
I used a similar approach to the first code snipped in Jasarian's answer to overwrite the target for links and forms by iterating over tags and forms. To override window.open, I used code similar to the following:
var oldWindowOpen = window.open;
window.open = function(url, sName, sFeatures, bReplace) {
oldWindowOpen(url, '_self');
};
So after a small amount of research, it's clear that the UIWebView class purposefully ignores links that will open in a new window (either by using the 'target' element on the a tag or using javascript in the onClick event).
The only solutions I have found are to manipulate the html of a page using javascript. While this works for some cases, it's not bulletproof. Here are some examples:
links = document.getElementsByTagName('a');
for (i=0; i<links.length; i++)
{
links[i].target='_self';
}
This will change all links that use the 'target' element to point at _self - instead of _blank or _new. This will probably work across the board and not present any problems.
The other snippet I found followed the same idea, but with the onClick event:
links = document.getElementsByTagName('a');
for (i=0; i<links.length; i++)
{
links[i].onclick='';
}
This one is just plain nasty. It'll only work if the link tag has it's href element correctly set, and only if the onclick event is used to open the new window (using window.open() or something similar). The reasons why it is nasty shouldn't need explaining, but one example would be if the onClick is used for anything other than opening a window - which is a very common case.
I guess one could go further with this and start doing some string matching with the onClick method, and check for window.open(), but again, this is really far from ideal.
Here's how I get twitter links to work (i.e. link to pages that try to open with new windows):
-(BOOL)webView:(UIWebView *)mainWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
//Allows for twitter links
[self.mainWebView loadRequest:request];
return NO;
}
return YES;
}
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
theConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = YES;
webView1 = [[WKWebView alloc] initWithFrame:self.webView.frame configuration:theConfiguration];
webView1.navigationDelegate = self;
webView1.UIDelegate = self;
[self.view addSubview:webView1];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
NSString *htmlString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"htmlString: %#", htmlString);
[webView1 loadHTMLString:htmlString baseURL:[NSURL URLWithString:#"your url"];
}];
[dataTask resume];

UIWebView loading parsed html string

i'm building an app that will display some newsletters to the users. the newsletters are displayed in a uiWebView. I'm reading the url's for the newsletters from an rss feed. I parse the xml, and in a table view i have all the newsletters. When a cell is clicked the uiWebView is pushed and the newsletter is loaded. Because the uiWebView doesn't open links that have target=_blank i need to replace the _blank from target with "". In an NSOperation i download the contents of the html and after the download is finished i replace the strings like this:
NSMutableString *page = [[[NSMutableString alloc] initWithData:pageData encoding:NSISOLatin1StringEncoding] autorelease]; [page replaceOccurrencesOfString:#"target=_blank" withString:#"target=""" options:0 range:NSMakeRange(0, [page length])];
after i do this i load the parsed string in the webView to display it to the user.
[myWebView loadHTMLString:page baseURL:[NSURL URLWithString:#""]];
while the NSOperation is downloading the contents of the page an HUD with a activity indicator and a label that says Loading is showed. When the download is finished the HUD is removed from the superview.
so far so good..but here come the questions. i used the NSOperation with the callback function because i wasn't able to determine the last call to webDidFinishLoading ( i read this UIWebView - How to identify the "last" webViewDidFinishLoad message? - this is a part of my problem but the response was to use some Apple private classes and that is a problem for me). so i'm doing this:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
NSLog(#"WebViewSouldStartWithRequest: %#", urlString);
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
if(![urlString isEqualToString:#"about:blank"])
{
NSLog(#"FeedViewController: startPageLoad");
activityHud = [[HUDView alloc] initWithFrame:CGRectMake(110, 100, 80, 80)];
[activityHud setText:#"Loading"];
[myWebView addSubview:activityHud];
NSLog(#"FeedViewController: pageUrl = %#", urlString);
[self resetWebView];
[urlLoader loadPageFromUrl:request.URL withCallbackTarget:self withCallbackSelector:#selector(endLoading:)];
}
}
return NO;
}
- (void) endLoading:(NSMutableString *)page { [self resetWebView]; NSLog(#"FeedViewController: endLoading"); [activityHud removeFromSuperview]; [myWebView loadHTMLString:page baseURL:[NSURL URLWithString:#""]]; }
after i touch a cell in the table view and the newsletter is showed it looks like it should, when i click a link in the newsletter, the page is loaded with the new request, parsed but visually is not looking as it should (i looked at the page after parsing in NSLog and it has the css styles and html tags, head, body opened and closed correctly) anyone had this problem with uiWebView, not showing webpages correctly?
i tried loading the page with - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType{ return YES; }
and in - (void)webViewDidFinishLoad:(UIWebView *)webview {} and in - webViewDiStartLoad
but the methods are being called for every item that is loaded in the webview so showing and hiding the HUD in those method is not a good solution.
I encountered some problems while using - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { ... return NO }
for example links that have paths like this /bilder-galerien to not work and in NSLog i receive this for them
Unknown scheme, doing nothing:
/bilder-galerien
but when i use
(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { return Yes } and didstartLoading and finishLoading the urls are loaded and i don't know why...
another problem are the special german characters..in my first load(after pressing a cell in the uiTableView) the page is parsed like it should be by the uiWebView but after i click a link and the corresponding request is loaded also the characters are not parsed correctly..
can anyone point me in the good direction? thank you in advance
UIWebView doesn't open target="_blank" links. Certain links don't fire UIWebViewNavigationTypeLinkClicked events. This happens when the link has the target="_blank" attribute.
To work around this problem i used the code below. It injects some javascript after the page load to remove the target attribute from all the links. After using this code i didn;t needed anymore to parse the html source and replace _blank with _self for example.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *js = #"\
var d = document.getElementsByTagName('a');\
for (var i = 0; i < d.length; i++) {\
if (d[i].getAttribute('target') == '_blank') {\
d[i].removeAttribute('target');\
}\
}\
";
[webView stringByEvaluatingJavaScriptFromString:js];
}
I like SorinA answer, we can make it even better by:
avoid obstructing javascript with var d
as we know we're running webkit engine we can use selectors:
...so in your UIWebViewDelegate protocol method invoke js code:
- (void) webViewDidFinishLoad: (UIWebView *) webView {
[webView stringByEvaluatingJavaScriptFromString: #"(function($){for(var i=0;i<$.length;++i){$[i].removeAttribute('target')}})(document.querySelectorAll('a[target=_blank]'))"];
}