๐ SeSAC์ 'JetPack๊ณผ Kotlin์ ํ์ฉํ Android App ๊ฐ๋ฐ' ๊ฐ์ข๋ฅผ ์ ๋ฆฌํ ๊ธ ์ ๋๋ค.
์ํ๋ฐฉ์ ์ฑ์ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๊ฒ์ ์๋ฆผ(Notifiaction) ์ด๋ผ๊ณ ํ๋ค.
์ํ๋ฐ๋ ์์คํ ์ ์ํด ๊ด๋ฆฌ๋๋ ๊ณณ
์ฑ์ด ์ง์ ์ ์ด ๋ถ๊ฐ
์ฑ์ ์ํ๋ฅผ ์ํ๋ฐ์ ์ถ๋ ฅํด ์ ์ ์๊ฒ ๋ฌด์ธ๊ฐ์ ์ํฉ์ ์๋ ค์ฃผ๋ ๊ธฐ๋ฅ
์ฑ์ด ์์ ์ ์กํฐ๋นํฐ๋ฅผ ์ถ๋ ฅํ๊ณ ์๋ ์ํฉ์ด๋ฉด ๊ตณ์ด ์๋ฆผ์ ๋ฐ์ํ ํ์๊ฐ ์๋ค.
๊ทธ๋์ ์ฃผ๋ ฅ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด Receiver ํน์ Service ์ด๋ค.
์๋ฆผ์ NotificationManager ์ notify() ํจ์๋ก ๋ฐ์
Notification ๊ฐ์ฒด๋ NotificationCompat.Builder ์ ์ํด ์์ฑ
NotificationChannel ๋ก NotificationCompat.Builder ์์ฑ
NotificationCompat.Builder ๊ฐ ํ์ํ๋ฐ Builder ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ด API Level 26(Android 8) ๋ฒ์ ๋ถํฐ ๋ณ๊ฒฝ
API 26๋ถํฐ Channel ๊ฐ๋ ์ด ๋์ ๋๋ฉด์ ๋ถ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ด์ผ ํ๋ค.
1. `Mnanger` ๊ฐ `notify()` ๋ก ์๋ฆผ์ ๋ฐ์
2. ์ด ์๋ฆผ ๋ด์ฉ์ `Notification ๊ฐ์ฒด` ๊ฐ ๊ฐ์
3. ์ด ๊ฐ์ฒด๋ฅผ `Builder` ๊ฐ ์์ฑ
4. ์ด Builder ๋ฅผ ๋ง๋ค ๋ `Channel` ๊ฐ๋
์ด ๋์
๋จ
Builder(context: Context!) - API Level 26(Android 8) ์ด์ ๋ฒ์
Builder(context: Context!, channelId: String!) - API Level 26(Android 8) ๋ถํฐ
API 26 ์ด์ ์๋ ๊ทธ๋ฅ Context ๋ง ์ฃผ๋ฉด ์๋ฆผ์ ๋ง๋ค ์ ์์๋ค.
๊ทธ๋ฐ๋ฐ์ฑ๋
๊ฐ๋ ์ด์ด ๋์ ๋๋ฉด์์ฑ๋
์ ๊ฐ์ด ๋์ ธ ์ฃผ์ด์ผ ํ๋ค.
ํธ๋ํฐ ํ๊ฒฝ ์ค์ ์์ ์ฑ์ ๋ํ ์๋ฆผ์ ์ ์ดํ ์ ์๋๋ฐ, ์ฑ๋ ๋์ ์ด์ ์๋ ๊ทธ๋ฅ
์ฑ ์์ฒด
๊ฐ ๋์์ด์๋ค. ๊ทธ๋ฐ๋ฐ ์ฑ์์ ๋ณด๋ด๋ ์๋ฆผ์ ์ข ๋ฅ๊ฐ ์ฌ๋ฌ๊ฐ์ง๋ค. ๊ทธ๋์ ์ฑ์์ ๋ณด๋ด๋ ๊ฐ๊ฐ์ ์๋ฆผ์ ์ ์ดํ ์ ์๊ฒ๋ ๋์ ๋ ๊ฐ๋ ์ด์ฑ๋
์ด๋ค.
NotificationChannel(id: String!, name: CharSequence!, importance: Int)
์ํ๋ | ๋ด์ฉ |
---|---|
NotificationManager.IMPORTANCE_HIGH | ๊ธด๊ธ ์ํฉ์ด๋ฉฐ ์๋ฆผ์์ด ์ธ๋ฆฌ๋ฉฐ ํค๋์ ์ผ๋ก ํ์ |
NotificationManager.IMPORTANCE_DEFAULT | ๋์ ์ค์๋์ด๋ฉฐ ์๋ฆผ์์ด ์ธ๋ฆผ |
NotificationManager.IMPORTANCE_LOW | ์ค๊ฐ ์ค์๋์ด๋ฉฐ ์๋ฆผ์์ด ์ธ๋ฆฌ์ง ์์ |
NotificationManager.IMPORTANCE_MIN | ๋ฎ์ ์ค์๋์ด๋ฉฐ ์๋ฆผ์์ด ์๊ณ ์ํํ์์ค์ ํ์๋์ง ์์ |
builder.setSmallIcon(android.R.drawable.ic_notification_overlay)
builder.setWhen(System.currentTimeMillis())
builder.setContentTitle("Content Title")
builder.setContentText("Content Massage")
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<?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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="notification"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.kotdev99.android.c74
class MainActivity : AppCompatActivity() {
private lateinit var btn: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn = findViewById(R.id.button)
btn.setOnClickListener {
initNotification()
}
}
private fun initNotification() {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val builder: NotificationCompat.Builder
// channel ์ ๋ณด ์
๋ ฅ
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "one-channel"
val channelName = "My One Channel"
val channel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_HIGH
)
// channel ์ ์ฃผ๋ ์ ๋ณด
channel.description = "My Channel One Description" // ํ๊ฒฝ์ค์ ์ ์ถ๋ ฅ๋๋ ์ค๋ช
channel.setShowBadge(true)
val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val audio = AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
channel.setSound(uri, audio)
channel.enableLights(true) // ์๋ฆผ ์์ ๋น๋จ (์ ๊ณต ์ฌ๋ถ๋ ๊ธฐ์ข
์ ๋ฐ๋ผ ๋ค๋ฆ)
channel.lightColor = Color.RED // ๋ถ๋น ์์
channel.enableVibration(true)
channel.vibrationPattern = longArrayOf(100, 200, 100, 200)
manager.createNotificationChannel(channel)
builder = NotificationCompat.Builder(this, channelId)
} else {
builder = NotificationCompat.Builder(this)
}
builder.setSmallIcon(android.R.drawable.ic_notification_overlay)
builder.setWhen(System.currentTimeMillis())
builder.setContentTitle("Title")
builder.setContentText("message")
manager.notify(1, builder.build())
}
}
static fun getActivity(context: Context!, requestCode: Int, intent: Intent!, flags: Int)
: PendingIntent!
static fun getBroadcast(context: Context!, requestCode: Int, intent: Intent!, flags: Int)
: PendingIntent!
static fun getService(context: Context!, requestCode: Int, intent: Intent!, flags: Int)
: PendingIntent!
์ธํ ํธ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋๋ฐ ์์ง ๋ฐ์ํ์ง ์์ ์ธํ ํธ.
PendingIntent ๋ก ์์คํ ์ ๋ฑ๋กํ๋ฉด, ์์คํ ์์ ์ค์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ PendingIntent ๋ด์ฉ ๋๋ก ์ธํ ํธ๋ฅผ ๋ฐ์์ํจ๋ค.
val intent = Intent(this, DetailActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(pendingIntent)
์๋ฆผ์ ์ต๋ 3๊ฐ๊น์ง์ ์ ์ ์ด๋ฒคํธ๋ฅผ ์ํ ์ก์ ์ ์ถ๊ฐ
๋ง์ฐฌ๊ฐ์ง๋ก ์ธํ ํธ ๋ด์ฉ์ ์ฐ๋ฆฌ๊ฐ ์ค๋นํ ์ ์์ง๋ง, ์ธํ ํธ ๋ฐ์์ ์์คํ ์์ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ PendingIntent ๋ก ์๋ขฐํ๋ค.
val actionIntent = Intent(this, DetailActivity::class.java)
val actionPendingIntent
= PendingIntent.getActivity(this, 20, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT)
builder.addAction(
NotificationCompat.Action.Builder(
android.R.drawable.stat_notify_more,
"Action",
actionPendingIntent
).build()
)
builder.setProgress(100, 0, false) // (max, min, Boolean)
manager.notify(11, builder.build())
thread {
for (i in 1..100) {
builder.setProgress(100, i, false)
manager.notify(11, builder.build())
SystemClock.sleep(100)
}
}
// BigPicture Style ์์
val bigPicture = BitmapFactory.decodeResource(resources.R.drawable.logo_1)
val bigStyle = NotificationCompat.BigPictureStyle()
bigStyle.bigPicture(bigPicture)
builder.setStyle(bigStyle)
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<?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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="notification"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.kotdev99.android.c75
class MainActivity : AppCompatActivity() {
private lateinit var btn: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn = findViewById(R.id.button)
btn.setOnClickListener {
initNotification()
}
}
// Notification ๊ตฌํ
private fun initNotification() {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "one"
val channelName = "channel name"
val channel = NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_HIGH
)
channel.description = "one description"
manager.createNotificationChannel(channel)
builder = NotificationCompat.Builder(this, channelId)
} else {
builder = NotificationCompat.Builder(this)
}
builder.setSmallIcon(android.R.drawable.ic_notification_overlay)
builder.setWhen(System.currentTimeMillis())
builder.setContentTitle("Title")
builder.setContentText("Text")
pendingIntent(builder)
manager.notify(1, builder.build())
}
// PendingIntent ๊ตฌํ
private fun pendingIntent(builder: NotificationCompat.Builder) {
// ์๋ฆผ PendingIntent
val actionIntent = Intent(this, DetailActivity::class.java)
val actionPending =
PendingIntent.getActivity(
this, 20, actionIntent,
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
builder.setContentIntent(actionPending)
// Action PendingIntent
val actionIntent2 = Intent(this, DetailActivity::class.java)
val actionPending2 =
PendingIntent.getActivity(
this, 20, actionIntent2,
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
builder.addAction(
NotificationCompat.Action.Builder(
android.R.drawable.stat_notify_more,
"Action",
actionPending2
).build()
)
// BigPicture Style
val bigPicture = BitmapFactory.decodeResource(resources, R.drawable.logo_1)
val style = NotificationCompat.BigPictureStyle()
style.bigPicture(bigPicture)
builder.setStyle(style)
}
}