que example swift facebook oauth swift2 sfsafariviewcontroller

swift - que - sfsafariviewcontroller example



SafariViewController: ¿Cómo obtener el token OAuth de la URL? (2)

Tratando de usar Facebook OAuth con el SafariViewController. Primero abro el authURL con SafariViewController, que si el usuario ha iniciado sesión en Facebook en Safari, los redireccionará y devolverá una URL de OAuth con el token para ese servicio específico, por ejemplo, Instagram.

RESPUESTA: https://www.facebook.com/connect/login_success.html#access_token=BLAHTOKENRESPONSE&expires_in=5114338

Cuando SafariViewController se haya redirigido, quiero capturar la URL de respuesta y almacenarla para poder agarrar el token. Aquí está mi código:

import SafariServices let kSafariViewControllerCloseNotification = "kSafariViewControllerCloseNotification" import UIKit // facebook OAuth URL for service let authURL = NSURL(string: "https://www.facebook.com/dialog/oauth?client_id=3627644767&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=basic_info,email,public_profile,user_about_me,user_activities,user_birthday,user_education_history,user_friends,user_interests,user_likes,user_location,user_photos,user_relationship_details&response_type=token") class ViewController: UIViewController, SFSafariViewControllerDelegate { var safariVC: SFSafariViewController? @IBOutlet weak var loginButton: UIButton! @IBAction func loginButtonTapped(sender: UIButton) { safariVC = SFSafariViewController(URL: authURL!) safariVC!.delegate = self self.presentViewController(safariVC!, animated: true, completion: nil) } override func viewDidLoad() { super.viewDidLoad() // not firing the safariLogin function below NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.safariLogin(_:)), name: kSafariViewControllerCloseNotification, object: nil) } func safariLogin(notification: NSNotification) { print("Safari Login call") // get the url form the auth callback let url = notification.object as! NSURL print(url) self.safariVC!.dismissViewControllerAnimated(true, completion: nil) } func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool { print("application call") // just making sure we send the notification when the URL is opened in SFSafariViewController if (sourceApplication == "com.application.SafariViewTest") { NSNotificationCenter.defaultCenter().postNotificationName(kSafariViewControllerCloseNotification, object: url) return true } return true } }

Abre el authURL y redirige a la URL de respuesta correcta, pero el observador no activa la función safariLogin para capturar la URL. Cualquier ayuda sería muy apreciada!

¡Muchas gracias!


iOS 12

iOS 12 Beta ya resta SFAuthenticationSession (ver más abajo) a favor de ASWebAuthenticationSession . Parece que se usa exactamente de la misma manera pero requiere el nuevo marco de AuthenticationServices .

iOS 11

iOS 11 introdujo SFAuthenticationSession que es mucho más fácil de manejar. Dada su naturaleza, esta API beta aún puede cambiar, pero ya hay un par de ejemplos ( 1 , 2 ) en Internet. Primero, necesita un controlador de finalización que se llame con el resultado de la solicitud de autenticación:

