issues about Facebook Login
在学习The complete iOS 9 Developer Course - Build 18 Apps 中的Letture134-Facebook Login,需要整合(integrate)Parse+Facebook在iOS(Xcode)中,也就是用Facebook的账户登录制作的APP(copy Tinder),然后在Parse中记录账户的相关信息,而不用手动建立。登陆成功之后在后台返回账户的名称等public_profile。
此Lecture算是至今最难的一节,因为1、Parse的更新速度很快,已经开源且2017年不再提供服务2、Facebook Dev网站上写的与Parse整合的相关tutorial在不断更新,由于我看到这门课的时候,相关步骤已经与教学视频中变化很大。虽然Rob(teacher)提供了一个project,用此project可以完成该lecture,但是由于不是最新的,所以以后隐患大大。
用最新的Parse SDK+Facebook SDK+Swift+Xcode则问题重重。
好在经过摸索+参考其他classmate的question,最终解决了相关问题。现记录如下:
1、在info.plist中添加
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb---------------</string> <string>fbauth2</string> </array> </dict> </array> <key>FacebookAppID</key> <string>16----------------</string> <key>FacebookDisplayName</key> <string>Tinder2</string> <key>LSApplicationQueriesSchemes</key> <array> <string>fbapi</string> <string>fb-messenger-api</string> <string>fbauth</string> <string>fbauth2</string> <string>fbshareextension</string> </array>
如下图:
2、添加ParseStarterProject-Bridging-Header.h文件
新建一个文件也成,或者从Rob的project中复制也成,然后在Build Settings中,添加这个文件所在的目录。要注意,是这个文件的正确路径,可以先查看一下再添加。
然后修改文件如下:
// // ParseStarterProject-Bridging-Header.h // // Copyright 2011-present Parse Inc. All rights reserved. // #ifndef ParseStarterProject_Bridging_Header_h #define ParseStarterProject_Bridging_Header_h // If you are using Facebook, uncomment this line to get automatic import of the header inside your project. #import <ParseFacebookUtilsV4/PFFacebookUtils.h> #import <FBSDKCoreKit/FBSDKCorekit.h> #endif
这里要注意一定要选上那个 All 否则会有一些项出不来。然后,只要修改箭头指出的那两项就可以了。
3、添加Facebook的SDK和Parse出的整合Facebook的SDK,其中,Parse那个需要下两个东西,一个Project+一个SDK。拖进来文件时不选择必要时复制,然后在framework search path中添加目录即可,同时修改 Always Search User Paths 为Yes,如下图:
4、然后就是修改,AppDelegate.swift和ViewController.swift两个文件
//AppDelegate.swift中添加如下 import FBSDKCoreKit import ParseFacebookUtilsV4 PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions) // // //省略若干 // // // Swift 2.0 下面这些其实是取消注释 if #available(iOS 8.0, *) { let types: UIUserNotificationType = [.Alert, .Badge, .Sound] let settings = UIUserNotificationSettings(forTypes: types, categories: nil) application.registerUserNotificationSettings(settings) application.registerForRemoteNotifications() } else { let types: UIRemoteNotificationType = [.Alert, .Badge, .Sound] application.registerForRemoteNotificationTypes(types) } //这个是添加的 return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
//ViewController.swift import UIKit import Parse import FBSDKCoreKit import FBSDKLoginKit import ParseFacebookUtilsV4 class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let logInToFBButton = FBSDKLoginButton() logInToFBButton.center = self.view.center self.view.addSubview(logInToFBButton) let permissions = ["public_profile"] PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) { (user: PFUser?, error: NSError?) -> Void in print("123") if let error = error { print(error) } else { if let user = user { print(user) } } } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
然后就可以运行程序啦!
如果要搞清楚这里面的全部,还是很蛋疼的!
贴上Jonathan Hornby 和 Ng Yi Xian 两位童鞋的原回答
Got it working with all the latest SDKs! Read this before you start the lecture! Lecture 131 Connecting to Facebook Spent a whole day on this. Definitely the most challenging lecture thus far as a lot of moving parts have changed. This is a long note, but you will want to read it - covers a lot of the errors/ issues people have been struggling with. I used Parse v1.9.0 (9 Oct 15) , FBSDK v4.7 (7 Oct 15) and the production Xcode 7.0.1 - it all works! Here’s a run down of the issues I came across, and the solutions … 1st run of code to connect with Parse When Rob did this, he looked at the Parse website to confirm that a user & test object had been created. I got nothing. After checking code with the video, I decided to write some code to create a class (just like we did in a previous lecture) … and bingo - it worked … I got a user entry and new class. Further along in the video, Rob deletes some similar code he used to create his testobject in the viewDidLoad section of his ViewController. Rob - when you update the video, I’d recommend you reference this before running the app/ checking for your entries ;-) That was the easy bit, the rest was extremely difficult … but I learned a ton during the process. The 1st real challenge was when you started to reference code from either PFFacebookUtilsV4 or FBSDKCoreKit. Lot’s of red error messages. To cut a long story short, the Parse v1.9.0 downloads have a file missing: ParseStarterProject-Bridging-Header.h - without it, none of the import statements work The Parse AppDelegate tells you to follow Facebooks instructions for setting everything up on the FB site & populating your info.plist file … then uncomment a line in the missing header file. I created one from scratch: File > New > File > Header File and called it: ParseStarterProject-Bridging-Header.h Here are the contents I used: #ifndef ParseStarterProject_Bridging_Header_h #define ParseStarterProject_Bridging_Header_h #import <ParseFacebookUtilsV4/PFFacebookUtils.h> #import <FBSDKCoreKit/FBSDKCoreKit.h> #endif /* ParseStarterProject_Bridging_Header_h */ When you unpack the Parse v1.9.0 starter project, it doesn’t contain all the frameworks, so make sure you unpack the Parse Library zip and drag them into your project. Ditto for Facebook. In Robs video, he ran a guided install package. The latest version of the FBSDK is in a zip file - unpack following the instructions on the Facebook site. I associated everything with the project (Core, Login, Messenger etc) ... just to be sure! At this point, I thought everything would work - it didn’t. Still lots of red error messages. When I looked at the “issues navigator” it couldn’t find the FBSDK, ParseFacebookUtilsV4 or the header file I’d created. They were all in the navigation pane, so I was totally confused. The key/ solution was in the Targets Build Settings. Under Search Paths: Always Search User Paths - I set this to YES - default was NO Framework Search Paths - You should have a pointer to your project, but need to add one to your FBSDK location - Rob covered this in his video. If you followed the recommendations, it should be /Users/<your name>/Documents/FacebookSDK Swift Compiler - Code Generation: Install Objective-C Compatibility Header = YES Objective-C Bridging Header = ParseStarterProject/ParseStarterProject-Bridging-Header.h Took me a while to get the right syntax here - if you used the ParseStarterProject and put the header file in the same group as your AppDelegate and ViewController - the above should work for you. Info.plist file: Copy over the entries Facebook provide including the transport security entires. Under LSApplicationQueriesSchemes I added entries for: fbapi, fbauth, fbauth2, fb-messenger-api, fbshareextension ... just to be sure In the AppDelegate file: I put … import FBSDKCoreKit import ParseFacebookUtilsV4 at the top. The default PFFacebookUtils.initializeFacebook() line provided by parse for uncommenting didn’t work for me - kept showing an error, so I replaced with the code Rob used at 15:20 of the video: PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions) Uncommented the swift 2 code “let types & settings”, but left the if #available check and associated else stmts commented out (I set my target to ios9 - so the check wasn’t needed). Did the same as Rob at the end of the didFinsihLaunchWithOptions func: return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions) At the end of the file “MARK: Facebook SDK Integration” the return FBAppCall didn’t work for me, so I replaced with: func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool { return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation) } and added the func Rob used at the very end: func applicationDidBecomeActive(application: UIApplication) { FBSDKAppEvents.activateApp() } In the ViewController file: I put … import FBSDKCoreKit import FBSDKLoginKit import ParseFacebookUtilsV4 at the top. Robs code in the viewDidLoad func didn’t seem to work for me … at least, that’s what I thought when I ran the app … I was left with a white simulator screen and error messages in the output window: - canOpenURL: failed for URL: “fbauth2:/“ - error: “(null)” I spent a lot of time researching this and couldn’t find an answer anywhere. That said, a few people had commented that the error was just a message and not important … which got me thinking. I decided to install and run the scrumptious sample app from Parse - it worked and authenticated - just like in Robs video. I checked all the build and plist settings and nothing was different. Then I noticed that the output log had the same error messages re fbauth2. Perhaps it wasn’t a failure after all … Back on the Facebook dev site, they had some objective c code to test your integration. Part of it looked like the last bit of code in the AppDelegate file, but the code for the viewDidLoad func in the viewController used the FBSDKLoginButton. I took a guess at how to convert to swift and added the following to viewDidLoad: let logInToFbButton = FBSDKLoginButton() logInToFbButton.center = self.view.center self.view.addSubview(logInToFbButton) Ran the App, got the error message … but also a Facebook login button on my simulator. On selecting it, it took me to a login screen and after entering my username & pw it confirmed I was logged into Facebook. But before giving me access, it detected this was a new browser, so locked the account and asked me to enter a code they sent. The message popped up on my iPhone and took me to the Facebook code generator part of their app. Once I entered the code in simulator, it gave me the usual prompts for remembering the device. Success! Obviously, this didn't use Parse to authenticate, but I'm guessing that now I know the fbauth2 issue perhaps isn't a real issue the rest of the code will probably work - fingers crossed ;-) The key for me was “tinkering” … one thing at a time as an experiment - running the app then looking at the messages in the “issues navigator” to get some inspiration/ direction. There were times when I was tempted to scrap everything and use the old SDK, but I figured these kind of challenges will always occur when Apple, Parse, Facebook etc decide to change things … so a good exercise to figure out a solution. Hope it works for you (think I captured everything, but could have missed stuff)… and that the next challenge won’t be as tough ;-) ------Jonathan Hornby
Solution of solving -canOpenURL: failed for URL: "fbauth2:/" - error: "(null)" I've found a solution to solve this problem without downgrade the simulator to iOS 8.4. Here's the solution : 1) go to info.plist > open as source file 2) search CFBundleURLSchemes 3) under the <string>fb (ID) </string> paste this line : <string>fbauth2</string> 4) then add "Allow Arbitrary Loads" as YES in App Transport Security Settings. (add it if it's not there) 5) run it and see if it works It works for me and hope this help. :D Reference : http://stackoverflow.com/questions/21893447/facebook-sdk-app-not-registered-as-a-url-scheme ------Ng Yi Xian