初心者のためのAndroid Firebase
Firebase
I. Firebaseとは
Google FirebaseはGoogleのバックエンドアプリケーションで開発者がiOSやandroid、Web appsの開発を行うことができるサービスです。Firebaseはトラッキングやその分析、クラッシュレポートまたその修正、マーケティングの調査、アプリケーションの検証のツールとして提供されています。Firebaseはたくさんのサービスがあります。今回はin-app messaging、cloud messages、そしてreal-time databasesについてご紹介したいと思います。
II. アプリにFirebaseを追加する
AndroidアプリケーションにFirebaseを入れる前に、AndroidアプリケーションをFirebaseに接続するためそのプロジェクトを構築する必要があります。Firebaseコンソールにログインをします。 https://console.firebase.google.com/?hl=en
Step 1: Firebaseにログインした後、”Create a project“をクリックします。
Step 2: ここからは新しくFirebaseプロジェクトを作成するための手順です。Android iconをクリックします。
Step 3:Android Manifestのpackage nameと同じものを”Android package name“に入力してください。
Step 4: “google-services.json”をダウンロードしてください。そしてプロジェクトに追加してください。
- Viewを切り替えるために”Project”をクリックしてください。そうするとプロジェクトのrootディレクトリが表示されます。”google-services.json“ファイルを”Project/~/app”フォルダにおきます。
Step 5: Firebase SDKを設定します。(画像参照)
1. “build.gradle” (Project):
2. “build.gradle” (app):
Step 6: 起動させFirebaseのアプリの確認を待ちます。成功のメッセージが表示されると“Continue to console”をクリックします。
III. In-App Message
1. 紹介
Firebase In-App Messagingは 狙ったユーザに対しアプリの主要な機能を動かすためテキストメッセージを送りユーザにアプリを起動させるように促すことができます。例えば、サブスクライバーやビデオ観賞、レベルの達成またはアイテムの購入を誘導するためユーザにin-app messageを送ります。
カードやバナー、モーダル、画像のようにカスタマイズすることができ、そしてトリガーをセットできます。そのため、一番効果があるタイミングで正確にそれを表示することができます。
2. 始め方
Step 1: “build.gradle” (app)に“implementation ‘com.google.firebase:firebase-inappmessaging-display:19.0.3’を追加します。そして”Sync Now“をクリックします。
Step 2: Firebase instance ID (Firebaseのin-app messageのテストに使用するID)を取得します。
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") } }
Step 3:アプリを起動させ”Logcat” ツールを開きます。ID tokenをそこで確認することができます。
Step 4: ID tokenをコピーし, Firebase コンソール -> “In-App Messaging“を開き, “Create your first campaign”をクリックします。
Step 5: “Message title” (例: Hello I’m FireBase)”Body” (optional), “Images” (ex: https://cdn.pixabay.com/photo/2015/10/12/14/54/coffee-983955_960_720.jpg)を入力します。
“Button text“を追加します。
Step 6: “Test on Device”をクリックし, “Add an instance ID” フィールドにID tokenをペーストします。
Firebase In-App Messagingはクリックするとすぐに”Test“を送信します。それを見るためにはアプリをバックエンドへ移動し、テスト端末でアプリを再起動します。
結果:
Step 7: テストが成功した後、続けるために”Next”をクリックします。
メッセージを公開するために”Review“をクリックしてください。
“Publish“をクリックすると、アプリにメッセージが送信されます。
結果:
IV. Cloud Message
1. 紹介
Firebase Cloud Messaging (FCM)は費用なしで確実にメッセージを届けるクロスプラットフォームメッセージソリューションです。FCMを使用し、メールや同期可能な他のデータでクライアントアプリケーションに知らせることができます。ユーザの再訪問やアプリの使用を継続させるプッシュ通知を送ることができます。
インスタントメッセージを使用するケースとして、メッセージはクライアントアプリに4KBまでのpayloadで送ることができる。
2. 始め方
Step 1: “implementation ‘com.google.firebase:firebase-messaging:20.1.0’ “を”build.gradle” (app)に追加する。そして”Sync Now“をクリックします。
Step 2 : AndroidManifestファイルにfilterを追加します。
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
MyFirebaseMessagingServiceはFirebaseMessagingServiceの拡張です。これはバックグラウンドでアプリにPush通知を受け取る以外にメッセージを扱うとき必要になります。フォアグランドでPush通知を受け取るためにはPayloadで受け取り、upstream messagesを送るなど、このサービスを使わなければならない。
今line 23にエラーが表示されています。これはMyFirebaseMessagingServiceファイルがないために発生しているので、それを作ります。
.java.MyFirebaseMessagingServiceから<package>.MyFirebaseMessagingServiceにpackage nameを変更します。
Step 3 (optional): デフォルトアイコンと色を設定します。特にPush通知で変更したくなければこのステップをスキップして良いです。
<!-- 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" />
Step 4 (Optional): Android 8.0 (API level 26)またはそれ以上から、notification channelsはsupported またはrecommendedになっています。FCMは基本設定としてdefault notification channelの使用を提供しています。
もし新たにchannelを作りたい、デフォルトのchannelにしたい場合はdefault_notification_channel_idに自分のデフォルトchannelとしてpush通知channelオブジェクトを利用してください。
FCMはnotification channelが明示的にセットされない限りこの値を使用します。もっと詳しく知りたければ、Manage notification channelsを参照してください。
- res/values/strings.xmlを開き、この行を追加してください。
<string name="default_notification_channel_id">1</string>
- AndroidManifestファイルを開き、このコードを追加してください。
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id" />
Step 5: 現在のregistration tokenを取得するためMainActivityを開き、この機能を追加します。
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() } }
- アプリを動作させ、Firebase instance IDを取得します。
Step 6: 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()) } }
Step 7: Cloud Messagingのテスト
Notification Title, text と image (optional)を入力します。 ex: https://cdn.pixabay.com/photo/2017/07/07/02/05/symbol-2480161_960_720.png and send test message.
- Logcat (step 5)からtokenを取得し追加します。
- 結果:
Step 7: 作成とメッセージ送信
テストが成功した後で、続けるために”Next“を追加します。
- メッセージを送信するため”Publish“を送信します。
結果:
V. Realtime Database
1. 紹介
Firebase Realtime Databaseはクラウドホスティングデータベースです。データはJson形式で保存され、クライアントに毎回リアルタイムに同期されます。iOS, Android JavaScript SDKを使ったあなたのクライアントのクロスプラットフォームアプリはrealtime database instanceに同期され、自動で最新のデータにアップデートされます。
2. Get start
Step 1: “build.gradle”に“implementation ‘com.google.firebase:firebase-database:19.2.1’ ” (app)を追加します。そして”Sync Now“をクリックします。
Step 2: テストのためにrealtime databaseのrules設定します。
realtime databaseのrulesについてはこちらを確認してください。
Step 3: 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')" } }
Step 4: 3つの項目(name, age and email)があるLayoutを作成し、User dataを含めるために1つのrecycler viewを追加します。
これが作成したlayoutです。
Step 5:
データベースを記述します。
最初にdatabaseReferenceを初期化します。
private fun initDatabase() { databaseReference = FirebaseDatabase.getInstance().reference }
次に、入力した値を取得し、データベースに追加します。
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() } } }
Insertボタンのイベントのコードを追加します。
btn_insert.setOnClickListener { insertUser() }
アプリの”Insert“ボタンをクリックした後で、データはすぐにFirebaseに送られます。
データの読み込み:
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() } } })
データの更新:
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) } }
データの削除:
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. 参考文献
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