# java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: SERVICE_NOT_AVAILABLE
๋ชจ๋ ๊ฑธ ๋ค ์ ์ค์ ํ๋๋ฐ ๋์ค๋ ์๋ฌ๋ฉ์์ง๋ค. ๊ณต๊ธฐ๊ณ๊ฐ ์ธํฐ๋ท์ ์ฐ๊ฒฐ๋์ด์์ง์์์ FCMํ ํฐ์ ๋ฐ๊ธ๋ฐ์ง ๋ชปํด ์๊ธด ๋ฌธ์ ์๋ค. ๊ณต๊ธฐ๊ณ์ ์์ดํ์ด๋ฅผ ์ผ์ฃผ๋ฉด ํด๊ฒฐ๋๋ ๋ฌธ์ .
class MyFirebaseMessageService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d(TAG, "onNewToken: $token")
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// remote์์ ๋ฉ์์ง๊ฐ ์ค๋ฉด
}
}
FirebaseMessagingService๋ฅผ ์์๋ฐ์ ๊ตฌํํ ํด๋์ค๋ก, ํ ํฐ์ด ์์ฑ๋๋ฉด onNewToken์ด ํธ์ถ๋๋ค. ํ ํฐ ์์ฑ์ ์๋ ์ฝ๋๋ก ํ๋ค. ๊ณต์๋ฌธ์์ ์ ํ์๋ ์ค๋ํซ ๊ทธ๋๋ก ๊ฐ๋ค๋จ๋ค.
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
return@OnCompleteListener
}
Log.d(TAG, "token: ${task.result ?: "task.result is null"}")
if (task.result != null) {
uploadToken(task.result!!)
}
})
# AndroidManifest.xml์ intent-filter ์ ์๋ฅผ ์ํ๋ค๋ฉด?
<service
android:name="com.example.fcm.MyFirebaseMessageService"
android:exported="true">
</service>
์ด๋ ๊ฒ ๋๊ณ ์๋ฒ์์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ฉด, ์๋น์ค๊ฐ ๋ฑ๋ก์ ๋์ด์์ง๋ง
์๋์ ๊ฐ์ ๋ฉ์์ง๊ฐ ๋์ค๋ฉด์ ๋ฐฑ๊ทธ๋ผ์ด๋์ ์ฑ์ด ๋ค์ด๊ฐ์์๋๋ง notification์ผ๋ก ํธ์์๋ฆผ์ด ์จ๋ค.
Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.
๋ฉ์์ง๊ฐ ๊ฐ์ง ๊ธฐ๋ณธ ์๋ฆผ ์ฑ๋(Notification Channel)์ ์ค์ ํด๋์ง ์์๋ค๋ฉด FCM์ ์ด ๋ฉ์์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด์ Miscellaneous๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ ์๋ ๊ธฐ๋ณธ ์ฑ๋์ ๋ง๋ค์ด์ ๊ฐ๋๋ค.
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id" />
๊ธฐ๋ณธ ์๋์ฑ๋์ ์ง์ ํ๋ ค๋ฉด ์ด๋ ๊ฒ name-value๋ก ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ฃผ๋ฉด๋๋ค.
ํฌ๊ทธ๋ผ์ด๋์์ ๋ญ ํ๋ ค๋ฉด ์ด๊ฑธ ํ์ฅํด์ ์จ์ผํ๊ณ , MESSAGING_EVENT ์ธํ ํธ ํํฐ๋ฅผ ๋ฌ์๋์ง์์ผ๋ฉด ๋ฉ์์ง๋ฅผ ๋ฐ๋ ํ์๋ฅผ ํ ์ ์๊ฒ ๋๋ค. ์ด ์ก์ ์ ๋ด๋ถ์ ์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ฐ์์ FirebaseMessagingService๋ฅผ ๋๋ฆฐ๋ค.
// Internal actions for routing intents from this receiver to services defined by API clients
static final String ACTION_MESSAGING_EVENT = "com.google.firebase.MESSAGING_EVENT";
@MainThread
Intent getMessagingEvent() {
return messagingEvents.poll();
}
/** Securely start the service identified by {@param action} with the provided {@param intent}. */
@MainThread
public int startMessagingService(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Starting service");
}
// As the services use to be exported and not protected by a permission, place the intent on a
// queue, then start the service with an empty intent telling it to check the queue.
messagingEvents.offer(intent);
Intent serviceIntent = new Intent(ACTION_MESSAGING_EVENT);
serviceIntent.setPackage(context.getPackageName());
return doStartService(context, serviceIntent);
}
๊ทธ๋์ ๋งจ ์์ ์๋ ์ฝ๋์ฒ๋ผ ๊ตฌํํด์ ์จ์ผ notification ๋ฉ์์ง, data ๋ฉ์์ง๋ฅผ ๊ตฌ๋ถํ ์ ์๋ค. ๋ค์ ๋ณด๋ฉด
class MyFirebaseMessageService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
Log.d(TAG, "onNewToken: $token")
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// remote์์ ๋ฉ์์ง๊ฐ ์ค๋ฉด
}
}
์ธ๋ถ์์ ๋ฉ์์ง๋ฅผ ๋ฐ์ FCM์ด JSON์ ์ ๋ฌํ๋ฉด onMessageReceived๊ฐ ํธ์ถ๋์ด remoteMessage์ notification ๋ฉค๋ฒ๋ฅผ ๋ณด๊ณ ๋ฉ์์ง ์ข ๋ฅ๋ฅผ ๊ตฌ๋ถํ ์ ์๊ฒ ๋๋ค.
# ์ ์ ๋ชจ๋(Doze) ์ํ์์ ์ฑ ๊นจ์ฐ๊ธฐ
์ด๊ฑฐ๋ ๊ฐ ์๋ฆผ ํ์ ์ Priority์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
- Normal
- ๋ฐ์ดํฐ๋ฉ์์ง์ ๊ธฐ๋ณธ๊ฐ์ด๋ค. ๊ธฐ๊ธฐ๊ฐ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ๋ชจ๋๋ผ๋ฉด ์ฆ์ ์๋ฆผ์ด ์ ์ก๋๊ณ , ์ ์๊ธฐ ๋ชจ๋๋ผ๋ฉด ์ ์๊ธฐ๋ชจ๋๋ฅผ ์ข ๋ฃํ ๋๊น์ง ์ง์ฐ๋๋ค ์ ์ก๋๋ฉฐ, ์ ์ ๋ชจ๋(doze)์ ๋ค์ด๊ฐ์ ๋๋ ์์ ์์ ๋์ง์๋๋ค.
- High
- Notification ๋ฉ์์ง์ ๊ธฐ๋ณธ๊ฐ์ด๋ค. FCM์์ ๊ธฐ๊ธฐ์ ์ ์ ๋ชจ๋๋ฅผ ํด์ ํ๊ณ ๋งค์ฐ ์ ํ๋ ๋คํธ์ํฌ ์ก์ธ์ค๋ฅผ ํฌํจํ์ฌ ์ ํ๋ ์ผ๋ถ ์ฒ๋ฆฌ ์์ ์ ์คํํ ์ ์๋ค.
notification์ด null์ด ์๋ ๊ฒฝ์ฐ์๋ ์์คํ ์ด ๊ฐ๋ก์ฑ๋ ๊ฒฝ์ฐ๊ณ , ์ด๋ ์๋ฆผ์ priority๋ high์ด๊ธฐ ๋๋ฌธ์ ์ด์ ์ ์ํ์ ๋ค์ด๊ฐ ์ฑ๋ ํธ์์๋ฆผ์ ๋ฐ์ ์ ์๋ค. ๊ทธ๋ฌ๋ ๋ฐ์ดํฐ ๋ฉ์์ง๋ผ๋ฉด ๊ธฐ๋ณธ priority๊ฐ normal์ด๊ธฐ ๋๋ฌธ์ ์๋ ์ฝ๋์ ๊ฐ์ด ์ฐ์ ์์๋ฅผ ์ฌ๋ ค์ค์ผํ๋ค.
val builder1 = NotificationCompat.Builder(this, MainActivity.channel_id)
.setSmallIcon(android.R.drawable.ic_dialog_info)
.setContentTitle(messageTitle)
.setContentText(messageContent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(mainPendingIntent)
๋ฌธ์ ๋ ์ ์กฐ์ฌ์ ๋ฐ๋ผ ์ ์๊ธฐ(doze)๋ชจ๋์ ์์ ์ด ๋ค์ด๊ฐ ์์ ์ ์๋ค๊ณ ํ๋ค...
Why Android does not exit DOZE mode, despite the high priority of the message in FCM?
I'm sending a data-message via FCM with HIGH priority. curl -X POST -H "Authorization: Bearer ya29.c.b0AXv..." -H "Content-Type: application/json" -d '{ "message": {...
stackoverflow.com
์ ์ ๋ชจ๋๋ก ๋ค์ด๊ฐ๋ฉด ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ฐ์ํ๋ ์ผ๋ค์ ์ง์ฐ์์ผฐ๋ค๊ฐ ์คํํ๊ณ , ์ด์ ์ ๋ชจ๋๋ก ๋ค์ด๊ฐ๋ฉด ๊ทธ๊ฑฐ๋ ๋ง์๋ฒ๋ฆฌ๋๋ฐ ์ด์ ์ ๋ชจ๋๋ก ๋ค์ด๊ฐ๋ ๊ฒ์ ๋ง์ผ๋ ค๋ฉด ๋ฐฐํฐ๋ฆฌ ์ต์ ํํ์ง ์์ ๋์์ผ๋ก ์ถ๊ฐํ๋๊ฐ(whitelist๊ฐ๋ )
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
JobSchedueler๋ก ์ถ๊ฐํด์ผ๋๋ค.
ํ์คํ์ง์์ง๋ง FCM, ๊ฑฐ๊ธฐ์๋ notification ๋ฉ์์ง์ ํํด์ ์ด์ ์ ๋ชจ๋์ฌ๋ ์ ๊ทผํ ์ ์๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
์ฐ์ ์์์ ๊ด๋ จํด์ ์์ธํ ๋ถ๋ถ์ ๋ฌธ์๋ฅผ ์ฝ์ด๋ณด๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
https://developer.android.com/about/versions/pie/power?hl=ko
์ ์ ๊ด๋ฆฌ | Android ๊ฐ๋ฐ์ | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ์ ์ ๊ด๋ฆฌ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. Android 9(API ๋ ๋ฒจ 28)์์๋ ๊ธฐ๊ธฐ ์ ์ ๊ด๋ฆฌ๋ฅผ
developer.android.com
๋์์ด ๋๋ค๋ฉด ๋๊ธ์ด๋ ๊ณต๊ฐ ๋ฒํผ ํ ๋ฒ์ฉ ๋๋ฅด๊ณ ๊ฐ์ฃผ์ธ์! ๋ก๊ทธ์ธ ์ํด๋ ๋ฉ๋๋ค ^_^
'Android ๐ฅ๏ธ > ์ฝ์งโ๏ธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Location Service ์ฝ์งํ๊ธฐ - ๋ด ์์น ๋ฐ์์ค๊ธฐ (0) | 2024.05.03 |
---|---|
Firebase CloudFunction ์ฝ์ง + FCM(1) (0) | 2024.04.21 |
LiveData ์์๋ณด๊ธฐ (0) | 2024.04.10 |
์ง๋ ฌํ - Parcelize, Parcelable, Serializable (0) | 2024.04.05 |
์๋๋ก์ด๋ ๋ฌดํ์คํฌ๋กค ๊ธฐ์ด - Infinite Scroll, Endless Scroll (0) | 2024.04.03 |