Google は、黒人コミュニティのための人種的公平の促進に取り組んでいます。詳細をご覧ください。

Firebase iOS Codelab Swift

2efe6805ef369641.png

フレンドリーチャットコードラボへようこそ。このコードラボでは、Firebaseプラットフォームを使用してiOSアプリケーションを作成する方法を学習します。チャットクライアントを実装し、Firebaseを使用してそのパフォーマンスを監視します。

このコードラボはObjective-Cでも利用できます。

あなたが学ぶこと

  • ユーザーにサインインを許可します。
  • Firebase RealtimeDatabaseを使用してデータを同期します。
  • バイナリファイルをFirebaseStorageに保存します。

必要なもの

  • Xcode
  • CocoaPods
  • iOS8.0以降またはシミュレーターを備えたテストデバイス

このチュートリアルをどのように使用しますか?

読むだけそれを読んで、演習を完了してください

iOSアプリの構築経験をどのように評価しますか?

初心者中級熟練している

コマンドラインからGitHubリポジトリのクローンを作成します。

$ git clone https://github.com/firebase/codelab-friendlychat-ios

2f4c98d858c453fe.png

スターターアプリを作成するには:

  1. ターミナルウィンドウで、に移動します。 android_studio_folder.pngサンプルコードのダウンロードからのios-starter/swift-starterディレクトリ
  2. pod install --repo-update実行します
  3. FriendlyChatSwift.xcworkspaceファイルを開いて、プロジェクトをXcodeで開きます。
  4. クリック98205811bbed9d74.png実行ボタン。

数秒後にFriendlyChatのホーム画面が表示されます。 UIが表示されます。ただし、この時点では、サインイン、メッセージの送信または受信はできません。次の手順を完了するまで、アプリは例外を除いて中止されます。

プロジェクトを作成する

Firebaseコンソールから[プロジェクトの追加]を選択します。

プロジェクトFriendlyChat呼び出し、[プロジェクトの作成]をクリックします

2015-11-06 14:13:39.pngのスクリーンショット

iOSアプリを接続します

  1. 新しいプロジェクトの[プロジェクトの概要]画面で、[ iOSアプリにFirebaseを追加]クリックします
  2. バンドルIDを「 com.google.firebase.codelab.FriendlyChatSwift 」として入力します。
  3. App 123456を「 123456 」として入力します。
  4. [アプリの登録]をクリックします。

GoogleService-Info.plistファイルをアプリに追加します

2番目の画面で、[ GoogleService-Info.plistのダウンロード]をクリックして、アプリに必要なすべてのFirebaseメタデータを含む構成ファイルをダウンロードします。そのファイルをアプリケーションにコピーし、 FriendlyChatSwiftターゲットに追加します。

これで、ポップアップの右上隅にある「x」をクリックして閉じることができます(手順3と4はスキップします)。ここでこれらの手順を実行します。

19d59efb213ddbdc.png

Firebaseモジュールをインポートする

Firebaseモジュールがインポートされていることを確認することから始めます。

AppDelegate.swiftFCViewController.swift

import Firebase

AppDelegateでFirebaseを設定する

application:didFinishLaunchingWithOptions関数内のFirebaseAppの「configure」メソッドを使用して、.plistファイルから基盤となるFirebaseサービスを構成します。

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  FirebaseApp.configure()
  GIDSignIn.sharedInstance().delegate = self
  return true
}

ルールを使用して、認証されたユーザーに制限する

メッセージを読み書きする前に認証を要求するルールを追加します。これを行うには、メッセージデータオブジェクトに次のルールを追加します。 Firebaseコンソールの[データベース]セクションから[リアルタイムデータベース]を選択し、[ルール]タブをクリックします。次に、ルールを次のように更新します。

{
  "rules": {
    "messages": {
      ".read": "auth != null",
      ".write": "auth != null"
    }
  }
}

これがどのように機能するか(「auth」変数に関するドキュメントを含む)の詳細については、Firebaseセキュリティドキュメントを参照してください。

認証APIを構成する

アプリケーションがユーザーに代わってFirebaseAuthentication APIにアクセスする前に、それを有効にする必要があります

  1. Firebaseコンソールに移動して、プロジェクトを選択します
  2. 認証を選択します
  3. [サインイン方法]タブを選択します
  4. Googleスイッチを有効(青)に切り替えます
  5. 結果のダイアログで[保存]を押します

