I am using FlickrKit to attempt to login to my Flickr account for iOS (iPhone 5 simulator).
A) I specified the following for [[FlickrKit sharedFlickrKit] initializeWithAPIKey:]
- Flickr Key
- Flickr Secret
B) Then I called [[FlickrKit sharedFlickrKit] beginAuthWithCallbackURL:]
- where the callback URL is #"MyTestApp://auth".
- "MyTestApp" is defined under URL Types -> Item 0 -> URL Schemes -> Item 0.
C) Unfortunately after the logging in process, I get this error when I try to login using FlickrKit for iOS.
"An external application has asked to link to your Flickr account, but
failed to include all the necessary information. Specifically:"
(then I see a black bar, so I have no idea what the specific error is).
See screenshot below:
Any ideas?
Are you having to press the "OK, I'LL AUTHORIZE IT" button twice, with this black bar appearing the second time?
I believe what is happening is that you select the "authorize" button, which then sends the callback to your app, but when you select that button again Flickr thinks you are trying to use a duplicate auth token and wont allow it.
As a quick check, implement this method in your app delegate:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
Then throw an NSLog in there to see what the url is that is being passed. You'll probably get the data you were looking for.
I ran into this problem earlier today and was incredibly frustrated by it.
So for the latest version of swift I had to do the following:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
if (url.host == "oauth-callback") {
OAuth1Swift.handleOpenURL(url)
}
return true
}
Also my plist needed the following:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>my.bundle.id</string>
<string>oauth-swift</string>
</array>
<key>CFBundleURLName</key>
<string></string>
</dict>
</array>
But that is because I was using the following library: https://github.com/dongri/OAuthSwift
This is coming over a year late. I was able to make it work by making sure the all the info.plist was well configured (with the right schemes. The previous dev removed it. But, it worked fine then.) and also, I override a function in my AppDelegate class. func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool and did this
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
print("DictionaryScheme: ", url.scheme!)
if url.scheme == "schemename" {
NotificationCenter.default.post(name: Notification.Name(rawValue: "UserAuthCallbackNotification"), object: url)
return true
}
return false
}
Related
I have used custom url scheme to open url in browser.I have one button in browser. how to know in app when button is clicked in browser.
below is my code for ref:
let customURL = URL(string: customURLScheme)!
if UIApplication.shared.canOpenURL(customURL) {
if #available(iOS 10.0, *) {
// UIApplication.shared.open(customURL)
UIApplication.shared.open(customURL, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(customURL)
}
}
and in Appdelegate
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return true
}
Can I use Universal links or deep linking?
Use Universal Links
When linking from the browser, you should most definitely be using Universal Links. If the user does not have the app installed and they click a URI scheme, the browser will show an error message. There are ways around this, like a javascript redirect, but these are very hacky and tend not to work all the time.
Detecting click in browser
The functions in your app delegate will not be called until the app has already been handed control from the browser, so it's impossible to detect the browser click from the app itself. You'll have to use some javascript click event handlers to detect that, but all of the handoff is handled at the OS level so you won't be able to control that.
Registering an open from a deep link
Once the deep link opens your app, it will call one of three functions.
From URI Scheme (myapp://):
application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
From Universal Link ONLY WHEN APP IS RUNNING IN BACKGROUND:
(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler
From Universal Link if app is closed
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This last one gets most people because they assume continueUserActivity should get called but it's really this function and they put the deep link url inside the launch options parameter.
Use Branch or a third party
Lastly, you could use Branch that leverages both URI and Universal Links whenever necessary and forwards all of your app delegate functions to one callback so you don't have to update routing logic in three different places.
In case of Universal Link
You should implement delegate method. Hope this snippet will be helpful.
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
NSURLComponents *URLComponents = [NSURLComponents componentsWithURL:userActivity.webpageURL resolvingAgainstBaseURL:YES];
[[UniversalLinksManagerLocator model] handleDeepLink:userActivity.webpageURL];
}
}
I'm using the FBSDKLoginManager to receive a token for later usage (FB posting) and end up in an endless loop after confirming the access.
When calling the FBSDKLoginManager(), the following popup appears (Sorry, it's in German language... This is the official Facebook popup, where the user can select whether he wants to logon manually or using the FB App).
Now the following error occurs:
If I'm using the second button (logon via phone number or E-Mail-Address), everything works fine. The function returns with a token and I can go on in my App.
The ERROR: If I'm using the first button (logon with Facebook-App), the Facebook App opens, I can set all the privacy settings in FB, and confirm. After confirming the access, the FB-App closes automatically and returns to the same popup-screen without any change. No action occurs after coming back to this screen...
I don't have any foggy idea where the problem is... There is no error message. Due to the fact that everything works fine when using the E-Mail Login, the problem must be in the return of the FB-App. The E-Mail Login works via Safari, in the error case there is the break to the FB-App.
let login: FBSDKLoginManager = FBSDKLoginManager()
login.logIn(withPublishPermissions: ["publish_actions"], from: self) { (result, error) in
if (error != nil) {
print("publish_actions: \(error!)")
} else if (result?.isCancelled)! {
print("publish_actions: Canceled")
} else if (result?.grantedPermissions.contains("publish_actions"))! {
//print("publish_actions: permissions granted: \(String(describing: result?.token.tokenString))")
UserDefaults.standard.set(result?.token.tokenString, forKey: "facebook_token")
}
Added Frameworks: Bolts / CoreKit / LoginKit
Development Environment: Xcode 9.2 / iPhone 6s with iOS 11.2 / latest Facebook App installed.
I solved by adding the follow missing call to FB SDK:
[[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
inside
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation method of the AppDelegate.
Check for following
in your info plist file
<key>FacebookAppID</key>
<string>fb_id_here</string> // in format 234234234
<key>FacebookDisplayName</key>
<string>display_name_here</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fbfb_id_here </string>. // in format fb234234234
</array>
</dict>
</array>
now inyour appdelegate
in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
if let scheme = url.scheme {
if scheme == "fb 234234234" { //the one you kept in your info plist file
//TODO: replace with real value
return SDKApplicationDelegate.shared.application(application, open: url, options: options)
}
}
return true
}
Do configure these and then dub your app, if the control folw comes in appdelegate function
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool
if it doesnt you have not configured facebook schemas correctly in info plist file
also
let fbManager = FBSDKLoginManager()
fbManager.logOut()
let readPermissions: [ReadPermission] = [.publicProfile, .email]
let sdkPermissions = readPermissions.map({ $0.permissionValue.name })
fbManager.logIn(withReadPermissions: sdkPermissions, from: nil) { (result, error) in
if let token = result?.token {
// your token here
}
else {
}
}
Thank you very much. This solved the problem.
1.) The plist file was already set up. I think otherwise the login with Safari wouldn't have worked.
2.) The App Delegate was the reason!!! Small adjustment:
SDKApplicationDelegate.shared didn't work. I should be as followed:
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
(As well in the added "application-open URL"-function.)
But now it works. Thanks a lot.
i think maybe i found an one issue, in my xcode, AppDelegate's
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool , xcode fix this function to private, and i fixed this function to internal, it will works~
I am able to handle the launchOptions value in the application method (since, obviously, the parameter gets passed to it). What I'm doing is basically receiving an image from a user who imported it by selecting my app in the Share menu:
It works fine if the App hasn't already been launched, but I don't see how I get the input parameters if the App is already running and the application method isn't called.
I tried to find a method that would help me like
applicationWillEnterForeGround(_ application: UIApplication, _ launchOptions: [UIApplicationLaunchOptionsKey: Any]?
but without any success.
I assume it's possible, since you can share images to WhatsApp or Facebook too, even when they've already been launched.
Can someone help me out?
Thanks,
Jan
You should implement the application:openURL:options: method as follows (Swift 2):
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
// Do your stuff and return true if you have handled the URL...
// Else
return false
}
Relevant tutorial in Ray Wenderlich
As of Swift 4.2 the signature is:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Do your stuff and return true if you have handled the URL...
// Else
return false
}
I think you're currently watching in the wrong direction. You should refer to Inter-App communication guide, provided by Apple. If generalise this, you simply need this method, that will handle URI link to your app.
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options;
I have an iOS app under development [Not yet launched]
And i want to get the following "Open" button visible on it while sharing the "from my app" via facebook messenger using FBSDKMessengerSharer:
Facebook SDK
What i have done is the following:
As per Facebook's guidelines for Optimized integration.
https://developers.facebook.com/docs/messenger/ios#optimized_integration
I have put .plist entries for facebook app ids, my own app id, URL schemes etc.
i confirm the when i type my scheme://, it open up my app.
Facebook developer console on developer.facebook.com has correct entries for the app/bundle.
I have added myself and another user as test users as per the guidelines and Facebook have clearly written this is testable without submitting the app.
And then i have the following pieces of code for sharing in the app:
func Share(){
let image : UIImage = UIImage(named: "Sample")!
let opts : FBSDKMessengerShareOptions = FBSDKMessengerShareOptions()
opts.contextOverride = cContext
FBSDKMessengerSharer.shareImage(image, withOptions: opts)
}
And the following for enabling optimized sharing in AppDelegate:
func application(app: UIApplication,
openURL url: NSURL,
options: [String : AnyObject]) -> Bool {
print("Called OpenURL")
let h = FBSDKMessengerURLHandler()
let a = "com.appcompany-new.name"
if h.canOpenURL(NSURL(string: "temp://abc.xyz"), sourceApplication: a) {
h.openURL(NSURL(string: "temp://abc.xyz"), sourceApplication: a)
}
return true
}
func messengerURLHandler(messengerURLHandler : FBSDKMessengerURLHandler,didHandleOpenFromComposerWithContext context : FBSDKMessengerURLHandlerOpenFromComposerContext) {
cContext = context
print("Called Open from composer")
}
I donot see any button, the Open, Install or Reply button even now. What am i missing?
I'm working on the Swift version of an app that handles custom URL schemes.
The method you need to implement changed in iOS 9.
The Objective-C version of the method works fine in an Objective-C app:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<NSString *,
id> *)options
{
//my code here
}
However, in my Swift app, the equivalent function:
func application(application: UIApplication,
openURL: NSURL,
options: [String : AnyObject]) -> Bool
{
//My code here
}
Is never called when I run the app on an iOS 9 device. When I invoke my custom URL scheme in Safari, I get prompted 'Open in "appname"?', and when I tap open, it brings my app back to the foreground, but the above method does not get called.
There must be some subtle mismatch in my method signature, but I can't see it. What am I doing wrong? I've tried various variations, none of which work.
My problem appears to have been a red herring caused by a corrupted project. I created a new project file and copied the same code in and in the new project, application:openURL:options: is called correctly.
This is a very strange problem. If I delete "AppDelegate.swift" in the malfunctioning project and replace it with an AppDelegate.m/AppDelegate.h, then the application:openURL:options: is called correctly in the Objective-C version.
My suspicion is that there is an intermittent bug in Xcode that causes some projects to fail to cal your app delegate's application:openURL:options: when the app delegate in Swift.
If you are having the same problem you may want to create a new project, set up your info.plist, and copy over the application:openURL:options: method to see if the new project calls your method.
Function signature (iOS9) is:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool
And if you want to test it working, just copy this into your app delegate:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool
{
print("Scheme: \(url.scheme)")
print("Host: \(url.host)")
print("Path: \(url.path)")
print("Query String: \(url.query)")
// DEBUG: get all key-value pairs in options also
for (key, value) in options {
print("Key: \(key), Value: \(value)")
}
return true
}
Also remember to add the "scheme" (app name) to your info.plist file. Call from Safari on the phone like this
scheme://host/path?query