Tweetbot URL Scheme not opening user - ios

I've been trying to get Tweetbot to open a user account when a table row is tapped by the user. However, although Tweetbot opens, it doesn't show the user account. I've been using the Tweetbot URL Scheme page as a reference.
Below is my code:
if (indexPath.row == 1) {
// Removed the actual username
self.destViewURL = #"http://twitter.com/dummyusername";
self.destViewTitle = #"Twitter";
// URLs to try
NSURL *twitterURL = [NSURL URLWithString:#"twitter://user?screen_name= dummyusername"];
NSURL *tweetbotURL = [NSURL URLWithString:#"tweetbot://dummyusername/timeline"];
// Check if Tweetbot is available to open it
if ([[UIApplication sharedApplication] canOpenURL:tweetbotURL]) {
[[UIApplication sharedApplication] openURL:tweetbotURL];
}
else {
// Check if Twitter is available to open it
if ([[UIApplication sharedApplication] canOpenURL:twitterURL]) {
[[UIApplication sharedApplication] openURL:twitterURL];
}
// Otherwise open it in the web view
else {
[self performSegueWithIdentifier:#"showWebView" sender:nil];
}

The URL schemes page for Tweetbot 3 is here
All of the supported URLs begin with tweetbot://<screenname>, which suggests that you need to know the user's existing twitter screen name to link to a profile.
However, my testing has shown that you could link directly to a profile by using the same value for tweetbot://<screenname>/user_profile/<profile_screenname>
Swift e.g.
/* Tweetbot app precedence */
if let tweetbotURL = NSURL(string: "tweetbot://dummyusername/user_profile/dummyusername") {
if UIApplication.sharedApplication().canOpenURL(tweetbotURL) {
UIApplication.sharedApplication().openURL(tweetbotURL)
return
}
}
/* Twitter app fallback */
if let twitterURL = NSURL(string: "twitter:///user?screen_name= dummyusername") {
if UIApplication.sharedApplication().canOpenURL(twitterURL) {
UIApplication.sharedApplication().openURL(twitterURL)
return
}
}
/* Safari fallback */
if let webURL = NSURL(string: "http://www.twitter.com/dummyusername") {
if UIApplication.sharedApplication().canOpenURL(webURL) {
UIApplication.sharedApplication().openURL(webURL)
}
}

Related

Obj-C decidePolicyForNavigationAction not being triggered

decidePolicyForNavigationAction is not being triggered when the webview loads a new page. It works when everything is initially loaded but then never gets triggered after that.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSLog(#"decidePolicyForNavigationActionnavigationAction.request.URL.absoluteString:%#|", navigationAction.request.URL.absoluteString);
if (kTestLocalHTML == 1) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
NSURL *url = navigationAction.request.URL;
if (url != nil) {
//
// TODO: Trim the url string below as well?
// No, because this is being trimmed already in the AppManager methods related to web view URL
//
NSString *urlString = url.absoluteString;
WKNavigationType navType = navigationAction.navigationType;
//
// Display the club mobile native login page and log the user out
// if the webview is about to load the blazor login page URL
//
if ([urlString isEqualToString:[AppManager getMobileLoginUrl]]) {
self.appManager.userLoginDetails = nil;
[self displayLoginPage];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
//
// Check if link is tapped from webview and if URL string contains the
// prepended identifier within the JavaScript injection which can be found in
// "webViewDidFinishLoad" delegate method of webview
//
if (navType == WKNavigationTypeLinkActivated && [AppManager isWebViewURL_containsTargetBlank:urlString]) {
//
// Make sure to ignore the prepended identifier on the URL string
// before opening it on an external browser
//
NSInteger targetBlankIdentifierLength = kIdentifier_TargetBlank.length;
NSURL *url = [NSURL URLWithString:[urlString substringFromIndex:targetBlankIdentifierLength]];
[[UIApplication sharedApplication] openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
//
// Check if url has custom scheme other than "http" & "https" (If is either one of the tags for Telephone "tel", Mail "mailto", SMS "sms", Web Calendar "webcal", etc.)
//
// Solution Reference: https://stackoverflow.com/questions/47040471/wkwebview-not-opening-custom-url-scheme-js-opens-custom-scheme-link-in-new-wind
// - (Answers of both "hstdt" & "mattblessed")
//
// NOTE: It seems loading telephone and mail links do not work when testing on an iOS simulator.
//
NSString *urlScheme = url.scheme;
BOOL isCustomURLscheme = ( ! [urlScheme isEqualToString:#"http"] && ! [urlScheme isEqualToString:#"https"]);
if (isCustomURLscheme) {
NSURL *url = [NSURL URLWithString:urlString];
[[UIApplication sharedApplication] openURL:url];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
//
// Get reference to the current URL being requested so that if there
// will be failure in loading the webview, we have a reference to that URL.
//
self.currentUrlRequest = navigationAction.request;
// Check if web view URL contains a calendar file to download
if ([AppManager isWebViewURL_containsCalendarDownload:urlString]) {
//
// Download and process calendar file either from Events or Dining module
// and display "New Event" page where user can view its details, edit and save to device calendar
//
[self processCalendarFileAndDisplayEventPageWithURLrequest:self.currentUrlRequest];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
// Check if web view URL contains a PDF file attachment to download
else if ([AppManager isWebViewURL_containsPDFAttachmentDownload:urlString]) {
// Display document viewer page and pass few parameters for page customization (initial URL to load, navigation bar title)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:kStoryboardName bundle:nil];
UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:kStoryboardID_OverlayBrowserNavigationController];
OverlayBrowserViewController *vcOverlay = (OverlayBrowserViewController *)[navigationController topViewController];
vcOverlay.initialURLtoLoad = urlString;
vcOverlay.navigationBarTitle = [self getPDFDocumentNameFromURLString:urlString];
[self presentViewController:navigationController animated:YES completion:nil];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
decisionHandler(WKNavigationActionPolicyAllow);
}
This function is supposed to trigger and detect if the webview is loading the web login page and if that is the case it will logout the user and instead show the apps native login page. However the function is never triggered after the main screen is loaded initially.
"Are you sure the web page is actually performing a redirect and is not a SPA like Angular which may not be updating the URL? Also how are you setting self.wkWebMain? – RunLoop"
Thanks for this, you were correct and the webpage was acting as an SPA which was the reason the function would call at first on the initial load but not after.

Start navigation automatically with Google Maps and Apple Maps URL Schemes

Is there a way to start navigation automatically when launching Google Maps or Apple Maps with a URL Scheme on iOS?
I see several optional parameters for both but none to start navigation without user input.
Here's how I did it for your reference, but for apple, I haven't found a way to start the navigation through url scheme.
+ (void)navigateToLocation:(CLLocation*)_navLocation {
if ([[UIApplication sharedApplication] canOpenURL:
[NSURL URLWithString:#"comgooglemaps://"]]) {
NSString *string = [NSString stringWithFormat:#"comgooglemaps://?daddr=%f,%f&directionsmode=driving",_navLocation.coordinate.latitude,_navLocation.coordinate.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:string]];
} else {
NSString *string = [NSString stringWithFormat:#"http://maps.apple.com/?ll=%f,%f",_navLocation.coordinate.latitude,_navLocation.coordinate.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:string]];
}
}
You are correct, Google and Apple both require the user input - but only to hit the go button.
If you want to specify both the start and end location, use the following format:
Apple Maps:
http://maps.apple.com/maps?saddr=Current%20Location&daddr=<Your Location>
Google Maps:
comgooglemaps-x-callback://?saddr=&daddr=<Your Location>
Swift 3 helper class for starting Apple Maps or Google Maps navigation
struct LinksHelper {
static func startNavigation(coordinate: CLLocationCoordinate2D) {
struct Links {
static let kGoogleMapsSchema = "comgooglemaps://"
static let kGoogleMaps = "\(kGoogleMapsSchema)?daddr=%f,%f&directionsmode=driving"
static let kAppleMaps = "https://maps.apple.com/?saddr=Current Location&daddr=%f,%f&z=10&t=s"
}
var path: String!
if let googleMapsSchemaUrl = URL(string:Links.kGoogleMapsSchema), UIApplication.shared.canOpenURL(googleMapsSchemaUrl) {
path = Links.kGoogleMaps
} else {
path = Links.kAppleMaps
}
guard let str = String(format: path, coordinate.latitude, coordinate.longitude).addingPercentEncoding(
withAllowedCharacters: .urlQueryAllowed) else {
return
}
guard let url = URL(string: str) else {
return
}
UIApplication.shared.openURL(url)
}
}

"facebook login_sucess.html" not give access token through Graph API in iOS

I'm using Graph API in my iOS project. The problem is that after entering login credential in Facebook login webview it not give me access token with the redirect URI. I'm facing this problem with 2 days. Before 2 days my app working fine.
Code which called after login in Graph API is :
- (void)webViewDidFinishLoad:(UIWebView *)_webView {
/**
* Since there's some server side redirecting involved, this method/function will be called several times
* we're only interested when we see a url like: http://www.facebook.com/connect/login_success.html#access_token=..........
*/
//get the url string
NSString *url_string = [((_webView.request).URL) absoluteString];
//looking for "access_token="
NSRange access_token_range = [url_string rangeOfString:#"access_token="];
//looking for "error_reason=user_denied"
NSRange cancel_range = [url_string rangeOfString:#"error_reason=user_denied"];
//it exists? coolio, we have a token, now let's parse it out....
if (access_token_range.length > 0) {
//we want everything after the 'access_token=' thus the position where it starts + it's length
int from_index = access_token_range.location + access_token_range.length;
NSString *access_token = [url_string substringFromIndex:from_index];
//finally we have to url decode the access token
access_token = [access_token stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//remove everything '&' (inclusive) onward...
NSRange period_range = [access_token rangeOfString:#"&"];
//move beyond the .
access_token = [access_token substringToIndex:period_range.location];
//store our request token....
self.accessToken = access_token;
//remove our window
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window) {
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
}
[self.webView removeFromSuperview];
//tell our callback function that we're done logging in :)
if ( (callbackObject != nil) && (callbackSelector != nil) ) {
[callbackObject performSelector:callbackSelector];
}
//the user pressed cancel
} else if (cancel_range.length > 0) {
//remove our window
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window) {
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
}
[self.webView removeFromSuperview];
//tell our callback function that we're done logging in :)
if ( (callbackObject != nil) && (callbackSelector != nil) ) {
[callbackObject performSelector:callbackSelector];
}
}
[activityindicatorview stopAnimating];
}
Can anyone tell me what is the problem. Thanks in advance.
Facebook has changed his policies.
Item 4. Native iOS and Android apps must not use custom web views for
Login (Effective October 2, 2013)
You should use Facebook Official SDK.

How can I determine if a user has an iOS app installed?

How can I determine if the user of an iOS device has a specific application installed? If I know the name of the application can I use canOpenURL somehow?
If the application supports a custom url scheme you can check UIApplication -canOpenURL:. That will tell you only that an application able to open that url scheme is available, not necessarily which application that is. There's no publicly available mechanism to inspect what other apps a user has installed on their device.
If you control both apps you might also use a shared keychain or pasteboard to communicate between them in more detail.
You can check in this way as well:
BOOL temp = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"yourAppURL://"]];
       
if(!temp)
{
NSLog(#"INVALID URL"); //Or alert or anything you want to do here
}
for swift users
let urlPath: String = "fb://www.facebook.com"
let url: NSURL = NSURL(string: urlPath)!
let isInstalled = UIApplication.sharedApplication().canOpenURL(url)
if isInstalled {
print("Installed")
}else{
print("Not installed")
}
Facebook uses this https://github.com/facebook/facebook-ios-sdk/blob/master/FBSDKCoreKit/FBSDKCoreKit/Internal/FBSDKInternalUtility.m internally, you can do the same
#define FBSDK_CANOPENURL_FACEBOOK #"fbauth2"
+ (BOOL)isFacebookAppInstalled
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[FBSDKInternalUtility checkRegisteredCanOpenURLScheme:FBSDK_CANOPENURL_FACEBOOK];
});
NSURLComponents *components = [[NSURLComponents alloc] init];
components.scheme = FBSDK_CANOPENURL_FACEBOOK;
components.path = #"/";
return [[UIApplication sharedApplication]
canOpenURL:components.URL];
}
Code in Swift 3
static func isFacebookAppInstalled() -> Bool {
let schemes = ["fbauth2", "fbapi", "fb"]
let schemeUrls = schemes.flatMap({ URL(string: "\($0)://") })
return !schemeUrls.filter({ UIApplication.shared.canOpenURL($0) }).isEmpty
}

Make a phone call programmatically

How can I make a phone call programmatically on iPhone? I tried the following code but nothing happened:
NSString *phoneNumber = mymobileNO.titleLabel.text;
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
To go back to original app you can use telprompt:// instead of tel:// - The tell prompt will prompt the user first, but when the call is finished it will go back to your app:
NSString *phoneNumber = [#"telprompt://" stringByAppendingString:mymobileNO.titleLabel.text];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
Probably the mymobileNO.titleLabel.text value doesn't include the scheme //
Your code should look like this:
ObjectiveC
NSString *phoneNumber = [#"tel://" stringByAppendingString:mymobileNO.titleLabel.text];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber]];
Swift
if let url = URL(string: "tel://\(mymobileNO.titleLabel.text))") {
UIApplication.shared.open(url)
}
Merging the answers of #Cristian Radu and #Craig Mellon, and the comment from #joel.d, you should do:
NSURL *urlOption1 = [NSURL URLWithString:[#"telprompt://" stringByAppendingString:phone]];
NSURL *urlOption2 = [NSURL URLWithString:[#"tel://" stringByAppendingString:phone]];
NSURL *targetURL = nil;
if ([UIApplication.sharedApplication canOpenURL:urlOption1]) {
targetURL = urlOption1;
} else if ([UIApplication.sharedApplication canOpenURL:urlOption2]) {
targetURL = urlOption2;
}
if (targetURL) {
if (#available(iOS 10.0, *)) {
[UIApplication.sharedApplication openURL:targetURL options:#{} completionHandler:nil];
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[UIApplication.sharedApplication openURL:targetURL];
#pragma clang diagnostic pop
}
}
This will first try to use the "telprompt://" URL, and if that fails, it will use the "tel://" URL. If both fails, you're trying to place a phone call on an iPad or iPod Touch.
Swift Version :
let phone = mymobileNO.titleLabel.text
let phoneUrl = URL(string: "telprompt://\(phone)"
let phoneFallbackUrl = URL(string: "tel://\(phone)"
if(phoneUrl != nil && UIApplication.shared.canOpenUrl(phoneUrl!)) {
UIApplication.shared.open(phoneUrl!, options:[String:Any]()) { (success) in
if(!success) {
// Show an error message: Failed opening the url
}
}
} else if(phoneFallbackUrl != nil && UIApplication.shared.canOpenUrl(phoneFallbackUrl!)) {
UIApplication.shared.open(phoneFallbackUrl!, options:[String:Any]()) { (success) in
if(!success) {
// Show an error message: Failed opening the url
}
}
} else {
// Show an error message: Your device can not do phone calls.
}
The answers here are perfectly working. I am just converting Craig Mellon answer to Swift. If someone comes looking for swift answer, this will help them.
var phoneNumber: String = "telprompt://".stringByAppendingString(titleLabel.text!) // titleLabel.text has the phone number.
UIApplication.sharedApplication().openURL(NSURL(string:phoneNumber)!)
If you are using Xamarin to develop an iOS application, here is the C# equivalent to make a phone call within your application:
string phoneNumber = "1231231234";
NSUrl url = new NSUrl(string.Format(#"telprompt://{0}", phoneNumber));
UIApplication.SharedApplication.OpenUrl(url);
Swift 3
let phoneNumber: String = "tel://3124235234"
UIApplication.shared.openURL(URL(string: phoneNumber)!)
In Swift 3.0,
static func callToNumber(number:String) {
let phoneFallback = "telprompt://\(number)"
let fallbackURl = URL(string:phoneFallback)!
let phone = "tel://\(number)"
let url = URL(string:phone)!
let shared = UIApplication.shared
if(shared.canOpenURL(fallbackURl)){
shared.openURL(fallbackURl)
}else if (shared.canOpenURL(url)){
shared.openURL(url)
}else{
print("unable to open url for call")
}
}
The Java RoboVM equivalent:
public void dial(String number)
{
NSURL url = new NSURL("tel://" + number);
UIApplication.getSharedApplication().openURL(url);
}
Tried the Swift 3 option above, but it didnt work. I think you need the following if you are to run against iOS 10+ on Swift 3:
Swift 3 (iOS 10+):
let phoneNumber = mymobileNO.titleLabel.text
UIApplication.shared.open(URL(string: phoneNumber)!, options: [:], completionHandler: nil)
let phone = "tel://\("1234567890")";
let url:NSURL = NSURL(string:phone)!;
UIApplication.sharedApplication().openURL(url);
'openURL:' is deprecated: first deprecated in iOS 10.0 - Please use openURL:options:completionHandler: instead
in Objective-c iOS 10+ use :
NSString *phoneNumber = [#"tel://" stringByAppendingString:mymobileNO.titleLabel.text];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNumber] options:#{} completionHandler:nil];
Swift
if let url = NSURL(string: "tel://\(number)"),
UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
Use openurl.
For making a call in swift 5.1, just use the following code: (I have tested it in Xcode 11)
let phone = "1234567890"
if let callUrl = URL(string: "tel://\(phone)"), UIApplication.shared.canOpenURL(callUrl) {
UIApplication.shared.open(callUrl)
}
Edit: For Xcode 12.4, swift 5.3, just use the following:
UIApplication.shared.open(NSURL(string: "tel://555-123-1234")! as URL)
Make sure that you import UIKit, or it will say that it cannot find UIApplication in scope.

Resources