iOS App 第三方登入:Facebook登入

Patty
14 min readAug 27, 2022

--

透過簡單的實作 — fb 登入、fb 登出以及顯示取得授權的公開資訊

outline: facebook login
大綱: facebook 登入

前置作業

使用 Facebook 登入的前置作業大同小異,單純作為紀錄的筆記,之後若有需要則可以快速參照。

【註冊為 facebook 的開發者且建立應用程式】

【Xcode 加入第三方套件】

【套件辨識碼】套件辨識碼即 App 的 Bundle ID

【啟用應用程式單一登入】

【設定專案 Info.plist】

開發者頁面

『第一種方式:以 key 值設定』

  • 新增 URL Type — URL Schemes:fb + App ID
fb 開發者頁面(上圖)、Xcode(下圖)
  • 新增 key
    FacebookAppID
    FacebookDisplayName
    FacebookClientToken
    LSApplicationQueriesSchemes → Array
    - fbapi
    - fb-messenger-share-api
Xcode

『第二種方式:以 XML 程式碼設定』

在專案的 Info.plist 選擇以原始碼開啟 ( 右鍵 > Open As > Source Code )

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fbAPP-ID</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>APP-ID</string>
<key>FacebookClientToken</key>
<string>CLIENT-TOKEN</string>
<key>FacebookDisplayName</key>
<string>APP-NAME</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-share-api</string>
</array>

打開 Keychain Sharing(鑰匙圈分享)

【設定 App — AppDelegate / SceneDelegate】

記得匯入框架 FacebookCore 方可使用 facebook 的設定,以及 App 啟動時完成 FB 的相關設定。
參考:facebook 說明文件
開始使用 Facebook iOS SDK-步驟 3:連結應用程式委派

AppDelegate.swift

// AppDelegate.swift
import UIKit
import FacebookCore
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
ApplicationDelegate.shared.application(app, open: url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String, annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)
}
}

SceneDelegate.swift

記得 import FacebookCore

func scene(_ scene:UIScene, openURLContexts URLContexts:Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
ApplicationDelegate.shared.application( UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation] )
}

內建 Facebook 登入的按鈕

使用內建的按鈕,加上登出設定

import FacebookLoginclass ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let loginButton = FBLoginButton()
loginButton.center = view.convert(CGPoint(x: view.center.x, y: 200), from: self.view)
view.addSubview(loginButton)
let manager = LoginManager()
manager.logOut()
}
}

一般自訂按鈕

【學習重點:檢查目前登入狀況】

  • AccessToken.current 登入用戶,nil 則為尚未取得授權
  • userID:使用者用戶,用於辨識目前登入用戶的 ID
if let token = AccessToken.current,
!token.isExpired {
print("\(token.userID) login")
} else {
print("not login")
}

【實作:開啟 App 後 — 判斷是否登入 facebook】

  • 狀況 1(已登入):進入下一個畫面
  • 狀況 2(尚未登入):停留在登入畫面,點選登入按鈕以進行登入,登入後再進入下一個畫面
if let accessToken = AccessToken.current,
!accessToken.isExpired {
print("\(accessToken.userID) login")
// 目前已經登入後要執行的程式碼...
guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "\(ProfileViewController.self)") as? ProfileViewController else { return }
self.present(controller, animated: false, completion: nil)
} else {
print("not login")
}

【學習重點:設定權限】

設定取得的權限包括公開的 profile 資訊和 email

let manager = LoginManager()
manager.logIn(permissions: [.publicProfile, .email], viewController: nil) { result in
switch result {
case .success(granted: let granted, declined: let declined, token: let token):
print("success")
}
case .cancelled:
print("cancelled")
case .failed(_):
print("failed")
}
}

【學習重點:如何取得授權的資訊】

方法一:登入成功後取得相關資訊

let request = GraphRequest(graphPath: "me", parameters: ["fields": "id, email, name"])
request.start { response, result, error in
if let result = result as? [String:String] {
print(result)
}
}

方法二:透過 Profile 呼叫 loadCurrentProfile 下載使用者的 profile 資訊『大頭照、公開的 email、name』

if let _ = AccessToken.current {
Profile.loadCurrentProfile { profile, error in
if let profile = profile,
let email = profile.email,
let name = profile.name {
print(name)
print(profile.imageURL(forMode: .square, size: CGSize(width: 300, height: 300)))
}
}
}

【實作:下一個畫面 - 顯示登入 facebook 取得授權公開資訊】

  • email
  • name
  • 大頭照

step 1. 畫面一:自訂登入按鈕

記得匯入框架 FacebookLogin

@IBAction func facebookLogIn(_ sender: UIButton) {
let manager = LoginManager()
manager.logIn(permissions: [.publicProfile, .email], viewController: nil) { result in
switch result {
case .success(granted: let granted, declined: let declined, token: let token):
print("success")
let request = GraphRequest(graphPath: "me", parameters: ["fields": "id, email, name"])
request.start { response, result, error in
if let result = result as? [String:String] {
print(result)
guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "\(ProfileViewController.self)") as? ProfileViewController else { return }
self.present(controller, animated: false, completion: nil)
}
}
case .cancelled:
print("cancelled")
case .failed(_):
print("failed")
}
}
}

step2. 畫面二:取得資訊、登出 facebook

import UIKit
import FacebookLogin
class ProfileViewController: UIViewController {@IBOutlet weak var emailLabel: UILabel! {
didSet {
emailLabel.numberOfLines = 0
}
}
@IBOutlet weak var IDLabel: UILabel!
@IBOutlet weak var photoImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
if let _ = AccessToken.current {
Profile.loadCurrentProfile { profile, error in
if let profile = profile,
let email = profile.email,
let name = profile.name {
print(name)
print(profile.imageURL(forMode: .square, size: CGSize(width: 300, height: 300)))
self.emailLabel.text = "email: \(email)"
self.IDLabel.text = "name: \(name)"
self.photoImageView.load(url: profile.imageURL(forMode: .square, size: CGSize(width: 300, height: 300))!)
}
}
}
}

@IBAction func facebookSignOut(_ sender: UIButton) {
let manager = LoginManager()
manager.logOut()
dismiss(animated: true, completion: nil)
}
}

extension UIImageView {
func load(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}

其他

【開放所有帳號可以登入】

尚未做其他設定之前,只有開發者可以登入

在開發者頁面

  • 設定 Privacy Policy URL、User data deletion
  • 將右上的 Live 開關打開

【在模擬器切換 FB 帳號】

除非透過『重置模擬器』,不然即使移除 App,模擬器仍舊存在已登入過的 facebook 紀錄則會由此登入

--

--

Responses (1)