반응형

1. 앱 실행화면
- 알림 발생 버튼을 누르면

- 알림이 발생하고

- 답장을 누르면 아래와 같이 글씨가 써지고 전송 버튼이 활성화됨

2. 프로젝트 구성
- MainActivity
- ReplyReceiver(브로드캐스트 리시버)
- drawable 폴더(사진 및 이미지들)
- build.gradle.kts 파일 수

3. build.gradle.kts
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
}
android {
namespace = "com.example.ch10_notification"
compileSdk = 35
viewBinding.isEnabled = true //여기 추가됨
defaultConfig {
applicationId = "com.example.ch10_notification"
minSdk = 35
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}
4. activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:id="@+id/main">
<Button
android:id="@+id/notificationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="알림 발생"/>
</LinearLayout>
5. MainActivity.kt
package com.example.ch10_notification
// 패키지 이름 정의. 앱 고유의 네임스페이스 역할을 함.
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.media.AudioAttributes
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationCompat
import androidx.core.app.RemoteInput
import androidx.core.content.ContextCompat
import com.example.ch10_notification.databinding.ActivityMainBinding
// 필요한 클래스들을 import. (알림, 권한 체크, 바인딩 등)
class MainActivity : AppCompatActivity() {
// MainActivity: 앱이 실행되면 가장 먼저 보여지는 화면(Activity)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 액티비티 생성 시 최초 실행되는 메서드
val binding = ActivityMainBinding.inflate(layoutInflater)
// activity_main.xml을 기반으로 자동 생성된 바인딩 클래스 인스턴스 생성
// layoutInflater가 XML을 실제 View 객체로 변환해줌
setContentView(binding.root)
// 변환된 뷰를 현재 액티비티 화면에 표시
// 권한 요청 런처: POST_NOTIFICATIONS 권한을 동적으로 요청할 때 사용
val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) {
// 요청 결과 콜백 (it은 Map<String, Boolean>)
if (it.all { permission -> permission.value == true }) {
// 모든 권한이 승인되면 알림 실행
noti()
} else {
// 거부되면 Toast로 메시지 표시
Toast.makeText(this, "permission denied...", Toast.LENGTH_SHORT).show()
}
}
// 버튼 클릭 이벤트
binding.notificationButton.setOnClickListener {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13 (API 33) 이상에서는 POST_NOTIFICATIONS 권한이 필요
if (ContextCompat.checkSelfPermission(
this,
"android.permission.POST_NOTIFICATIONS"
) == PackageManager.PERMISSION_GRANTED
) {
// 권한 이미 허용됨 → 알림 실행
noti()
} else {
// 권한 요청 실행
permissionLauncher.launch(
arrayOf("android.permission.POST_NOTIFICATIONS")
)
}
} else {
// Android 12 이하 → 권한 필요 없음
noti()
}
}
}
fun noti(){
// 실제 알림(Notification)을 만드는 함수
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
// NotificationManager: 알림을 관리하는 시스템 서비스
val builder: NotificationCompat.Builder
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// Android 8.0 (API 26) 이상 → NotificationChannel 필요
val channelId="one-channel"
val channelName="My Channel One"
val channel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_DEFAULT
).apply {
// 채널 설정
description = "My Channel One Description" // 설명
setShowBadge(true) // 앱 아이콘에 뱃지 표시 허용
// 기본 알림 사운드 지정
val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val audioAttributes = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
setSound(uri, audioAttributes)
enableVibration(true) // 진동 허용
}
manager.createNotificationChannel(channel)
// 채널을 NotificationManager에 등록
builder = NotificationCompat.Builder(this, channelId)
// 채널 ID를 연결해서 빌더 생성
} else {
// Android 7.1 이하 → 채널 필요 없음
builder = NotificationCompat.Builder(this)
}
// 알림의 기본 정보 설정
builder.run {
setSmallIcon(R.drawable.small) // 작은 아이콘
setWhen(System.currentTimeMillis()) // 알림 발생 시간
setContentTitle("홍길동") // 제목
setContentText("안녕하세요.") // 내용
setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.big)) // 큰 아이콘
}
// ---- 인라인 답장(RemoteInput) 설정 ----
val KEY_TEXT_REPLY = "key_text_reply" // 입력값 키
var replyLabel = "답장" // 답장 라벨
var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
setLabel(replyLabel) // 입력창에 표시될 힌트
build()
}
// 답장 동작을 받을 BroadcastReceiver 지정
val replyIntent = Intent(this, ReplyReceiver::class.java)
// PendingIntent: 나중에 실행할 Intent를 감싸는 객체
val replyPendingIntent = PendingIntent.getBroadcast(
this, 30, replyIntent, PendingIntent.FLAG_MUTABLE
)
// 알림에 "답장" 액션 추가
builder.addAction(
NotificationCompat.Action.Builder(
R.drawable.send, // 액션 아이콘
"답장", // 버튼 텍스트
replyPendingIntent // 실행할 인텐트
).addRemoteInput(remoteInput).build() // RemoteInput 연결
)
// 알림 표시 (id = 11)
manager.notify(11, builder.build())
}
}
6. ReplyReceiver.kt
package com.example.ch10_notification
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.RemoteInput
class ReplyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// 알림에서 사용자가 입력한 글자 획득
val replyTxt = RemoteInput.getResultsFromIntent(intent)
?.getCharSequence("key_text_reply")
// 입력된 답장을 로그로 출력
Log.d("kkang", "replyTxt : $replyTxt")
// 알림 취소 (id = 11인 알림 제거)
val manager = context.getSystemService(
AppCompatActivity.NOTIFICATION_SERVICE
) as NotificationManager
manager.cancel(11)
}
}
출처 : https://kkangsnote.tistory.com/
'프로그래밍 > 안드로이드(코틀린)' 카테고리의 다른 글
| 안드로이드 2 - 다양한 언어 지원 앱 및 가로 화면 만들기 예제 (1) | 2024.08.31 |
|---|---|
| 안드로이드 1 - 스톱워치 기능 만들기 예제 (0) | 2024.08.25 |