๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Notifications - PendingIntent

interfacer_han 2024. 6. 12. 22:51

#1 ์ด์ „ ๊ธ€

 

[Android] Notifications - ๊ธฐ์ดˆ

#1 ๊ฐœ์š” ์•Œ๋ฆผ ๊ฐœ์š”  |  Views  |  Android Developers์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ ๊ฐœ์š” ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ

kenel.tistory.com

์œ„ ๊ฒŒ์‹œ๊ธ€์˜ ์™„์„ฑ๋œ ์•ฑ์„ ์ผ๋ถ€ ์ˆ˜์ •ํ•ด์„œ, ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ํด๋ฆญ ์‹œ์˜ ๋™์ž‘์„ ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค.
 

#2 PendingIntent

 

PendingIntent  |  Android Developers

 

developer.android.com

Intent๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์ปดํฌ๋„ŒํŠธ(Activity, Service, BroadcastReceiver, ContentProvider) ๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์‹œ์ง€ ๊ฐ์ฒด๋‹ค. PendingIntent๋Š” ๋‚˜์ค‘์— ์‹คํ–‰๋  Intent๋ฅผ ํฌ์žฅ(Wrapping)ํ•˜๋Š” ๊ฐ์ฒด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒํƒœ๋ฐ”์— ์˜ฌ๋ผ๊ฐˆ ์•Œ๋ฆผ(Notifications) ๋ฉ”์‹œ์ง€์— PendingIntent๋ฅผ ๋‹ฌ์•„์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ํ•ด๋‹น ๋ฉ”์‹œ์ง€๋ฅผ ํด๋ฆญํ•  ๋•Œ์˜ ๋™์ž‘์„ ๊ตฌํ˜„ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. PendingIntent๊ฐ€ ์—†๋‹ค๋ฉด, ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๋ฅผ ํด๋ฆญํ•ด๋„ ์•„๋ฌด๋Ÿฐ ๋ฐ˜์‘์ด ์—†๋‹ค.
 

#3 ์ฝ”๋“œ ์ˆ˜์ • - Tab behavior

#3-1 ๊ฐœ์š”

 

์•Œ๋ฆผ ๋งŒ๋“ค๊ธฐ  |  Views  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ ๋งŒ๋“ค๊ธฐ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. ์•Œ๋ฆผ์€ ์‚ฌ์šฉ ์ค‘์ด ์•„๋‹Œ ์•ฑ์˜ ์ด๋ฒคํŠธ์— ๊ด€

developer.android.com

์ƒํƒœ๋ฐ”์˜ ์•Œ๋ฆผ ํŒจ๋„์„ ํด๋ฆญ(Tab)ํ•˜๋ฉด ๋ฐ˜์‘(ํŠน์ • ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ ์ด๋™)ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.
 

#3-2 MainActivity.kt ์ˆ˜์ •

...

class MainActivity : AppCompatActivity() {

    ...
    private val channelId = "com.example.pendingintent.channel1"
    private val myRequestCode1 = 12345

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
    }

    private fun displayNotification() {
        val notificationId = ...

        val tabBehavior = getSecondActivityPendingIntent()

        val notification = NotificationCompat.Builder(this@MainActivity, channelId).apply {
            ...
            setContentIntent(tabBehavior)
        }.build()

        notificationManager?.notify(notificationId, notification)
    }

    private fun getSecondActivityPendingIntent(): PendingIntent {
        val intent = Intent(this, SecondActivity::class.java)
        return PendingIntent.getActivity(
            this, myRequestCode1, intent, PendingIntent.FLAG_IMMUTABLE
        )
    }

    ...
}

์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. PendingIntent.getActivity()์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” Context, ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” ์„œ๋กœ ๋‹ค๋ฅธ PendingIntent๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ Intํ˜• Id๊ฐ’ (๋‚˜๋Š” ์•„๋ฌด ์ˆซ์ž์ธ 12345๋ฅผ ๋„ฃ์—ˆ๋‹ค), ์„ธ๋ฒˆ์งธ ์ธ์ž๋Š” Intent, ๋„ค๋ฒˆ์งธ ์ธ์ž๋Š” PendingIntent์˜ ์†์„ฑ์„ ์ •์˜ํ•˜๋Š” Intํ˜• ์ƒ์ˆ˜๋‹ค. FLAG_IMMUTABLE์€ ๋งˆ์น˜ valํ˜• ๋ณ€์ˆ˜์˜ ๋ถˆ๋ณ€์ (Immutable) ์„ฑ๊ฒฉ๊ณผ ๋น„์Šทํ•œ ๋งฅ๋ฝ์œผ๋กœ, ์œ„ ์ฝ”๋“œ ์† PendingIntent์— ์ƒˆ๋กœ์šด Intent๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋งŒ๋“œ๋Š” ๋“ฑ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“œ๋Š” ํ”Œ๋ž˜๊ทธ๋‹ค.
 

#3-3 activity_second.xml ์ƒ์„ฑ

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SecondActivity"
        android:textSize="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

๊ฐ„๋‹จํ•œ View.
 

#3-4 SecondActivity.kt ์ƒ์„ฑ

// package com.anushka.notificationdemo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
    }
}

๋น„์–ด์žˆ๋Š” Activity.
 

#3-5 AndroidMenifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    ...

    <application
        ...>
        <activity
            android:name=".SecondActivity"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

AndroidMenifest.xml์— SecondActivity๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
 

#3-6 ์ž‘๋™ ํ™•์ธ

๋งŒ์•ฝ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋„ ์•Œ๋ฆผ์ด ๋œจ์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์„ค์น˜๋œ ์•ฑ์˜ ์•Œ๋ฆผ ๊ถŒํ•œ์ด ์ฐจ๋‹จ๋˜์ง€๋Š” ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž. ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •์ด ์ฐจ๋‹จ์ธ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
 

