NCMBのSwift SDKでFacebook認証を実装する

ニフクラ mobile backendでは各種言語向けにSDKを提供しています。その中で最も新しいSwift SDKについて、その使い方を紹介します。

今回はFacebook認証の使い方を紹介します。

## SwiftUI Appとして実装

今回はLifeCycleをSwiftUI Appとして実装していきます。Facebook SDKの実装方法についてすら、あまり情報がないので、最適な実装ではないかもしれません。

## SDKのインストールはCocoaPodsで

Facebook SDKとNCMB SDKともにCocoaPods経由でインストールします。

```
target 'YOUR_APP' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for todoapp
  pod 'NCMB', :git => 'https://github.com/NIFCLOUD-mbaas/ncmb_swift.git'
  pod 'FBSDKLoginKit'
end
```

## 管理画面の設定

NCMBの管理画面でFacebookアプリIDを設定してください。

![FireShot Capture 003 - ニフクラ mobile backend - console.mbaas.nifcloud.com.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/a4e8f6e8-b6bd-f96c-e610-f75c75201046.jpeg)


## SDKのインポート

今回は `Auth` というアプリ名にしたので、 `AuthApp.swift` を開いてSDKをインポートします。

```swift
import SwiftUI
import NCMB         // 追加
import FBSDKCoreKit // 追加
```

bodyを修正します。 `onOpenURL` と `onChange` でそれぞれ `ApplicationDelegate.shared.application` を使って初期化処理を行っています。

```swift
@Environment(\.scenePhase) private var scenePhase // 追加（最初からあるかも？）
var body: some Scene {
    WindowGroup {
        ContentView()
            .onOpenURL(perform: { url in
                // Facebook SDKの初期化（OpenURLで戻ってきた場合）
                ApplicationDelegate.shared.application(
                    UIApplication.shared,
                    open: url,
                    sourceApplication: nil,
                    annotation: UIApplication.OpenURLOptionsKey.annotation)
            })
    }.onChange(of: scenePhase) { scene in
        switch scene {
        case .active:
            // Facebook SDKの初期化
            ApplicationDelegate.shared.application(
                UIApplication.shared,
                didFinishLaunchingWithOptions: nil
            )
            // NCMBのSwift SDKの初期化
            NCMB.initialize(applicationKey: "YOUR_APPLICATION_KEY", clientKey: "YOUR_CLIENT_KEY")
        case .background:
            print(".background")
        case .inactive:
            print(".inactive")
        @unknown default: break
        }
    }
```

## ContentView.swiftの修正

次に `ContentView.swift` の修正です。まずSDKを読み込みます。

```swift
import SwiftUI
import NCMB           // 追加
import FBSDKLoginKit  // 追加
```

ステートを追加します。

```swift
struct ContentView: View {
    @State var user: NCMBUser?
    @State var manager = LoginManager()
```

ボタンを配置して、そのイベントを facebookLogin としておきます。

```swift
var body: some View {
    NavigationView {
        VStack(alignment: .center) {
            if user == nil {
                Text("ログインしていません")
                    .padding()
            } else {
                Text(user!.userName!)
                Text(user!.objectId!)
            }
            Button(action: facebookLogin, label: {
                Text("Facebookログイン")
            })
    }.onAppear {
        self.user = NCMBUser.currentUser
    }
    
}
```

最初は `NCMBUser.currentUser` が nil なので、ログインしていませんと出ます。

## Info.plistの編集

Info.plistをXMLで開いて、`<dict></dict>` の中に下記を記述します。 () 内をそれぞれ自分のものに書き換えます。

```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
    <key>CFBundleURLSchemes</key>
    <array>
    <string>fb(Facebook App Id)</string>
    </array>
    </dict>
</array>
<key>FacebookAppID</key>
<string>(Facebook App Id)</string>
<key>FacebookClientToken</key>
<string>(Facebookアプリ名)</string>
<key>FacebookDisplayName</key>
<string>(Facebookアプリ名)</string>
```


## Facebook認証の実装

では、ここからFacebook認証の実装です。関数名は `facebookLogin` です。

```swift
func facebookLogin() {
    // この中に実装します
}
```

まずFacebook側のログイン処理を実行します。エラーだったり、キャンセルだったら、ここで終了です。

```swift
self.manager.logIn(permissions: ["public_profile", "email"], from: nil) {(result, err) in
    if err != nil {
        print(err!.localizedDescription)
        return
    }
    if ( result != nil && (result?.isCancelled)! ) {
        print("Canceled")
        return
    }
    // 後述
```

トークンが取れれば、自分自身の情報を取得します。

```swift
let token = result?.token!
if  result != nil && (result?.grantedPermissions != nil) {
    GraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, email"]).start(completionHandler: { (connection, result, error) in
        if error != nil {
            print("プロフィール取得エラー")
            return
        }
    // 後述
```

レスポンスからID（ユーザID）を取得します。

```swift
let res = result as! [String : Any]
let id = res["id"] as! String
```

トークン情報とIDを使って `NCMBFacebookParameters` を作ります。

```swift
let params = NCMBFacebookParameters(id: id, accessToken: token!.tokenString, expirationDate: token!.dataAccessExpirationDate)
```

これで準備ができたので、認証を実行します。認証が成功すると `.success` になり、 `NCMBUser.currentUser` が取得できます。

```swift
let user = NCMBUser()
user.signUpWithFacebookToken(facebookParameters: params, callback: { (result) in
    switch result {
    case .success:
        print("認証成功")
        self.user = NCMBUser.currentUser
        break
    case let .failure(error):
        print(error)
        break;
    }
})
```

## まとめ

SwiftUI Appとして実装する場合、Facebook SDKの初期化が2カ所に分かれるなど、実装面での違いがありました。ボタンを押した後、Facebook認証を行ったりNCMBでログインする流れについては、特に変わらずに行えます。

Swift SDKを使えばソーシャル認証も簡単に実装できます。ぜひお試しください。

[ドキュメント : 開発者向けドキュメント | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/#/Swift)