このコードラボの後半で「CONFIGURATION_NOT_FOUND」というメッセージが表示されたエラーが発生した場合は、この手順に戻って作業を再確認してください。

FirebaseAuthの依存関係を確認する

PodfileファイルにFirebaseAuthの依存関係が存在することをPodfileます。

Podfile

pod 'Firebase/Auth'

Googleサインイン用にInfo.plistを設定します。

XCodeプロジェクトにカスタムURLスキームを追加する必要があります。

  1. プロジェクト構成を開きます。左側のツリービューでプロジェクト名をダブルクリックします。 [ターゲット]セクションからアプリを選択し、[情報]タブを選択して、[URLタイプ]セクションを展開します。
  2. [+]ボタンをクリックして、逆にしたクライアントIDのURLスキームを追加します。この値を見つけるには、GoogleService-Info.plist構成ファイルを開き、REVERSED_CLIENT_IDキーを探します。そのキーの値をコピーして、構成ページの[URLスキーム]ボックスに貼り付けます。他のフィールドは空白のままにします。
  3. 完了すると、構成は次のようになります(ただし、アプリケーション固有の値が含まれます)。

1b54d5bd2f4f1448.png

GoogleサインインのclientIDを設定します

Firebaseを設定したら、clientIDを使用して「didFinishLaunchingWithOptions:」メソッド内でGoogleログインを設定できます。

AppDelegate.swift

  func application(_ application: UIApplication, didFinishLaunchingWithOptions
      launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  FirebaseApp.configure()
  GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
  GIDSignIn.sharedInstance().delegate = self
  return true
}

サインインハンドラーを追加する

Googleログインの結果が成功したら、アカウントを使用してFirebaseで認証します。

AppDelegate.swift

  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
    if let error = error {
      print("Error \(error)")
      return
    }

    guard let authentication = user.authentication else { return }
    let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
                                                      accessToken: authentication.accessToken)
    Auth.auth().signIn(with: credential) { (user, error) in
      if let error = error {
        print("Error \(error)")
        return
      }
    }
  }

ユーザーに自動的にサインインします。次に、Firebase Authにリスナーを追加して、ログインに成功した後、ユーザーがアプリにアクセスできるようにします。deinitでリスナーを削除します。

SignInViewController.swift

  override func viewDidLoad() {
    super.viewDidLoad()
    GIDSignIn.sharedInstance().uiDelegate = self
    GIDSignIn.sharedInstance().signInSilently()
    handle = Auth.auth().addStateDidChangeListener() { (auth, user) in
      if user != nil {
        MeasurementHelper.sendLoginEvent()
        self.performSegue(withIdentifier: Constants.Segues.SignInToFp, sender: nil)
      }
    }
  }

  deinit {
    if let handle = handle {
      Auth.auth().removeStateDidChangeListener(handle)
    }
  }

サインアウト

サインアウト方法を追加します

FCViewController.swift

  @IBAction func signOut(_ sender: UIButton) {
    let firebaseAuth = Auth.auth()
    do {
      try firebaseAuth.signOut()
      dismiss(animated: true, completion: nil)
    } catch let signOutError as NSError {
      print ("Error signing out: \(signOutError.localizedDescription)")
    }
  }

サインインしたユーザーとしてメッセージの読み取りをテストする

  1. クリック98205811bbed9d74.png実行ボタン。
  2. すぐにサインイン画面に移動します。 Googleログインボタンをタップします。
  3. すべてがうまくいった場合は、メッセージング画面に移動する必要があります。

2efe6805ef369641.png

メッセージのインポート

Firebaseコンソールのプロジェクトで、左側のナビゲーションバーの[データベース]アイテムを選択します。データベースのオーバーフローメニューで、[ JSONのインポート]を選択しますinitial_messages.jsonディレクトリのinitial_messages.jsonファイルを参照して選択し、[インポート]ボタンをクリックします。これにより、現在データベースにあるすべてのデータが置き換えられます。緑の+と赤のxを使用してアイテムを追加および削除し、データベースを直接編集することもできます。

20ccf4856b715b4c.png

データベースをインポートすると、次のようになります。

f3e0367f1c9cd187.png