#4 ์ฝ”๋“œ ์ˆ˜์ • - Action Button

#4-1 ๊ฐœ์š”

 

NotificationCompat.Action  |  Android Developers

androidx.appsearch.builtintypes.properties

developer.android.com

์ƒํƒœ๋ฐ”์˜ ์•Œ๋ฆผ ํŒจ๋„์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ Action Button์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ๋‚ด๋ถ€์ ์ธ ์ฝ”๋“œ๋Š” #3๊ณผ ๊ฑฐ์˜ ๊ฐ™๋‹ค. #3๊ณผ์˜ ์ฐจ์ด๋Š” ์•Œ๋ฆผ ํŒจ๋„์— ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ๋ฒ„ํŠผ์ด ์กด์žฌํ•˜๋ฉฐ, ๊ฐ ๋ฒ„ํŠผ์— ์„œ๋กœ ๋‹ค๋ฅธ PendingIntent๋ฅผ ๋„ฃ์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.
 

#4-2 MainActivity.kt ์ˆ˜์ •

...

class MainActivity : AppCompatActivity() {

    ...
    private val myRequestCode2 = 12346
    private val myRequestCode3 = 12347

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
    }

    private fun displayNotification() {
        val notificationId = ...

        val tabBehavior = getSecondActivityPendingIntent()
        val actionButton1 = getThirdActivityAction()
        val actionButton2 = getFourthActivityAction()

        val notification = NotificationCompat.Builder(this@MainActivity, channelId).apply {
            ...
            setContentIntent(tabBehavior)
            addAction(actionButton1)
            addAction(actionButton2)
        }.build()

        notificationManager?.notify(notificationId, notification)
    }

    private fun getSecondActivityPendingIntent(): PendingIntent {
        ...
    }

    private fun getThirdActivityAction(): NotificationCompat.Action {
        val intent = Intent(this, ThirdActivity::class.java)
        val pendingIntent: PendingIntent = PendingIntent.getActivity(
            this, myRequestCode2, intent, PendingIntent.FLAG_IMMUTABLE
        )
        return NotificationCompat.Action.Builder(0, "Go Third", pendingIntent).build()
    }

    private fun getFourthActivityAction(): NotificationCompat.Action {
        val intent = Intent(this, FourthActivity::class.java)
        val pendingIntent: PendingIntent = PendingIntent.getActivity(
            this, myRequestCode3, intent, PendingIntent.FLAG_IMMUTABLE
        )
        return NotificationCompat.Action.Builder(0, "Go Fourth", pendingIntent).build()
    }

    ...
}

Action ๋ฒ„ํŠผ์€ NotificationCompat.Action์˜ ๋นŒ๋” ํด๋ž˜์Šค์ธ NotificationCompat.Action.Builder๋ฅผ ํ†ตํ•ด ๋งŒ๋“ ๋‹ค. ํ•ด๋‹น ํด๋ž˜์Šค ์ƒ์„ฑ์ž์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ์•„์ด์ฝ˜(IconCompat), ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” Action ๋ฒ„ํŠผ์˜ ์ œ๋ชฉ, ์„ธ๋ฒˆ์งธ ์ธ์ž๋Š” PendingIntent๋‹ค.
 

#4-3 ThirdActivity์™€ FourthActivity ๊ด€๋ จ ์ฝ”๋“œ

์ฝ”๋“œ ์ƒ๋žต

#3-3 ~ #3-5์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ, ThirdActivity ๋ฐ FourthActivity ๊ทธ๋ฆฌ๊ณ  ๊ฐ๊ฐ์˜ View๋ฅผ ๋งŒ๋“ ๋‹ค. AndroidManifest์— ๋งŒ๋“  Activity๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ์žŠ์ง€ ๋ง์ž.
 

#4-4 ์ž‘๋™ ํ™•์ธ

 

#4-5 ํ•„์š”ํ•œ ๊ฐœ์„ ์ 

Action Button์„ ํด๋ฆญํ•ด๋„, Notification์ด ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. Action Button์ด ์•„๋‹ˆ๋ผ Notification ์ž์ฒด๋ฅผ Tabํ–ˆ์„ ๋•Œ Notification์ด ์ž˜๋งŒ ์‚ฌ๋ผ์ง€๋˜ ๊ฒƒ๊ณผ๋Š” ๋Œ€์กฐ์ ์ด๋‹ค. ์ด์–ด์ง€๋Š” ๊ฒŒ์‹œ๊ธ€(#7 ์ฐธ์กฐ)์—์„œ ํ•ด๋‹น ๋™์ž‘์„ ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค.
 

#5 ์š”์•ฝ

PendingIntent๋Š” ์–ด๋–ค ๊ฒƒ์— ๋งค๋‹ฌ๊ธฐ(Pend) ์œ„ํ•œ Intent๋‹ค.
 

#6 ์™„์„ฑ๋œ ์•ฑ

 

android-practice/notifications/PendingIntent at master · Kanmanemone/android-practice

Contribute to Kanmanemone/android-practice development by creating an account on GitHub.

github.com

 

#7 ์ด์–ด์ง€๋Š” ๊ธ€

 

[Android] Notifications - Action ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์•Œ๋ฆผ Cancel

#1 ์ด์ „ ๊ธ€ [Android] Notifications - PendingIntent#1 ์ด์ „ ๊ธ€ [Android] Notifications - ๊ธฐ์ดˆ#1 ๊ฐœ์š” ์•Œ๋ฆผ ๊ฐœ์š” | Views | Android Developers์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•Œ๋ฆผ ๊ฐœ์š” ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉ

kenel.tistory.com