I wanted to play a bit with SwiftUI and deep-linking, with passing data between two apps. But it seems not to work.
I build two small apps. First app with a textfield and a button, second app with a label and a button. When I press the button in the first app, it calls the second app via the given url scheme and vice versa.
First App looks like that...
struct ContentView: View {
#State var message: String = ""
var body: some View {
Group {
TextField("Enter message...", text: $message).textFieldStyle(.roundedBorder).padding()
Button(action: {
// go to second app
let application = UIApplication.shared
let secondAppPath = "second://\(self.message)"
let appUrl = URL(string: secondAppPath)!
application.open(appUrl, options: [ : ], completionHandler: nil)
}) { Text("Go to second app")}
.padding()
.border(Color.black, width: 2)
}
}
}
and the info.plist...
<key>LSApplicationQueriesSchemes</key>
<array>
<string>second</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>first</string>
</array>
</dict>
</array>
Second app info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>first</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>second</string>
</array>
</dict>
</array>
And when I press the button in the first app, this function in the second app should print the url like: "second://somethingfromthetextfield"
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
print(url)
return true
}
But its not doing it. The second app starts but didn't print anything. Now i wondering, am I doing something wrong? Is it working anyways on Xcode beta and SwiftUI or does it work differently?
Try to use the following method in the SceneDelegate:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
print("\(URLContexts.first!.url)")
}
I've gone through the Facebook "Quickstart" guide multiple times but can't seem to figure out what is causing this error. I'm trying to authenticate through FB using the following function call:
FBSDKLoginManager().logIn(withReadPermissions: ["public_profile", "email"], from: self) { (result, error) in
}
However, I'm getting the following error console output:
-canOpenURL: failed for URL: "fbauth2:/" - error: "The operation couldn’t be completed. (OSStatus error -10814.)"
Here are my AppDelegate methods:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance()!.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return FBSDKApplicationDelegate.sharedInstance()!.application(app, open: url, options: options)
}
I've added the following key/values to my Info.plist as told by the Quickstart guide:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb719997618357318</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>719997618357318</string>
<key>FacebookDisplayName</key>
<string>Test</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
#Kelvin Lua
You need to implement this method in AppDelegate
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool{
return FBSDKApplicationDelegate.sharedInstance().application (
application,
open: url as URL!,
sourceApplication: sourceApplication,
annotation: annotation)
}
This method will be called when user logged in form the Application. Just try it and let me know if it works or not else will try to help you out with something else.
This is a bug in the Facebook SDK due to the recent Xcode 10.1 update. The function signatures for UIApplicationDelegate have changed slightly:
// before
func application(_ app: UIApplication,
open url: URL,
options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
// before
func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
The key change is that the options dictionary is no longer keyed by String types. Instead, the keys are typed as UIApplication.OpenURLOptionsKey, which have the following definition:
// Inside definition of `UIApplication`
public struct OpenURLOptionsKey : Hashable, Equatable, RawRepresentable {
public init(rawValue: String)
}
The solution right now is to target a specific version of the Facebook SDK discussed by this thread: https://github.com/facebook/facebook-swift-sdk/issues/301.
I'have parent & child app in my device.I need to check and open parent app. In my app delegate(when app is launched), I am checking if the app is installed then open parent app otherwise go to app store.
I have tried below code to check if app is installed or not in your device.
I was created URL Types, as given-
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>Parent</string>
</array>
<key>CFBundleURLName</key>
<string>parentAppBundleid</string>
</dict>
</array>
I have written following code in didFinishLaunchingWithOptions-
func openGoYoApp() {
let parentapp = "Parent://"
let parentAppUrl = URL(string: parentapp)
if UIApplication.shared.canOpenURL(parentAppUrl! as URL)
{
UIApplication.shared.open(parentAppUrl!)
}
else {
//redirect to safari because the user doesn't have Instagram
print("App not installed")
UIApplication.shared.open(URL(string: "ituneLink")!)
}
}
In the given condition, if is returning true and UIApplication.shared.open(parentAppUrl!) is executed but its not opening my parent app.
The parent app's info plist should have something like this:
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLIconFile</key>
<string>temp</string>
<key>CFBundleURLName</key>
<string>com.parent-app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>parent</string>
</array>
</dict>
</array>
and in your parent app AppDelegate, you should handle it from here:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
print("open url: \(options)")
if let scheme = url.scheme, scheme == "parent" {
// handle url scheme
return true
}
return false
}
then in your child app:
// add this to button action or where ever you want it to trigger the 'open parent app scheme'
let urlString = "parent://info-to-pass-to-parent"
if let schemeURL = URL(string: urlString) {
if UIApplication.shared.canOpenURL(schemeURL) {
UIApplication.shared.open(schemeURL, options: [:], completionHandler: { (success) in
print("open success: \(success)")
})
}else{
//redirect to safari because the user doesn't have Instagram
print("App not installed")
UIApplication.shared.open(URL(string: "ituneLink")!)
}
}
I'm using facebook sign in api (SDK version Optional("4.1.0")) in Swift in my ios application. I placed the fb login button on my view Controller and when user clicks it - it opens facebook login panel in safari. When user puts the credentials and clicks log in - he sees the popup message with a question:
Open this page in APP_NAME?
Cancel OPEN
I want to get rid of that and open the app directly.
My code that handles the behavior of the button is like this:
class ViewController: UIViewController, FBSDKLoginButtonDelegate {
#IBOutlet weak var fbLoginButton: FBSDKLoginButton!
override func viewDidLoad() {
super.viewDidLoad()
fbLoginButton.readPermissions = ["public_profile", "email"]
fbLoginButton.layer.cornerRadius = 5
fbLoginButton.delegate = self
self.fbLoginButton.delegate = self
FBSDKProfile.enableUpdates(onAccessTokenChange: true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if (FBSDKAccessToken.current() != nil){
let tokenAsAParam = [
"access_token":FBSDKAccessToken.current().tokenString!
]
let loginManager = FBSDKLoginManager()
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
let data:[String:AnyObject] = result as! [String : AnyObject]
let defaults = UserDefaults.standard
let firstName:String = data["first_name"] as! String!
defaults.set(firstName, forKey: "facebook_display_name")
defaults.synchronize()
}else {
print("fb error")
}
})
Alamofire.request("\(serverURL)/auth/facebook", method: .post, parameters: tokenAsAParam)
.validate()
.responseJSON { response in
switch(response.result) {
case .success:
self.performSegue(withIdentifier: "openMainApp", sender: self)
break
case .failure:
print(response.result.error)
loginManager.logOut()
break
}
}
}
In the code above I'm fetching user's data from facebook and sends the token to my webservice to validate there whether the user is real or not and do some backend stuff.
My info.plist file is:
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>fbXXXXXXXXXX</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>2XXXXXXXXXXX</string>
<key>FacebookDisplayName</key>
<string>xxxxxxxx</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
Also, in my appDelegate I have the following methods:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
print("SDK version \(FBSDKSettings .sdkVersion())")
...
return true
}
func application(_ application: UIApplication,
open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation)
}
// [END openurl]
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String?, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
}
yet it still show this weird poppup instead of opening the app normally.
Does anyone know what I could do to fix this problem?
This is one of the better way to integration of FB for native iOS device, you get your solution from here :
http://www.theappguruz.com/blog/facebook-integration-using-swift
Also check the App Setting from the developer FB account
I guess if might be happening on iOS 9. You hace to use safariViewController to deal with this.
I guess this link might help you.
Get your Facebook login ready for iOS9 with SFSafariViewController
You can change it form Build Setting -> product name change it to your app display name.
By default it take target name.
I'm currently trying implement Facebook login using the 4.0 version of the SDK, this also happens with the 3.+ version. When I call logInWithReadPermissions (4.0 version) or openActiveSessionWithReadPermissions (3.+ version). The closure/block is called immediately with isCancelled (4.0 version) and ClosedFailedLogin (3.+ version) before the user can make a selection (cancel or ok). I thought it may be a problem with the URL Scheme in my plist settings but I've checked it over and over and everything seems to be right. Just wondering if anyone may have any ideas on solving this problem. My Bundle ID is right, single signin is on, native app is enabled, in the Facebook dev console. See some sample code and configurations below (4.0 version).
Login Call:
AppDelegate:
Plist:
With Facebook SDK version 4 I only had to add this to my application delegate on iOS 10 & Swift 3 to make the authentication work. Before that I also only had cancelled logins.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
I had the some problem but I found a workaround. You can set the login behaviour of the Login Manager to use the Facebook details on the phone. The default behaviour is FBSDKLoginBehaviorSystemNative and that tries to use the Facebook app first and then if its not there, it uses a web modal.
Instead of doing it that way and passing around urls that don't seem to work you can set the login behaviour as FBSDKLoginBehaviorSystemAccount.
Long story short, try:
let fbLoginManager = FBSDKLoginManager();
fbLoginManager.loginBehavior = FBSDKLoginBehaviorSystemAccount;
// call login method of choice here
I have same issue login method always return canacelled then I add below things in info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>akamaihd.net</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>facebook.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
<key>fbcdn.net</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
and in AppDelegate update didFinishLaunching method and add new method like below
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
{
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
Login method is given below:
#objc func loginButtonClicked() {
let loginManager = LoginManager()
loginManager.loginBehavior = .systemAccount
loginManager.logIn([ .publicProfile,.userFriends,.email ], viewController: self) { loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success(let grantedPermissions, let declinedPermissions, let accessToken):
print("Logged in!")
//Do further code...
}
}
}
it works for me in Swift 3.0 and SDK 4.17.0, I hope it works for you Thanks.
Did you add function to AppDelegate?
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
I had very similar problem while adding LoginButton in my app by following this tutorial → https://developers.facebook.com/docs/swift/login.
After clicking the Facebook Connect button and finishing the authorization, it always returns with status 'cancelled'.
I tried many solutions and finally the following worked:
In AppDelegate.swift, add the following 2 functions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return SDKApplicationDelegate.shared.application(application, open: url, options: options)
}
I got this issue too. It turned out that the app bundle id (in project configuration) mismatched with the app bundle id configured in the facebook app dashboard. After fixing the bundle id, the login worked just fine.
Hope this helps someone.
I found that the wrong AppDelegate method was being called. It was calling
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {...
instead of
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {...
So i had to add this to the first AppDelegate method (the one that was being called):
return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: "com.apple.mobilesafari", annotation: nil)
Note that i had to pass the safari bundle ID explicitly, otherwise the FB account delegate would get isCancelled = true
I have also faced this problem from past 1 month. I was integrating facebook login with firebase in ios 10 swift 3. Finally, I m able to successfully implement it. I corrected it by making following changes in AppDelegate file.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
#available(iOS 9.0, *)
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any])
-> Bool {
var shouldOpen :Bool = FBSDKApplicationDelegate.sharedInstance().application(application, open: url, sourceApplication:options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String!,annotation: options[UIApplicationOpenURLOptionsKey.annotation])
return shouldOpen
}
// for iOS below 9.0
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
var shouldOpen :Bool = FBSDKApplicationDelegate.sharedInstance().application(application,open: url as URL!,sourceApplication: sourceApplication,annotation: annotation)
return shouldOpen
}
I Hope it might help others
tested on ios 10.2 Emulator, iPhone 6 Plus running with 10.2
My issue was caused from me modally presenting a loading view controller, which I had being dismissed when the view disappeared. Since FBSDK calls the viewWillDisappear method when transitioning to Safari or the app, it was closing the view and the FB login screen. Same thing can happen if you present the login over a UIAlertController.
13 january 2019
Solved for me :
Delete Podfile.lock
Delete Pods folder
replace the facebook pods in your Podfile with this version of facebook
pod 'FBSDKCoreKit', '~> 4.38.0'
pod 'FBSDKLoginKit', '~> 4.38.0'
now please notice that if you have FacebookShareKit or anything else for facebook you have to change it to the same version you are using which is 4.38.0
run your terminal with pod install
open your project, go to Product > Clean Build Folder
run the app and try.
worked for me, if it does for you let everybody knows.
original post: https://github.com/facebookarchive/facebook-swift-sdk/issues/298#issuecomment-449626683
cheers.
UPDATE 2020-10-09:
FBSDK version 4.38.0 uses UIWebView, which is currently being discontinued by Apple and will be completely discontinued in December.
ORIGINAL:
I've been having the same problem and none of the other answers here worked for me. I went through the Facebook documentation carefully to make sure that I had everything correct, which I did. After some research, I discovered that this is a problem within the FBSDK itself starting with version 4.39.0. As it turned out, I had been using FBSDK version 4.40.0. The problem was completely resolved when I reverted to FBSDK version 4.38.0.
Here's a link which explains how to revert to FBSDK version 4.38.0 if you are using cocoapods
If however you are like me and prefer not to use cocoapods, here is a link to download FBSDK version 4.38.0
I had the same issue. Don't mix FBSDKApplicationDelegate and SDKApplicationDelegate
Solved it with the next Swift 4 code in AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
SDKApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let appId = SDKSettings.appId
if url.scheme != nil && url.scheme!.hasPrefix("fb\(appId)") && url.host == "authorize" { // facebook
return SDKApplicationDelegate.shared.application(app, open: url, options: options)
}
return false
}
In my case that using React-Native, FacebookSDK and Deeplink together, I need to have only one openUrl inside AppDelegate.m. More details explanation is in https://github.com/facebook/react-native-fbsdk/blob/master/README.md#32-ios-project