let completion : SFAuthenticationSession.CompletionHandler = { (callBack:URL?, error:Error?) in guard error == nil, let successURL = callBack else { return } let oauthToken = NSURLComponents(string: (successURL.absoluteString))?.queryItems?.filter({$0.name == "oauth_token"}).first // Do what you have to do... }

Luego simplemente crea una SFAuthenticationSession y lo inicia.

let authURL = "https://the.service.you/want/toAuthorizeWith?..." let scheme = "YOURSCHEME://" let authSession = SFAuthenticationSession(url: authURL, callbackURLScheme: scheme, completionHandler: completion) authSession.start()

iOS 10 y antes

Como algunos han señalado en los comentarios, la respuesta aceptada es incompleta y no funcionará por sí sola. Al pasear por el blog de Strawberry Code, puede encontrar un enlace al proyecto relacionado de GitHub . El README.MD ese proyecto explica una parte crucial de la configuración, a saber, agregar el URI de redireccionamiento a Info.plist . Así que todo se reduce así:

AppDelegate.swift

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { if let sourceApplication = options[.sourceApplication] { if (String(describing: sourceApplication) == "com.apple.SafariViewService") { NotificationCenter.default.post(name: Notification.Name("CallbackNotification"), object: url) return true } } return false }

ViewController.swift

Regístrese para recibir la notificación de llamar a su manejador en algún lugar sensible. Recomiendo no hacerlo en viewDidLoad() pero solo antes de que realmente estés presentando el SFSafariViewController .

NotificationCenter.default.addObserver(self, selector: #selector(safariLogin(_:)), name: Notification.Name("CallbackNotification"), object: nil) let safariVC = SFSafariViewController(URL: authURL) safariVC.delegate = self self.present(safariVC, animated: true, completion: nil)

Y luego quitar la observancia en el controlador:

@objc func safariLogin(_ notification : Notification) { NotificationCenter.default.removeObserver(self, name: Notification.Name("CallbackNotification"), object: nil) guard let url = notification.object as? URL else { return } // Parse url ... }

Recuerde que el usuario puede descartar el SFSafariViewController tocando el botón Done , así que asegúrese de adoptar el protocolo SFSafariViewControllerDelegate y elimine la observación de esta manera también:

func safariViewControllerDidFinish(_ controller: SFSafariViewController) { NotificationCenter.default.removeObserver(self, name: Notification.Name("CallbackNotification"), object: nil) }

Info.plist

Para que todo funcione, debe agregar su esquema de redirección de URI a Info.plist :

<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLName</key> <string>com.YOUR.BUNDLE.IDENTIFIER</string> <key>CFBundleURLSchemes</key> <array> <string>YOURSCHEME</string> </array> </dict> </array>

Por supuesto, YOURSCHEME tiene que coincidir con el esquema de URI de redireccionamiento que registró con el servicio web con el que está tratando de autorizar.


Lo averigué. Algunos de los métodos fueron pre iOS 9 y ahora están en desuso. También tuve la función de application en el ViewController que creé cuando debería haberse definido en el AppDelagate.swift . Por ejemplo

Añadido al final de AppDelegate.swift

func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool { print("app: /(app)") // print OAuth response URL print("url: /(url)") print("options: /(options)") if let sourceApplication = options["UIApplicationOpenURLOptionsSourceApplicationKey"] { if (String(sourceApplication) == "com.testApp.Incognito") { NSNotificationCenter.defaultCenter().postNotificationName(kSafariViewControllerCloseNotification, object: url) return true } } return true }

ViewController.swift

import SafariServices let kSafariViewControllerCloseNotification = "kSafariViewControllerCloseNotification" // facebook OAuth URL let authURL = NSURL(string: "https://www.facebook.com/dialog/oauth?client_id=3627644767&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=basic_info,email,public_profile,user_about_me,user_activities,user_birthday,user_education_history,user_friends,user_interests,user_likes,user_location,user_photos,user_relationship_details&response_type=token") class ViewController: UIViewController, SFSafariViewControllerDelegate { var safariVC: SFSafariViewController? @IBOutlet weak var loginButton: UIButton! @IBAction func loginButtonTapped(sender: AnyObject) { safariVC = SFSafariViewController(URL: authURL!) safariVC!.delegate = self self.presentViewController(safariVC!, animated: true, completion: nil) } override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.safariLogin(_:)), name: kSafariViewControllerCloseNotification, object: nil) } func safariLogin(notification: NSNotification) { // get the url from the auth callback let url = notification.object as! NSURL // Finally dismiss the Safari View Controller with: self.safariVC!.dismissViewControllerAnimated(true, completion: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func safariViewControllerDidFinish(controller: SFSafariViewController) { controller.dismissViewControllerAnimated(true) { () -> Void in print("You just dismissed the login view.") } } func safariViewController(controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) { print("didLoadSuccessfully: /(didLoadSuccessfully)") } }