1. Tổng quan
Chào mừng bạn đến với lớp học lập trình thân thiện về Chat. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng nền tảng Firebase để tạo các ứng dụng iOS. Bạn sẽ triển khai ứng dụng trò chuyện và theo dõi hiệu suất của ứng dụng đó bằng Firebase.
Kiến thức bạn sẽ học được
- Cho phép người dùng đăng nhập.
- Đồng bộ hoá dữ liệu bằng Cơ sở dữ liệu theo thời gian thực của Firebase.
- Lưu trữ các tệp nhị phân trong Bộ nhớ Firebase.
Bạn cần có
- Xcode
- CocoaPods
- Thiết bị thử nghiệm chạy iOS 8.0 trở lên hoặc trình mô phỏng
Bạn sẽ sử dụng hướng dẫn này như thế nào?
Bạn đánh giá thế nào về trải nghiệm xây dựng ứng dụng iOS?
2. Nhận mã mẫu
Sao chép kho lưu trữ GitHub từ dòng lệnh.
$ git clone https://github.com/firebase/codelab-friendlychat-ios
3. Tạo ứng dụng khởi đầu
Cách tạo ứng dụng khởi đầu:
- Trong cửa sổ dòng lệnh, hãy chuyển đến thư mục
ios-starter/swift-starter
trong phần tải mã mẫu xuống - Vòng
pod install --repo-update
- Mở tệp YouChatSwift.xcworkspace để mở dự án trong Xcode.
- Nhấp vào nút Run (Chạy).
Bạn sẽ thấy màn hình chính của tính năng Trò chuyện thân thiện xuất hiện sau vài giây. Giao diện người dùng sẽ xuất hiện. Tuy nhiên, tại thời điểm này, bạn không thể đăng nhập, gửi hoặc nhận tin nhắn. Ứng dụng sẽ huỷ bỏ kèm theo một ngoại lệ cho đến khi bạn hoàn tất bước tiếp theo.
4. Tạo dự án trên bảng điều khiển của Firebase
Tạo dự án
Trong bảng điều khiển của Firebase, hãy chọn Thêm dự án.
Gọi dự án FriendlyChat
, sau đó nhấp vào Create Project (Tạo dự án).
Kết nối ứng dụng iOS của bạn
- Từ màn hình Tổng quan về dự án của dự án mới, hãy nhấp vào Thêm Firebase vào ứng dụng iOS của bạn.
- Nhập mã nhận dạng gói là "
com.google.firebase.codelab.FriendlyChatSwift
". - Nhập mã App Store là "
123456
". - Nhấp vào Đăng ký ứng dụng.
Thêm tệp GoogleService-Info.plist vào ứng dụng của bạn
Trên màn hình thứ hai, hãy nhấp vào Tải GoogleService-Info.plist xuống để tải tệp cấu hình chứa tất cả siêu dữ liệu Firebase cần thiết cho ứng dụng của bạn. Sao chép tệp đó vào ứng dụng rồi thêm vào mục tiêu ConsumerChatSwift.
Giờ đây, bạn có thể nhấp vào "x" ở góc trên bên phải của cửa sổ bật lên để đóng cửa sổ này – bỏ qua bước 3 và 4 – vì bạn sẽ thực hiện các bước đó ở đây.
Nhập mô-đun Firebase
Hãy bắt đầu bằng cách đảm bảo mô-đun Firebase
đã được nhập.
AppDelegate.swift, FCViewController.swift
import Firebase
Định cấu hình Firebase trong AppDelegate
Sử dụng nút "định cấu hình" trong FirebaseApp bên trong ứng dụng:didFinishLaunchingWithOptions để định cấu hình các dịch vụ Firebase cơ bản từ tệp .plist của bạn.
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance().delegate = self
return true
}
5. Xác định người dùng
Sử dụng quy tắc để hạn chế những người dùng đã xác thực
Bây giờ, chúng ta sẽ thêm quy tắc để yêu cầu xác thực trước khi đọc hoặc viết bất kỳ thư nào. Để thực hiện việc này, chúng ta thêm các quy tắc sau vào đối tượng dữ liệu tin nhắn. Trong mục Cơ sở dữ liệu của bảng điều khiển của Firebase, hãy chọn Cơ sở dữ liệu theo thời gian thực, rồi nhấp vào thẻ Quy tắc. Sau đó, hãy cập nhật các quy tắc để chúng trông giống như sau:
{
"rules": {
"messages": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Để biết thêm thông tin về cách hoạt động của tính năng này (bao gồm cả tài liệu về biến "auth"), hãy xem tài liệu bảo mật của Firebase.
Định cấu hình API xác thực
Trước khi ứng dụng của bạn có thể thay mặt người dùng truy cập API Xác thực Firebase, bạn sẽ phải bật API đó
- Chuyển đến bảng điều khiển của Firebase rồi chọn dự án của bạn
- Chọn Xác thực
- Chọn thẻ Phương thức đăng nhập
- Gạt nút chuyển Google sang trạng thái bật (màu xanh dương)
- Nhấn Save (Lưu) trên hộp thoại thu được
Nếu sau này bạn gặp lỗi trong lớp học lập trình này khi thông báo "CONFIGURATION_NOT_FOUND", hãy quay lại bước này và kiểm tra kỹ bài tập của bạn.
Xác nhận phần phụ thuộc Xác thực Firebase
Xác nhận rằng có các phần phụ thuộc Xác thực Firebase tồn tại trong tệp Podfile
.
Podfile
pod 'Firebase/Auth'
Thiết lập tệp Info.plist để Đăng nhập bằng Google.
Bạn sẽ cần thêm một lược đồ URL tùy chỉnh vào dự án XCode của mình.
- Mở cấu hình dự án: nhấp đúp vào tên dự án trong chế độ xem dạng cây ở bên trái. Chọn ứng dụng của bạn trong phần MỤC TIÊU, sau đó chọn thẻ Thông tin và mở rộng phần Loại URL.
- Nhấp vào nút dấu + rồi thêm lược đồ URL cho mã ứng dụng khách bị đảo ngược. Để tìm giá trị này, hãy mở tệp cấu hình GoogleService-Info.plist và tìm khóa REVERSED_CLIENT_ID. Sao chép giá trị của khoá đó rồi dán vào hộp Lược đồ URL trên trang cấu hình. Để trống các trường khác.
- Khi hoàn tất, cấu hình của bạn sẽ có dạng như sau (nhưng với các giá trị dành riêng cho ứng dụng):
Đặt clientID cho tính năng Đăng nhập bằng Google
Sau khi định cấu hình Firebase, chúng ta có thể sử dụng clientID để thiết lập tính năng Đăng nhập bằng Google bên trong trang "didFinishLaunchingWithOptions:" .
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
}
Thêm trình xử lý đăng nhập
Sau khi kết quả Đăng nhập bằng Google thành công, hãy sử dụng tài khoản đó để xác thực với 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
}
}
}
Tự động đăng nhập người dùng. Sau đó, thêm trình nghe vào tính năng Xác thực Firebase để cho phép người dùng truy cập vào ứng dụng sau khi đăng nhập thành công. Và xoá trình nghe trên 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)
}
}
Đăng xuất
Thêm phương thức Đăng xuất
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)")
}
}
Kiểm tra thư đọc với tư cách người dùng đã đăng nhập
- Nhấp vào nút Run (Chạy).
- Bạn sẽ được chuyển ngay đến màn hình đăng nhập. Nhấn vào nút Đăng nhập bằng Google.
- Sau đó, bạn sẽ được chuyển đến màn hình nhắn tin nếu mọi thứ đều hoạt động tốt.
6. Kích hoạt Cơ sở dữ liệu theo thời gian thực
Nhập ứng dụng Tin nhắn
Trong dự án của bạn trong bảng điều khiển của Firebase, hãy chọn mục Cơ sở dữ liệu trên thanh điều hướng bên trái. Trong trình đơn mục bổ sung của Cơ sở dữ liệu, hãy chọn Import JSON (Nhập JSON). Duyệt đến tệp initial_messages.json
trong thư mục friendlychat, chọn tệp đó rồi nhấp vào nút Import (Nhập). Thao tác này sẽ thay thế mọi dữ liệu hiện có trong cơ sở dữ liệu của bạn. Bạn cũng có thể chỉnh sửa trực tiếp cơ sở dữ liệu bằng cách sử dụng dấu x màu xanh lục + và màu đỏ để thêm và xoá các mặt hàng.
Sau khi nhập cơ sở dữ liệu, cơ sở dữ liệu của bạn sẽ có dạng như sau:
Xác nhận phần phụ thuộc của cơ sở dữ liệu Firebase
Trong khối phần phụ thuộc của tệp Podfile
, hãy xác nhận rằng Firebase/Database
được đưa vào.
Podfile
pod 'Firebase/Database'
Đồng bộ hoá thư hiện có
Thêm mã để đồng bộ hoá các thông báo mới được thêm vào giao diện người dùng của ứng dụng.
Mã bạn thêm vào phần này sẽ:
- Khởi chạy cơ sở dữ liệu Firebase và thêm một trình nghe để xử lý các thay đổi được thực hiện đối với cơ sở dữ liệu.
- Hãy cập nhật
DataSnapshot
để hiển thị các thông báo mới.
Sửa đổi "deinit", "configureDatabase" và "tableView:cellForRow_indexPath:" của FCViewController phương thức; thay thế bằng mã được xác định bên dưới:
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
}
Thử nghiệm tính năng đồng bộ hoá tin nhắn
- Nhấp vào nút Run (Chạy).
- Nhấp vào nút Đăng nhập để bắt đầu để chuyển đến cửa sổ thông báo.
- Thêm thông báo mới ngay trong bảng điều khiển của Firebase bằng cách nhấp vào biểu tượng dấu + màu xanh lục bên cạnh "thông báo" và thêm một đối tượng như sau:
- Kiểm tra để xác nhận rằng các cuộc trò chuyện đó sẽ xuất hiện trong giao diện người dùng friendly-Chat.
7. Gửi tin nhắn
Triển khai tính năng Gửi thông báo
Đẩy các giá trị đến cơ sở dữ liệu. Khi bạn sử dụng phương thức đẩy để thêm dữ liệu vào Cơ sở dữ liệu theo thời gian thực của Firebase, một mã nhận dạng tự động sẽ được thêm vào. Các mã nhận dạng được tạo tự động này có tính tuần tự, giúp đảm bảo rằng thư mới sẽ được thêm theo đúng thứ tự.
Sửa đổi thông báo "sendMessage" của FCViewController: phương thức; thay thế bằng mã được xác định bên dưới:
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)
}
Thử nghiệm tính năng gửi tin nhắn
- Nhấp vào nút Run (Chạy).
- Nhấp vào Đăng nhập để chuyển đến cửa sổ tin nhắn.
- Nhập tin nhắn và nhấn gửi. Thông báo mới sẽ xuất hiện trong giao diện người dùng ứng dụng và trong bảng điều khiển của Firebase.
8. Lưu trữ và nhận hình ảnh
Xác nhận phần phụ thuộc vào bộ nhớ Firebase
Trong khối phần phụ thuộc của Podfile
, hãy xác nhận rằng Firebase/Storage
được đưa vào.
Podfile
pod 'Firebase/Storage'
Kích hoạt Bộ nhớ Firebase trong trang tổng quan
Truy cập vào bảng điều khiển của Firebase và xác nhận rằng Bộ nhớ đã được kích hoạt bằng "gs://PROJECTID.appspot.com" miền
Nếu bạn đang nhìn thấy cửa sổ kích hoạt, hãy nhấp vào "BẮT ĐẦU" để kích hoạt nó với các quy tắc mặc định.
Định cấu hình FirebaseStorage
FCViewController.swift
func configureStorage() {
storageRef = Storage.storage().reference()
}
Nhận hình ảnh trong tin nhắn hiện có
Thêm mã tải hình ảnh xuống từ Bộ nhớ Firebase.
Sửa đổi "tableView: cellForRowAt IndexPath:" của FCViewController phương thức; thay thế bằng mã được xác định bên dưới:
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. Gửi tin nhắn hình ảnh
Triển khai cửa hàng và gửi hình ảnh
Tải hình ảnh của người dùng lên, sau đó đồng bộ hoá URL lưu trữ của hình ảnh này với cơ sở dữ liệu để gửi hình ảnh này bên trong thư.
Sửa đổi thông số "imagePickerController: DidFinishPickingMediaWithInfo:" của FCViewController của bạn phương thức; thay thế bằng mã được xác định bên dưới:
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])
}
}
}
Thử nghiệm tính năng gửi và nhận tin nhắn hình ảnh
- Nhấp vào nút Run (Chạy).
- Nhấp vào Đăng nhập để chuyển đến cửa sổ tin nhắn.
- Nhấp vào "thêm ảnh" biểu tượng để chọn ảnh. Thông báo mới kèm theo ảnh sẽ hiển thị trong giao diện người dùng ứng dụng và trong bảng điều khiển của Firebase.
10. Xin chúc mừng!
Bạn đã sử dụng Firebase để dễ dàng tạo ứng dụng trò chuyện theo thời gian thực.
Nội dung đã đề cập
- Cơ sở dữ liệu theo thời gian thực
- Đăng nhập liên kết
- Bộ nhớ