Firebaseデータベースの依存関係を確認する

Podfileファイルの依存関係ブロックで、 Firebase/Databaseが含まれていることを確認します。

Podfile

pod 'Firebase/Database'

既存のメッセージを同期する

新しく追加されたメッセージをアプリのUIに同期するコードを追加します。

このセクションで追加するコードは次のようになります。

  • Firebaseデータベースを初期化し、データベースに加えられた変更を処理するリスナーを追加します。
  • 新しいメッセージが表示されるようにDataSnapshot更新します。

FCViewControllerの「deinit」、「configureDatabase」、および「tableView:cellForRowindexPath:」メソッドを変更します。以下に定義されているコードに置き換えます。

FCViewController.swift

  deinit {
    if let refHandle = _refHandle {
      self.ref.child("messages").removeObserver(withHandle: _refHandle)
    }
  }


  func configureDatabase() {
    ref = Database.database().reference()
    // Listen for new messages in the Firebase database
    _refHandle = self.ref.child("messages").observe(.childAdded, with: { [weak self] (snapshot) -> Void in
      guard let strongSelf = self else { return }
      strongSelf.messages.append(snapshot)
      strongSelf.clientTable.insertRows(at: [IndexPath(row: strongSelf.messages.count-1, section: 0)], with: .automatic)
    })
  }


  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Dequeue cell
    let cell = self.clientTable.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
    // Unpack message from Firebase DataSnapshot
    let messageSnapshot = self.messages[indexPath.row]
    guard let message = messageSnapshot.value as? [String: String] else { return cell }
    let name = message[Constants.MessageFields.name] ?? ""
    let text = message[Constants.MessageFields.text] ?? ""
    cell.textLabel?.text = name + ": " + text
    cell.imageView?.image = UIImage(named: "ic_account_circle")
    if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
        let data = try? Data(contentsOf: URL) {
      cell.imageView?.image = UIImage(data: data)
    }
    return cell
  }

テストメッセージの同期

  1. クリック98205811bbed9d74.png実行ボタン。
  2. [サインインして開始]ボタンをクリックして、メッセージウィンドウに移動します。
  3. 「メッセージ」エントリの横にある緑色の+記号をクリックし、次のようなオブジェクトを追加して、Firebaseコンソールで新しいメッセージを直接追加します。 f9876ffc8b316b14.png
  4. それらがFriendly-ChatUIに表示されることを確認します。

メッセージ送信の実装

値をデータベースにプッシュします。 pushメソッドを使用してFirebaseRealtime Databaseにデータを追加すると、自動IDが追加されます。これらの自動生成されたIDはシーケンシャルであるため、新しいメッセージが正しい順序で追加されます。

FCViewControllerの「sendMessage:」メソッドを変更します。以下に定義されているコードに置き換えます。

FCViewController.swift

  func sendMessage(withData data: [String: String]) {
    var mdata = data
    mdata[Constants.MessageFields.name] = Auth.auth().currentUser?.displayName
    if let photoURL = Auth.auth().currentUser?.photoURL {
      mdata[Constants.MessageFields.photoURL] = photoURL.absoluteString
    }

    // Push data to Firebase Database
    self.ref.child("messages").childByAutoId().setValue(mdata)
  }

メッセージの送信をテストする

  1. クリック98205811bbed9d74.png実行ボタン。
  2. [サインイン]をクリックして、メッセージウィンドウに移動します。
  3. メッセージを入力して送信を押します。新しいメッセージは、アプリのUIとFirebaseコンソールに表示されます。

Firebaseストレージの依存関係を確認する

Podfile依存関係ブロックで、 Firebase/Storageが含まれていることを確認します。

Podfile

pod 'Firebase/Storage'

ダッシュボードでFirebaseStorageを有効にする

Firebaseコンソールに移動し、「gs://PROJECTID.appspot.com」ドメインでストレージがアクティブ化されていることを確認します

b0438b37a588bcee.png

代わりにアクティベーションウィンドウが表示されている場合は、[開始]をクリックして、デフォルトのルールでアクティベートします。

c290bbebff2cafa7.png

FirebaseStorageを構成します

FCViewController.swift

  func configureStorage() {
    storageRef = Storage.storage().reference()
  }

既存のメッセージで画像を受信する

FirebaseStorageから画像をダウンロードするコードを追加します。

