I placed a Facebook button in my iPhone app. How to open the iPhone's default browser when clicking on that button and loads the Facebook login page?
iOS 10 has introduced new method to open a URL, see below:
Swift 3:
let url = URL(string:"http://www.booleanbites.com")!
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(url)
}
Objective C:
NSURL *url = [NSURL URLWithString:#"http://www.booleanbites.com"];
if ([[UIApplication sharedApplication] respondsToSelector:#selector(openURL:options:completionHandler:)]) {
[[UIApplication sharedApplication] openURL:url options:#{} completionHandler:NULL];
}else{
// Fallback on earlier versions
[[UIApplication sharedApplication] openURL:url];
}
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://www.facebook.com"]];
When you open iPhone's default browser, your application gets to background - possibly terminated by iOS. Is that really what you want? User has no way to get back to your app.
Couple options to consider:
Integrate Facebook iOS library into your application. Lots of coding, since you need to write some UI code to support the integration. On the other hand it's your application and you have some control over what is going on and how to react to user actions
https://github.com/facebook/facebook-ios-sdk
Embed browser inside your application and "open the browser" within your app. Yet again you have some control over what's going on and what to do about it
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebView_Class/
The point is: it's YOUR application. Why would you force user to shutdown your app and start using something else without any way to get back?
Well, you know all the details and based on those you want the default browser. That's ok.
In Swift
UIApplication.sharedApplication().openURL(NSURL(string:"http://www.facebook.com")!)
In objective C
[[UIApplication sharedApplication] openURL:[NSURL
URLWithString:#"http://www.facebook.com"]];
Swift: iOS
var url:NSURL? = NSURL(string:webLink!)
UIApplication.sharedApplication().openURL(url!)
Swift 3:
let url = URL(string: "http://www.example.com")!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
If you want to add a completionHandler:
let url = URL(string: "http://www.example.com")!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: { (success) in
print("success!") // do what you want
})
}
OpenUrl is depricated, Use the following code.
NSURL *url = [NSURL URLWithString:#"https://google.com"];
[[UIApplication sharedApplication] openURL:url options:#{} completionHandler:nil];
Related
I have a location in my app. I want to make a button that sends this location to other apps like google maps or waze. How can I do that?
Create a ActionSheet like you have added in image.
And for all the applications in the list like GoogleMaps,Maps,Waze
do the following on click..
BOOL canHandle = [[UIApplication sharedApplication] canOpenURL: [NSURL URLWithString:#"comgooglemaps:"]];
if (canHandle) {
UIApplication.shared.openURL(URL(string:
"comgooglemaps://?center=\(self.location.coordinate.latitude),\(self.location.coordinate.longitude)&zoom=14&views=traffic&q=\(self.location.coordinate.latitude),\(self.location.coordinate.longitude)")!
} else {
//show alert to install googlemaps
}
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)")
}
}
I have web content inside a UIWebView in my app. My goal is to have all links open normally inside the app, but any links starting with "http://maps", get opened in safari, so they can in turn be opened in the external iphone maps app. If you have a solution for this problem stop reading now, below I'm going to propose my solution. Currently all links are opened inside the app, so http://maps links open to m.google.com inside the app. The solution I'm thinking of involves this code which uses openURL to open all links in safari:
(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
\[\[UIApplication sharedApplication] openURL:request.URL];
return false;
}
return true;
}
Obviously the problem with this code is that all links are opened in safari, and I only want map links. Can you suggest a way to parse through links and only pass ones that start with http://maps through the function? Also a more simple question, how do I delegate UIWebView so I can run this code, and also is the viewcontroller.m the right place to put this code?
If you guys could suggest an entire function, including the openURL part above and the link parsing to make sure only maps links get passed through the function that would be awesome. Again, if you have another solution or workaround I would love to hear it. Thanks so much for your help, stackoverflow has been a lifesaver, I'm almost finished with my first project ever!
Try something like this:
-(BOOL)webView:(UIWebView *)inWeb
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)inType {
// let UIWebView deal with non-click requests
if (inType != UIWebViewNavigationTypeLinkClicked) {
return YES;
}
// URL starts with "http://maps"?
if ([[request.URL description] hasPrefix:#"http://maps"]) {
// open URL in Safari and return NO to prevent UIWebView from load it
[[UIApplication sharedApplication] openURL:[request URL]];
return NO;
}
// otherwise let UIWebView deal with the request
return YES;
}
NSString *linkPath = [[request url] path];
if ([linkPath hasPrefix:#""http://maps"]) {
//open in safari
}
else {
//do whatever
}
We have an iphone app that hosts a web browser control which points to a website whose sole purpose is to display information for the application. I would like to know if it is possible to have an anchor/button open Safari using HTML/JavaScript. If it is possible, how so?
Thanks...
You can setup a delegate for the UIWebview you are using. In this delegate, write something like this:
-(bool) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//You might need to set up an "interceptLinks"-Bool since you don't want to intercept the initial loading of the content
if (self.interceptLinks) {
NSURL *url = request.URL;
//This launches Safari with your URL
[[UIApplication sharedApplication] openURL:url];
return NO;
}
//No need to intercept the initial request to fill the WebView
else {
self.interceptLinks = TRUE;
return YES;
}
}
If you only want to intercept some links, you can parse the url and only open Safari if necessary.
Set the delegate property of your UIWebView object (what you call the 'web browser control') to an object of your own that implements the method "webView:shouldStartLoadWithRequest:navigationType:" of the UIWebViewDelegate protocol:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html%23//apple_ref/occ/intf/UIWebViewDelegate
You can then detect if you desired URL is being requested and in that case open it on an external Safari instance using UIApplication's openURL method.
You can use something like this:
myWebView.ShouldStartLoad += LoadHook;
[...]
bool LoadHook (UIWebView sender, NSUrlRequest request, UIWebViewNavigationType navType){
var requestString = request.Url.AbsoluteString;
// determine here if this is a url you want to open in Safari or not
if (WantToOpenInSafari (requestString)){
UIApplication.SharedApplication.OpenUrl (new NSUrl (requestString));
return true;
} else {
return false;
}
}
I can successfully initiate a phone call within my app using the following:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"tel://123456789"]];
However, is it possible to automatically return back to the app once the phone call has been terminated? It seems this was not possible under iPhone OS 3.0 but I am hoping it is now possible under iOS 4.2 with multitasking (I wasn't able to find any information on this question specific to iOS 4.2).
Thanks in advance for any assistance!
I know the question is very old, but currently you can do this (at least on iOS 5) by using telprompt://, like:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt://123456789"]];
iPhone will show alert view confirmation and when call ends, your app shows again, instead of iPhone's call app.
As far as I'm aware, because control is passed to the phone.app to make the call, once the call has ended, as far as iOS is concerned phone.app is the current app so that stays in the foreground.
There doesn't seem to be anything you can do about this at the moment. It might be worth putting in a feature request to allow for a "modal phone call" similar to MFMessageComposer that allows you to send emails/sms within your own app.
EDIT
You can follow the advice that Frin gives in the answer below as this contains more up to date information.
I believe the issue is that you're still making the sharedApplication call and as per the other thread, there is no need to add the web view as part of your hierarchy.
I took your code, modified it as below, and it works just fine:
NSString *phoneStr = [NSString stringWithFormat:#"tel:%#", phoneNumber];
NSURL *phoneURL = [[NSURL alloc] initWithString:phoneStr];
// The WebView needs to be retained otherwise it won't work.
if (!mCallWebview)
mCallWebview = [[UIWebView alloc] init];
[mCallWebview loadRequest:[NSURLRequest requestWithURL:phoneURL]];
Following the call your own app runs as before.
This is definitively possible since the introduction of iOS 4.0. The best way to handle this is to use a UIWebView, load the "tel:0123456" URL in the WebView without adding it to the view hierarchy. The iOS will automatically display an alert with the phone number and ask the user to confirm by pressing "Call".
Once the call is completed, your app will be brought back to foreground automatically. This is detailed in this other thread: Return to app behavior after phone call different in native code than UIWebView
I have given this answer in iPhone SDK: Launching an app after call ends I will also post my code here.. here you can make a call without closing you app..
-(IBAction) dialNumber:(id)sender{
NSString *aPhoneNo = [#"tel://" stringByAppendingString:[itsPhoneNoArray objectAtIndex:[sender tag]]] ; NSURL *url= [NSURL URLWithString:aPhoneNo];
NSURL *url= [NSURL URLWithString:aPhoneNo];
NSString *osVersion = [[UIDevice currentDevice] systemVersion];
if ([osVersion floatValue] >= 3.1) {
UIWebView *webview = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
[webview loadRequest:[NSURLRequest requestWithURL:url]];
webview.hidden = YES;
// Assume we are in a view controller and have access to self.view
[self.view addSubview:webview];
[webview release];
} else {
// On 3.0 and below, dial as usual
[[UIApplication sharedApplication] openURL: url];
}
}
With iOS 9.3.4, every technique that I try has control return to the calling app after the phone call. Has this behavior changed recently? This example is just a Swift and simplified version of https://github.com/jatraiz/RZTelpromptExample:
class ViewController: UIViewController {
let phoneNumber = "7204790465"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func callWithTelPushed(sender: AnyObject) {
if let url = NSURL(string: "tel:" + self.phoneNumber) {
UIApplication.sharedApplication().openURL(url)
}
}
#IBAction func callWithTelpromptPushed(sender: AnyObject) {
if let url = NSURL(string: "telprompt:" + self.phoneNumber) {
UIApplication.sharedApplication().openURL(url)
}
}
#IBAction func callWithRZTelpromptPushed(sender: AnyObject) {
RZTelprompt.callWithString(self.phoneNumber)
}
}