1。概要
フレンドリーチャットコードラボへようこそ。このコードラボでは、Firebaseプラットフォームを使用してiOSアプリケーションを作成する方法を学習します。チャットクライアントを実装し、Firebaseを使用してそのパフォーマンスを監視します。
あなたが学ぶこと
- ユーザーがサインインできるようにします。
- Firebase RealtimeDatabaseを使用してデータを同期します。
- バイナリファイルをFirebaseStorageに保存します。
必要なもの
- Xcode
- CocoaPods
- iOS8.0以降またはシミュレーターを備えたテストデバイス
このチュートリアルをどのように使用しますか?
iOSアプリの構築の経験をどのように評価しますか?
2.サンプルコードを取得します
コマンドラインからGitHubリポジトリのクローンを作成します。
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3.スターターアプリを作成します
スターターアプリを作成するには:
- ターミナルウィンドウで、に移動します
サンプルコードのダウンロードから
ios-starter/swift-starter
ディレクトリ pod install --repo-update
実行します- FriendlyChatSwift.xcworkspaceファイルを開いて、Xcodeでプロジェクトを開きます。
- クリック
実行ボタン。
数秒後にFriendlyChatのホーム画面が表示されます。 UIが表示されます。ただし、この時点では、サインイン、メッセージの送受信はできません。次の手順を完了するまで、アプリは例外を除いて中止されます。
4.Firebaseコンソールプロジェクトを作成します
プロジェクトを作成する
Firebaseコンソールから[プロジェクトの追加]を選択します。
プロジェクトFriendlyChat
を呼び出し、[プロジェクトの作成]をクリックします。
iOSアプリを接続します
- 新しいプロジェクトの[プロジェクトの概要]画面で、[ iOSアプリにFirebaseを追加]をクリックします。
- バンドルIDを「
com.google.firebase.codelab.FriendlyChatSwift
」として入力します。 - App StoreIDを「
123456
」として入力します。 - [アプリの登録]をクリックします。
GoogleService-Info.plistファイルをアプリに追加します
2番目の画面で、[ GoogleService-Info.plistのダウンロード]をクリックして、アプリに必要なすべてのFirebaseメタデータを含む構成ファイルをダウンロードします。そのファイルをアプリケーションにコピーし、 FriendlyChatSwiftターゲットに追加します。
ここで、ポップアップの右上隅にある[x]をクリックして、ポップアップを閉じることができます(手順3と4をスキップして)。ここでこれらの手順を実行します。
Firebaseモジュールをインポートする
まず、 Firebase
モジュールがインポートされていることを確認します。
AppDelegate.swift 、 FCViewController.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
}
5.ユーザーを特定する
ルールを使用して認証されたユーザーに制限する
ここで、メッセージの読み取りまたは書き込みの前に認証を要求するルールを追加します。これを行うには、メッセージデータオブジェクトに次のルールを追加します。 Firebaseコンソールの[データベース]セクションから[リアルタイムデータベース]を選択し、[ルール]タブをクリックします。次に、ルールを次のように更新します。
{
"rules": {
"messages": {
".read": "auth != null",
".write": "auth != null"
}
}
}
これがどのように機能するか(「auth」変数に関するドキュメントを含む)の詳細については、Firebaseセキュリティドキュメントを参照してください。
認証APIを構成する
アプリケーションがユーザーに代わってFirebaseAuthentication APIにアクセスする前に、それを有効にする必要があります
- Firebaseコンソールに移動して、プロジェクトを選択します
- 認証を選択
- [サインイン方法]タブを選択します
- Googleスイッチを有効(青)に切り替えます
- 結果のダイアログで[保存]を押します
このコードラボの後半で「CONFIGURATION_NOT_FOUND」というメッセージが表示されたエラーが発生した場合は、この手順に戻って作業を再確認してください。
FirebaseAuthの依存関係を確認する
Podfile
ファイルにFirebaseAuthの依存関係が存在することを確認します。
Podfile
pod 'Firebase/Auth'
Googleサインイン用にInfo.plistを設定します。
XCodeプロジェクトにカスタムURLスキームを追加する必要があります。
- プロジェクト構成を開きます。左側のツリービューでプロジェクト名をダブルクリックします。 [ターゲット]セクションからアプリを選択し、[情報]タブを選択して、[URLタイプ]セクションを展開します。
- [+]ボタンをクリックして、逆にしたクライアントIDのURLスキームを追加します。この値を見つけるには、GoogleService-Info.plist構成ファイルを開き、REVERSED_CLIENT_IDキーを探します。そのキーの値をコピーして、構成ページの[URLスキーム]ボックスに貼り付けます。他のフィールドは空白のままにします。
- 完了すると、構成は次のようになります(ただし、アプリケーション固有の値を使用)。
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)")
}
}
サインインしたユーザーとしてメッセージの読み取りをテストする
- クリック
実行ボタン。
- すぐにサインイン画面に移動します。 Googleログインボタンをタップします。
- すべてがうまくいった場合は、メッセージング画面に移動する必要があります。
6.リアルタイムデータベースをアクティブ化します
メッセージのインポート
Firebaseコンソールのプロジェクトで、左側のナビゲーションバーの[データベース]アイテムを選択します。データベースのオーバーフローメニューで、[ JSONのインポート]を選択します。 friendlychatディレクトリのinitial_messages.json
ファイルを参照し、それを選択して、[インポート]ボタンをクリックします。これにより、現在データベースにあるすべてのデータが置き換えられます。緑の+と赤のxを使用してデータベースを直接編集し、アイテムを追加および削除することもできます。
データベースをインポートすると、次のようになります。
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
}
メッセージ同期のテスト
- クリック
実行ボタン。
- [サインインして開始]ボタンをクリックして、メッセージウィンドウに移動します。
- 「メッセージ」エントリの横にある緑色の+記号をクリックし、次のようなオブジェクトを追加して、Firebaseコンソールで新しいメッセージを直接追加します。
- それらがFriendly-ChatUIに表示されることを確認します。
7.メッセージを送信する
メッセージ送信の実装
値をデータベースにプッシュします。 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)
}
メッセージの送信をテストする
- クリック
実行ボタン。
- [サインイン]をクリックして、メッセージウィンドウに移動します。
- メッセージを入力して送信を押します。新しいメッセージは、アプリのUIとFirebaseコンソールに表示されます。
8.画像の保存と受信
Firebaseストレージの依存関係を確認する
Podfile
の依存関係ブロックで、 Firebase/Storage
が含まれていることを確認します。
Podfile
pod 'Firebase/Storage'
ダッシュボードでFirebaseStorageを有効にする
Firebaseコンソールに移動し、「gs://PROJECTID.appspot.com」ドメインでストレージがアクティブ化されていることを確認します
代わりにアクティベーションウィンドウが表示されている場合は、[開始]をクリックして、デフォルトのルールでアクティベートします。
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
}
9.画像メッセージを送信する
ストアの実装と画像の送信
ユーザーから画像をアップロードしてから、この画像のストレージ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])
}
}
}
画像メッセージの送受信をテストする
- クリック
実行ボタン。
- [サインイン]をクリックして、メッセージウィンドウに移動します。
- 「写真を追加」アイコンをクリックして写真を選択します。写真付きの新しいメッセージは、アプリのUIとFirebaseコンソールに表示されます。
10.おめでとうございます!
Firebaseを使用して、リアルタイムチャットアプリケーションを簡単に構築しました。
私たちがカバーしたこと
- リアルタイムデータベース
- フェデレーションサインイン
- 保管所