FCViewControllerの「tableView:cellForRowAtindexPath:」メソッドを変更します。以下に定義されているコードに置き換えます。

FCViewController.swift

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Dequeue cell
    let cell = self.clientTable .dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath)
    // Unpack message from Firebase DataSnapshot
    let messageSnapshot: DataSnapshot! = self.messages[indexPath.row]
    guard let message = messageSnapshot.value as? [String:String] else { return cell }
    let name = message[Constants.MessageFields.name] ?? ""
    if let imageURL = message[Constants.MessageFields.imageURL] {
      if imageURL.hasPrefix("gs://") {
        Storage.storage().reference(forURL: imageURL).getData(maxSize: INT64_MAX) {(data, error) in
          if let error = error {
            print("Error downloading: \(error)")
            return
          }
          DispatchQueue.main.async {
            cell.imageView?.image = UIImage.init(data: data!)
            cell.setNeedsLayout()
          }
        }
      } else if let URL = URL(string: imageURL), let data = try? Data(contentsOf: URL) {
        cell.imageView?.image = UIImage.init(data: data)
      }
      cell.textLabel?.text = "sent by: \(name)"
    } else {
      let text = message[Constants.MessageFields.text] ?? ""
      cell.textLabel?.text = name + ": " + text
      cell.imageView?.image = UIImage(named: "ic_account_circle")
      if let photoURL = message[Constants.MessageFields.photoURL], let URL = URL(string: photoURL),
          let data = try? Data(contentsOf: URL) {
        cell.imageView?.image = UIImage(data: data)
      }
    }
    return cell
  }

ストアの実装と画像の送信

ユーザーから画像をアップロードしてから、この画像のストレージURLをデータベースに同期して、この画像がメッセージ内で送信されるようにします。

FCViewControllerの「imagePickerController:didFinishPickingMediaWithInfo:」メソッドを変更します。以下に定義されているコードに置き換えます。

FCViewController.swift

  func imagePickerController(_ picker: UIImagePickerController,
    didFinishPickingMediaWithInfo info: [String : Any]) {
      picker.dismiss(animated: true, completion:nil)
    guard let uid = Auth.auth().currentUser?.uid else { return }

    // if it's a photo from the library, not an image from the camera
    if #available(iOS 8.0, *), let referenceURL = info[UIImagePickerControllerReferenceURL] as? URL {
      let assets = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
      let asset = assets.firstObject
      asset?.requestContentEditingInput(with: nil, completionHandler: { [weak self] (contentEditingInput, info) in
        let imageFile = contentEditingInput?.fullSizeImageURL
        let filePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000))/\((referenceURL as AnyObject).lastPathComponent!)"
        guard let strongSelf = self else { return }
        strongSelf.storageRef.child(filePath)
          .putFile(from: imageFile!, metadata: nil) { (metadata, error) in
            if let error = error {
              let nsError = error as NSError
              print("Error uploading: \(nsError.localizedDescription)")
              return
            }
            strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
          }
      })
    } else {
      guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else { return }
      let imageData = UIImageJPEGRepresentation(image, 0.8)
      let imagePath = "\(uid)/\(Int(Date.timeIntervalSinceReferenceDate * 1000)).jpg"
      let metadata = StorageMetadata()
      metadata.contentType = "image/jpeg"
      self.storageRef.child(imagePath)
        .putData(imageData!, metadata: metadata) { [weak self] (metadata, error) in
          if let error = error {
            print("Error uploading: \(error)")
            return
          }
          guard let strongSelf = self else { return }
          strongSelf.sendMessage(withData: [Constants.MessageFields.imageURL: strongSelf.storageRef.child((metadata?.path)!).description])
      }
    }
  }

画像メッセージの送受信をテストする

  1. クリック98205811bbed9d74.png実行ボタン。
  2. [サインイン]をクリックして、メッセージウィンドウに移動します。
  3. 「写真を追加」アイコンをクリックして写真を選択します。写真付きの新しいメッセージは、アプリのUIとFirebaseコンソールに表示されます。

Firebaseを使用して、リアルタイムチャットアプリケーションを簡単に構築しました。

私たちがカバーしたこと

  • リアルタイムデータベース
  • フェデレーションサインイン
  • ストレージ

もっと詳しく知る