Android Firebase cho người mới bắt đầu
Firebase
I. Firebase là gì
Google Firebase là phần mềm phát triển ứng dụng được Google hỗ trợ cho phép các nhà phát triển phát triển ứng dụng iOS, Android và Web apps. Firebase cung cấp các công cụ để theo dõi phân tích, báo cáo và khắc phục sự cố ứng dụng, tạo thử nghiệm tiếp thị và sản phẩm. Firebase có nhiều dịch vụ và hôm nay mình sẽ viết về in-app messaging, cloud messages and real-time databases.
II. Thêm Firebase vào dự án
Trước khi thêm Firebase vào ứng dụng Android, chúng ta cần tạo một dự án Firebase để kết nối với ứng dụng Android của mình. Đăng nhập vào Firebase console ở liên kết này https://console.firebase.google.com/?hl=en
III. In-App Message
1. Giới thiệu
Firebase In-App Messaging giúp ứng dụng của bạn có thể thu hút người dùng đang hoạt động bằng cách gửi cho họ những thông điệp tuỳ theo mục đích của bạn và khuyến khích họ sử dụng các tính năng chính của ứng dụng. Ví dụ: bạn có thể gửi tin nhắn trong ứng dụng để khiến người dùng đăng ký, xem video, hoàn thành cấp độ hoặc mua một mặt hàng nào đó. Bạn có thể tùy chỉnh tin nhắn dưới dạng cards, banners, modals, hoặc images, và bạn có thể cài đặt thời điểm hiển thị chính xác giúp cho chúng có thể mang lại lợi ích cho người dùng của bạn nhiều nhất.
2. Bắt đầu
private fun createInstanceId() { FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { task -> if (!task.isSuccessful) { Log.w(TAG, "getInstanceId failed", task.exception) return@addOnCompleteListener } //create new instance id Token val msg = task.result?.id Log.d(TAG, "token: $msg") } }
IV. Cloud Message
1. Giới thiệu
Firebase Cloud Messaging (FCM) là một giải pháp nhắn tin đa nền tảng cho phép bạn gửi tin nhắn một cách đáng tin cậy và hoàn toàn miễn phí. sử dụng FCM, bạn có thông báo đến cho người dùng rằng email mới hoặc dữ liệu khác đã có sẵn để đồng bộ hóa. Bạn có thể gửi tin nhắn thông báo để thúc đẩy sự tham gia và duy trì của người dùng. Đối với các trường hợp sử dụng như nhắn tin tức thời, tin nhắn có thể chuyển tải trọng lên tới 4KB cho ứng dụng.
2. Bắt đầu
Bước 1: Thêm “implementation ‘com.google.firebase:firebase-messaging:20.1.0’ ” vào “build.gradle” (app) và “Sync Now”
Bước 2 : Thêm service vào File AndroidManifest
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
MyFirebaseMessagingService thừa kế từ FirebaseMessagingService. Đây là bắt buộc nếu bạn muốn xử lý bất kì tin nhắn thông báo nào trên ứng dụng của bạn chạy dưới background. Để nhận thông báo trong foreground ứng dụng, để nhận dữ liệu, để gửi các thư ngược lại và nhiều hơn nữa… Bạn phải thừa kế từ service này.
Bây giờ bạn sẽ thấy dòng 23 bị lỗi, bởi vì chưa có class MyFirebaseMessagingService trong project
đổi package name từ .java.MyFirebaseMessagingService thành <package>.MyFirebaseMessagingService.
Bước 3 (không bắt buộc): thêm icon mặc định và màu, bạn có thể bỏ qua bước này nếu như bạn ko cần
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_stat_ic_notification" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
Bước 4 (Không bắt buộc): Từ Android 8.0 (API level 26) và cao hơn, các thông báo đã được hỗ trợ và đề xuất. FCM cung cấp thông báo mặc định với cài đặt cơ bản. Còn nếu bạn muốn thông báo với giao diện của riêng mình, bạn hãy đặt default_notification_channel_id thành ID thông báo của bạn như hình bên dưới. FCM sẽ sử dụng giá trị này với bất cứ tin nhắn nào đến mà không thiết lập thông báo nào vào thư mục res/values/strings.xml và thêm dòng code này.
<string name="default_notification_channel_id">1</string>
Mở file AndroidMnifest và thêm đoạn code này.
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id" />
Bước 5: Vào file MainActivity để lấy token (dùng để test FCM)
private fun createInstanceId() { FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { task -> if (!task.isSuccessful) { Log.w(TAG, "getInstanceId failed", task.exception) return@addOnCompleteListener } //get id Token // Get new Instance ID token val token = task.result?.token // Log and toast Log.d(TAG, "token: $token") Toast.makeText(baseContext, "token: $token", Toast.LENGTH_SHORT).show() } }
Cài app vào chạy, nếu thành công bạn sẽ nhận được Firebase instance ID.
Bước 6: Thiết lập file MyFirebaseMessagingService
class MyFirebaseMessagingService : FirebaseMessagingService() { companion object { private val TAG = this::class.java.simpleName } override fun onNewToken(token: String) { Log.d(TAG, "Refreshed token: $token") super.onNewToken(token) } override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) Log.d(TAG, "From: ${remoteMessage.from}") remoteMessage.data.isNotEmpty().let { } remoteMessage.notification?.let { Log.d(TAG, "Message Notification Body: ${it.body}") it.body?.let { body -> sendNotification(body) } } } private fun sendNotification(messageBody: String) { val intent = Intent(this, CloudMessageActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT) val channelId = getString(R.string.default_notification_channel_id) val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) val notificationBuilder = NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_notifications) .setContentTitle("Mess Title") .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel) } notificationManager.notify(1, notificationBuilder.build()) } }
Bước 7: Test FCM trên Firebase
Nhập Title, text và image (không bắt buộc) vd https://cdn.pixabay.com/photo/2017/07/07/02/05/symbol-2480161_960_720.png
Thêm ID token đã lấy được trong Logcat (bước 5)
Kết quả test:
Bước 8: Tạo và gửi tin nhắn
Sau khi test thành công, chọn “Next“để tiếp tục
Sau khi chọn “Publish” Firebase sẽ gửi tin nhắn đến cho ứng dụng
Kết quả:
V. Realtime Database
1. Giới thiệu
Firebase Realtime Database là cơ sở dữ liệu lưu trữ trên mây. Dữ liệu được lưu trữ và đồng bộ hóa theo thời gian thực với mỗi client được kêt nối. Khi bạn xây dựng ứng dụng đa nền tảng với iOS, Android, và javascript SDK, tất cả các client của bạn chia sẽ một thể hiện Realtime Database và tự động tiếp nhận các thay đổi với dữ liệu mới nhất.
2. Bắt đầu
Bước 1: Thêm “implementation ‘com.google.firebase:firebase-database:19.2.1’ ” vào “build.gradle” (app) và “Sync Now”
Bước 2: Sửa “Rules” realtime database thành true
chi tiết về “Rules” của real time database bạn có thể xem ở link này
Bước 3: tạo class UserModel
data class UserModel( var id: String = "", var name: String = "", var age: Int = 0, var email: String = "" ) { override fun toString(): String { return "UserModel(id='$id', name='$name', age=$age, email='$email')" } }
Bước 4: Tạo 1 layout gồm 3 edit text (name, age and email), 4 button (insert, get, update, delete), 1 recycler view để chứa dữ liệu User
Bước 5:
- Thêm dữ liệu vào database:
Đầu tiên, khởi tạo biến databaseReference
private fun initDatabase() { databaseReference = FirebaseDatabase.getInstance().reference }
Tiếp theo, lấy dữ liệu từ EditText và thêm vào database.
private fun insertUser() { if (edt_name.text.isNullOrEmpty() || edt_age.text.isNullOrEmpty() || edt_email.text.isNullOrEmpty()) { Toast.makeText(this, "Some field are missing.", Toast.LENGTH_SHORT).show() return } //get key val key = databaseReference.child("User").push().key //get user data from edit text val user = UserModel( name = edt_name.text.toString(), age = edt_age.text.toString().toInt(), email = edt_email.text.toString() ) key?.let { user.id = key // Write a data to the database databaseReference.child("User").child(key).setValue(user).addOnSuccessListener { clearText() //get user data from database getUser() //scroll to new item recycler_user.scrollToPosition(recyclerAdapter.userList.size - 1) } .addOnFailureListener { Toast.makeText(this, "Upload Error", Toast.LENGTH_SHORT).show() } } }
Ở sự kiện click của button_insert
btn_insert.setOnClickListener { insertUser() }
sau khi chọn button_insert dữ liệu sẽ được thêm vào database ngay lập tức.
- đọc dữ liệu trên database:
private fun getUser() { databaseReference.child("User").addValueEventListener(object : ValueEventListener { override fun onCancelled(dataError: DatabaseError) { Toast.makeText(this@DataBaseActivity, "Upload Error", Toast.LENGTH_SHORT).show() } override fun onDataChange(dataSnapshot: DataSnapshot) { //get user list from database val list = dataSnapshot.children.mapNotNull { it.getValue(UserModel::class.java) } list.forEach { Log.i("Users", it.toString()) } //add to recycler view if (list.isNotEmpty()) { recyclerAdapter.userList.clear() recyclerAdapter.userList.addAll(list) recyclerAdapter.notifyDataSetChanged() } } }) }
- Update dữ liệu trên database
private fun updateUser() { user?.let { //create new user object val user = UserModel( it.id, edt_name.text.toString(), edt_age.text.toString().toInt(), edt_email.text.toString() ) //update user databaseReference.child("User/${it.id}").setValue(user) } }
- Delete dữ liệu trên database
private fun deleteUser() { // get user id val query = databaseReference.child("User").orderByChild("id").equalTo(user?.id) query.addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { for (user in dataSnapshot.children) { //remove user user.ref.removeValue().addOnSuccessListener { clearText() } } } override fun onCancelled(databaseError: DatabaseError) { Log.e( TAG, "onCancelled", databaseError.toException() ) } }) getUser() }
VI. Link tham khảo
https://firebase.google.com/docs/guides
https://proandroiddev.com/firebase-android-playground-realtime-database-560d4e18404a
https://www.learnhowtoprogram.com/android/data-persistence/firebase-reading-data-and-event-listeners