04
16

# 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)๋ชจ๋“œ์— ์ˆ˜์ •์ด ๋“ค์–ด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค...

https://stackoverflow.com/questions/73404037/why-android-does-not-exit-doze-mode-despite-the-high-priority-of-the-message-in

 

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

๋„์›€์ด ๋๋‹ค๋ฉด ๋Œ“๊ธ€์ด๋‚˜ ๊ณต๊ฐ ๋ฒ„ํŠผ ํ•œ ๋ฒˆ์”ฉ ๋ˆ„๋ฅด๊ณ  ๊ฐ€์ฃผ์„ธ์š”! ๋กœ๊ทธ์ธ ์•ˆํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค ^_^

 

๋ฐ˜์‘ํ˜•
COMMENT