class ChatFragment : Fragment() {
private lateinit var binding: FragmentChatBinding
private lateinit var mAuth: FirebaseAuth
private lateinit var mDbRef: DatabaseReference
private lateinit var currentUserId: String
private lateinit var currentUserEmail: String
private lateinit var messageList: ArrayList<ChatDTO>
private lateinit var contentUid: String
private lateinit var uid: String
private lateinit var title: String
private lateinit var recieverName: String
private lateinit var recieverUid: String
private lateinit var senderRoom: String
private lateinit var recieverRoom: String
private lateinit var timestamp: String
lateinit var chatRoom: String
/*
private lateinit var notificationSender: NotificationSender
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAuth = FirebaseAuth.getInstance()
currentUserId = mAuth.currentUser?.uid?: ""
currentUserEmail = mAuth.currentUser?.email?: ""
mDbRef = FirebaseDatabase.getInstance().reference
uid = mAuth.currentUser?.uid?: ""
recieverName = mAuth.currentUser?.email?: ""
arguments?.let{
contentUid =it.getString("contentUid").toString()
recieverUid =it.getString("uid").toString()
title =it.getString("title").toString()
var senderUid =it.getString("senderUid")
if (senderUid == null) {
senderUid = currentUserId
}
chatRoom =listOf(senderUid, recieverUid).sortedBy{ it }.joinToString(separator = "_")
}
val firebaseService = MyFirebaseMessagingService.getInstance()
firebaseService.sendNotificationToUser(recieverUid,"" ,requireContext())
/*
notificationSender = NotificationSender("<http://localhost:3000/>")
*/
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentChatBinding.inflate(layoutInflater)
binding.chatTitleText.text= title
messageList = ArrayList()
val chatAdapter: ChatAdapter = ChatAdapter(requireContext(), messageList, currentUserId)
binding.chatRecycler.layoutManager= LinearLayoutManager(requireContext())
binding.chatRecycler.adapter= chatAdapter
binding.chatSendBtn.setOnClickListener{
val message = binding.chatInputEdit.text.toString()
val currentTime = System.currentTimeMillis()
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.KOREA)
sdf.timeZone= TimeZone.getTimeZone("Asia/Seoul")
val dateString = sdf.format(currentTime)
val messageObject = ChatDTO(
currentUserId,
message,
recieverUid,
currentTime,
dateString
)
val senderChatRef =
mDbRef.child("Chat").child("chatRooms").child(chatRoom).child("messages").push()
senderChatRef.setValue(messageObject).addOnSuccessListener{
mDbRef.child("Chat").child("chatRooms").child(chatRoom).child("users")
.child(currentUserId).setValue(true)
mDbRef.child("Chat").child("chatRooms").child(chatRoom).child("users")
.child(recieverUid).setValue(true)
// 알림을 보내는 대상을 변경합니다.
val firebaseService = MyFirebaseMessagingService.getInstance()
firebaseService.sendNotificationToUser(recieverUid, message, requireContext())
// 상대방이 채팅을 확인한 경우에만 read 값을 변경합니다.
if (currentUserId == recieverUid) {
val messageId = senderChatRef.key
messageId?.let{
val messageRef = mDbRef.child("Chat").child("chatRooms").child(chatRoom)
.child("messages").child(it)
messageRef.child("read").setValue(true)
}
}
}
binding.chatInputEdit.setText("")
chatAdapter.notifyDataSetChanged()
binding.chatRecycler.scrollToPosition(messageList.size - 1)
}
val messagesRef = mDbRef.child("Chat").child("chatRooms").child(chatRoom).child("messages")
messagesRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
messageList.clear()
for (postSnapshot in snapshot.children) {
val message = postSnapshot.getValue(ChatDTO::class.java)
messageList.add(message!!)
// 상대방이 채팅을 확인한 경우에만 read 값을 변경합니다.
if (currentUserId == message.receiverUid && !message.read) {
val messageId = postSnapshot.key
messageId?.let{
val messageRef = messagesRef.child(it)
messageRef.child("read").setValue(true)
}
}
}
chatAdapter.notifyDataSetChanged()
binding.chatRecycler.scrollToPosition(messageList.size - 1)
}
override fun onCancelled(error: DatabaseError) {
}
})
return binding.root
}
}
2.MyFirebaseMessagingService
class MyFirebaseMessagingService : FirebaseMessagingService() {
private val TAG = "FirebaseService"
companion object {
private const val CHANNEL_ID = "my_channel"
var firebaseToken: String? = null
private var instance: MyFirebaseMessagingService? = null
fun getInstance(): MyFirebaseMessagingService {
if (instance == null) {
instance = MyFirebaseMessagingService()
}
return instance!!
}
}
override fun onNewToken(token: String) {
Log.d(TAG, "new Token : $token")
firebaseToken = token
val pref = getSharedPreferences("token", Context.MODE_PRIVATE)
val editor = pref.edit()
editor.putString("token", token).apply()
editor.commit()
Log.i(TAG, "Successfully saved the token")
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
Log.d(TAG, "From: ${remoteMessage.from}")
if (remoteMessage.data.isNotEmpty()) {
val uid = remoteMessage.data["uid"] ?: return
val message = remoteMessage.data["message"] ?: return
val nickname = remoteMessage.data["nickname"] ?: return
sendNotificationToUser(uid, message,applicationContext)
} else {
Log.e(TAG, "Data is empty. Failed to receive the message.")
}
super.onMessageReceived(remoteMessage)
}
fun sendNotificationToUser(reciverUid: String, message: String, context: Context) {
val dbRef = FirebaseDatabase.getInstance().reference
val userRef = dbRef.child("user").child(reciverUid)/*.child("FCMToken")*/
userRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val userData = snapshot.valueas? Map<String, Any>
val fcmToken = userData?.get("FCMToken") as? String
val nickname = userData?.get("nickname") as? String
if (fcmToken != null) {
val remoteMessage = RemoteMessage.Builder("my_sender_id")
.setMessageId("my_message_id")
.addData("uid", reciverUid)
.addData("message", message)
.addData("nickname", nickname)
.build()
sendNotification(remoteMessage, context)
} else {
Log.e(TAG, "FCM Token not found for the user with UID: $reciverUid")
}
}
override fun onCancelled(error: DatabaseError) {
Log.e(TAG, "Failed to retrieve FCM Token")
}
})
}
private fun sendNotification(remoteMessage: RemoteMessage, context: Context) {
val channelId = CHANNEL_ID
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val uid = remoteMessage.data["uid"]
val message = remoteMessage.data["message"]
val nickname = remoteMessage.data["nickname"]
val notificationBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(nickname)
.setContentText(message)
.setAutoCancel(true)
.setSound(soundUri)
val intent = Intent(context, ChatRoomFragment::class.java)
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOTor PendingIntent.FLAG_IMMUTABLE,
null
)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, "Notice", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(0, notificationBuilder.build())
}
fun getFirebaseToken() {
FirebaseMessaging.getInstance().token.addOnSuccessListener{
Log.d(TAG, "token=$it")
}
}
}
/*
package com.example.animal.service
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_ONE_SHOT
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.media.RingtoneManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import com.example.animal.ChatRoomFragment
import com.example.animal.LoginActivity
import com.example.animal.R
import com.example.animal.`interface`.NotificationAPI
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import kotlin.random.Random
class MyFirebaseMessagingService : FirebaseMessagingService() {
private val TAG = "FirebaseService"
companion object {
private const val CHANNEL_ID = "my_channel"
var firebaseToken: String? = null
private const val SERVER_KEY =
"C://Users//mj//workspace//keys//animal-1ccca-firebase-adminsdk-add7s-e0ed63689a.json" // You need to replace with your actual server key
private const val CONTENT_TYPE = "application/json"
private val retrofit = Retrofit.Builder()
.baseUrl("<https://fcm.googleapis.com/>") // FCM base URL
.addConverterFactory(GsonConverterFactory.create())
.build()
val api: NotificationAPI = retrofit.create(NotificationAPI::class.java)
private var instance: MyFirebaseMessagingService? = null
fun getInstance(): MyFirebaseMessagingService {
if (instance == null) {
instance = MyFirebaseMessagingService()
}
return instance!!
}
}
override fun onNewToken(token: String) {
Log.d(TAG, "new Token : $token")
firebaseToken = token
val pref = getSharedPreferences("token", Context.MODE_PRIVATE)
val editor = pref.edit()
editor.putString("token", token).apply()
editor.commit()
Log.i(TAG, "Successfully saved the token")
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
*/
/* Log.d(TAG, "From: ${remoteMessage.from}")
if (remoteMessage.data.isNotEmpty()) {
val uid = remoteMessage.data["uid"] ?: return
val message = remoteMessage.data["message"] ?: return
val nickname = remoteMessage.data["nickname"] ?: return
sendNotificationToUser(uid, message, applicationContext)
} else {
Log.e(TAG, "Data is empty. Failed to receive the message.")
}*//*
super.onMessageReceived(remoteMessage)
val intent = Intent(this, LoginActivity::class.java)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationID = Random.nextInt()
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(notificationManager)
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(remoteMessage.data["nickname"])
.setContentText(remoteMessage.data["message"])
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build()
notificationManager.notify(notificationID, notification)
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(notificationManager: NotificationManager) {
val channelName = "channelName"
val channel = NotificationChannel(CHANNEL_ID, channelName, IMPORTANCE_HIGH).apply {
description = "My channel description"
enableLights(true)
lightColor = Color.GREEN
}
notificationManager.createNotificationChannel(channel)
}
fun sendNotificationToUser(receiverUid: String, message: String, context: Context) {
val dbRef = FirebaseDatabase.getInstance().reference
val userRef = dbRef.child("user").child(receiverUid)
userRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val userData = snapshot.value as? Map<String, Any>
val fcmToken = userData?.get("FCMToken") as? String
val nickname = userData?.get("nickname") as? String
if (fcmToken != null && nickname != null) {
val remoteMessage = RemoteMessage.Builder("my_sender_id")
.setMessageId("my_message_id")
.addData("uid", receiverUid)
.addData("message", message)
.addData("nickname", nickname)
.build()
sendNotification(remoteMessage, context, receiverUid)
Log.d("FCM", "UID : $receiverUid")
Log.d("FCM", "FCM Token : $fcmToken")
} else {
Log.e(TAG, "FCM Token not found for the user with UID: $receiverUid")
}
}
override fun onCancelled(error: DatabaseError) {
Log.e(TAG, "Failed to retrieve FCM Token")
}
})
}
private fun sendNotification(
remoteMessage: RemoteMessage,
context: Context,
receiverUid: String
) {
val channelId = CHANNEL_ID
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val receiverUid = remoteMessage.data["receiverUid"]
val message = remoteMessage.data["message"]
val nickname = remoteMessage.data["nickname"]
val notificationBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(nickname)
.setContentText(message)
.setAutoCancel(true)
.setSound(soundUri)
val intent = Intent(context, ChatRoomFragment::class.java)
val pendingIntent = PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE,
null
)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId, "Notice", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(0, notificationBuilder.build())
}
fun getFirebaseToken() {
FirebaseMessaging.getInstance().token.addOnSuccessListener {
Log.d(TAG, "token=$it")
}
}
}
*/
class RetrofitInstance {
companion object {
private val retrofit bylazy{
// Create a new HttpLoggingInterceptor.
val logging = HttpLoggingInterceptor().apply{
level = HttpLoggingInterceptor.Level.BODY
}
// Add the interceptor to OkHttpClient.
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client) // Add the custom OkHttpClient.
.build()
}
val api bylazy{
retrofit.create(NotificationAPI::class.java)
}
}
}
data class PushNotification(
val data:NotificationData,
val to : String
)
data class NotificationData(
val title : String,
val nickname : String,
val message: String
)
data class NotificationData(
val title : String,
val nickname : String,
val message: String
)