Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

부산대 Android_이창욱_6주차_과제_step2 #56

Open
wants to merge 8 commits into
base: ichanguk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@

![week6_1](https://github.com/user-attachments/assets/69e03c8f-851a-4d65-89fb-cb556d7b1d61)

- 서비스 비활성화 상태 화면
## 푸시 알림

![splash_error](https://github.com/user-attachments/assets/692f95a0-077e-484d-b840-85036e72252f)
앱 실행 중 알림               백그라운드 알림

- 인증 에러시 화면

![week4_1](https://github.com/user-attachments/assets/7c9bc6f0-c163-4058-83cc-1299120c7230)
![week6_noti_fore](https://github.com/user-attachments/assets/ec18e78b-fe9e-490d-9a10-bc2f31aad907) ![week6_noti_back](https://github.com/user-attachments/assets/ae65f018-877d-438e-8067-ce8296d4c00b)

## 에러 화면

서비스 비활성화 상태 화면          인증 에러시 화면

![splash_error](https://github.com/user-attachments/assets/692f95a0-077e-484d-b840-85036e72252f) ![week4_1](https://github.com/user-attachments/assets/7c9bc6f0-c163-4058-83cc-1299120c7230)

## flow chart

Expand Down
9 changes: 9 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
<activity
android:name=".ui.search.SearchActivity"
android:exported="true" />

<service
android:name=".data.network.service.MapFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package campus.tech.kakao.map.data.network.service

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.app.NotificationCompat
import campus.tech.kakao.map.R
import campus.tech.kakao.map.ui.splash.SplashActivity
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class MapFirebaseMessagingService : FirebaseMessagingService() {
private lateinit var notificationManager: NotificationManager
private val TAG = "FirebaseService"

override fun onNewToken(token: String) {
Log.d(TAG, "Refreshed token: $token")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onNewToken 은 갱신된 토큰이 내려오는 편이에요. 보통 data store 등에 저장해두었다가 서버에 보내는 작업을 진행하기도 합니다.

}

override fun onMessageReceived(remoteMessage: RemoteMessage) {
sendNotification(remoteMessage)
}

private fun sendNotification(remoteMessage: RemoteMessage) {
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
createNotificationChannel()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notification channel 은 매번 처리하기보다, 한번만 처리하는 편이 좋을 것 같네요!

val pendingIntent = createPendingIntent()
val notification = buildNotification(remoteMessage, pendingIntent)

notificationManager.notify(NOTIFICATION_ID, notification)
}

private fun buildNotification(remoteMessage: RemoteMessage, pendingIntent: PendingIntent): Notification {
return NotificationCompat.Builder(
this,
CHANNEL_ID,
)
.setSmallIcon(R.drawable.ic_kakaomap)
.setContentTitle("[포그라운드 알림] ${remoteMessage.notification?.body}")
.setContentText(getString(R.string.notification_content))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setStyle(
NotificationCompat.BigTextStyle()
.bigText(getString(R.string.notification_big_text)),
)
.setAutoCancel(true)
.build()
}

private fun createPendingIntent(): PendingIntent {
val intent = Intent(this, SplashActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
}

private fun createNotificationChannel() {
val descriptionText = getString(R.string.fcm_channel_description)
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT,
).apply {
description = descriptionText
}
notificationManager.createNotificationChannel(channel)
}

fun getFirebaseToken() {
FirebaseMessaging.getInstance().token.addOnSuccessListener {
Log.d(TAG, "token=$it")
}
}
Comment on lines +75 to +79
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하지 않는 코드인것 같네요!


companion object {
private const val NOTIFICATION_ID = 222222
private const val CHANNEL_ID = "main_default_channel"
private const val CHANNEL_NAME = "main channelName"
}
}
61 changes: 60 additions & 1 deletion app/src/main/java/campus/tech/kakao/map/ui/map/MapActivity.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package campus.tech.kakao.map.ui.map

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
Expand Down Expand Up @@ -40,6 +47,16 @@ class MapActivity : AppCompatActivity() {
private lateinit var searchActivityResultLauncher: ActivityResultLauncher<Intent>

private val locationViewModel: LocationViewModel by viewModels()
private val TAG = "MapActivity"
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
if (isGranted) {
Log.i(TAG, getString(R.string.notification_permission_granted_log))
} else {
Log.i(TAG, getString(R.string.notification_permission_denied_log))
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -50,6 +67,7 @@ class MapActivity : AppCompatActivity() {
startMapView()
setSearchBoxClickListener()
setSearchActivityResultLauncher()
askNotificationPermission()
}

/**
Expand Down Expand Up @@ -250,7 +268,7 @@ class MapActivity : AppCompatActivity() {
* Kakao 지도 API 준비가 완료되었을 때 호출되는 로깅 함수.
*/
private fun logMapReady() {
Log.d("MapActivity", "onMapReady called")
Log.d("MapActivity", getString(R.string.map_destroy_log))
}

@Override
Expand Down Expand Up @@ -283,4 +301,45 @@ class MapActivity : AppCompatActivity() {
}
}
}

/**
* 알림 권한 요청 함수.
*/
private fun askNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS,
) == PackageManager.PERMISSION_GRANTED
) {
Log.i(TAG, getString(R.string.notification_permission_already_granted))
} else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
showNotificationPermissionDialog()
} else {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}

/**
* 알림 권한 요청 이유를 설명하는 다이얼로그 표시 함수.
*/
private fun showNotificationPermissionDialog() {
AlertDialog.Builder(this).apply {
setMessage(
getString(
R.string.notification_permission_request_message,
getString(R.string.app_name),
),
)
setPositiveButton(getString(R.string.yes)) { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}
setNegativeButton(getString(R.string.deny_notification_permission)) { _, _ -> }
show()
}
}
}
Binary file added app/src/main/res/drawable/ic_kakaomap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,17 @@
<string name="bottom_sheet_place_name">부산대 컴공관</string>
<string name="bottom_sheet_place_address">부산광역시 금정구 부산대학로 63번길 2</string>
<string name="map_error_description">지도 인증을 실패했습니다.\n다시 시도해 주세요.</string>
<string name="yes">허용</string>
<string name="deny_notification_permission">허용 안함</string>
<string name="fcm_channel_description">fcm chennel description</string>
<string name="notification_content">앱이 실행중입니다.</string>
<string name="notification_big_text">앱이 실행 중일 때는 포그라운드 알림이 발생합니다.</string>
<string name="map_destroy_log">onMapDestroy called</string>
<string name="map_error_log">onMapError: %1$s</string>
<string name="map_ready_log">onMapReady called</string>
<string name="notification_permission_granted_log">알림 권한이 허용되었습니다. FCM SDK 및 앱에서 알림을 게시할 수 있습니다.</string>
<string name="notification_permission_denied_log">알림 권한이 거부되었습니다. 앱에서 알림을 표시하지 않습니다.</string>
<string name="notification_permission_already_granted">알림 권한이 이미 허용되어 있습니다.</string>
<string name="notification_permission_request_message">다양한 알림 소식을 받기 위해 권한을 허용하시겠어요?\n(알림 설정에서 %1$s의 알림 권한을 허용해주세요.)</string>

</resources>