開発者が知っておきたい通知の歴史

 開発者が知っておきたい通知の歴史

DroidKaigi 2018 Day2 18:30~19:00

85cab5fdf09afe3ee78ce3667681915a?s=128

Keisuke Kobayashi

February 09, 2018
Tweet

Transcript

  1. ։ൃऀ͕஌͓͖͍ͬͯͨ ௨஌ͷྺ࢙ Keisuke Kobayashi (kobakei) DroidKaigi 2018 Day2 Room1 18:30~19:00

  2. About Me • Keisuke Kobayashi • GitHub, Qiita: kobakei •

    Twitter: kobakei122 • Kyash, Inc.
  3. Kyash

  4. ࠓ೔࿩͢͜ͱ • ௨஌ͷྺ࢙ͱޙํޓ׵ੑΛߟྀ࣮ͨ͠૷ʹ
 ͍ͭͯ঺հ͠·͢ • ॳ৺ऀ޲͚ • ࠷ۙAndroid։ൃΛ࢝Ίͨํ • Firebaseʹ೚͖ͤͬΓͰ࣮૷͍ͯ͠Δํ

  5. ࠓ೔࿩͞ͳ͍͜ͱ • αϙʔτϥΠϒϥϦ͕αϙʔτ͍ͯ͠ͳ͍
 ICSΑΓੲͷ࿩͸͠·ͤΜ • Wearͷ࿩͸͠·ͤΜ

  6. ௨஌ͷྺ࢙

  7. ௨஌ • Ϣʔβʔʹͱͬͯॏཁͳػೳ • සൟʹมߋ͕ೖΔ • SDKόʔδϣϯͷ෼ذ͕ඞཁ • ಉ࣮͡૷Ͱ΋ɺݟ͑ํ͕OS͝ͱʹҧ͏ •

    ಈ࡞֬ೝ͕େม
  8. "1*MFWFM όʔδϣϯ໊ ίʔυωʔϜ ओͳػೳ   *$4   *$4

      +FMMZ#FBO ΞΫγϣϯɺελΠϧ௥Ճ   +FMMZ#FBO   +FMMZ#FBO   ,JU,BU   -PMMJQPQ ϚςϦΞϧσβΠϯɺϩοΫεΫϦʔϯɺ
 ϔουΞοϓɺελΠϧ௥Ճ   -PMMJQPQ   .BTINBMMPX   /PVHBU όϯυϧɺϦϓϥΠɺελΠϧ௥Ճ   /PVHBU   0SFP νϟϯωϧɺόοδ   0SFP
  9. "1*MFWFM όʔδϣϯ໊ ίʔυωʔϜ ओͳػೳ   *$4   *$4

      +FMMZ#FBO ΞΫγϣϯɺελΠϧ௥Ճ   +FMMZ#FBO   +FMMZ#FBO   ,JU,BU   -PMMJQPQ ϚςϦΞϧσβΠϯɺϩοΫεΫϦʔϯɺ
 ϔουΞοϓɺελΠϧ௥Ճ   -PMMJQPQ   .BTINBMMPX   /PVHBU όϯυϧɺϦϓϥΠɺελΠϧ௥Ճ   /PVHBU   0SFP νϟϯωϧɺόοδ   0SFP
  10. "1*MFWFM όʔδϣϯ໊ ίʔυωʔϜ ओͳػೳ   *$4   *$4

      +FMMZ#FBO ΞΫγϣϯɺελΠϧ௥Ճ   +FMMZ#FBO   +FMMZ#FBO   ,JU,BU   -PMMJQPQ ϚςϦΞϧσβΠϯɺϩοΫεΫϦʔϯɺ
 ϔουΞοϓɺελΠϧ௥Ճ   -PMMJQPQ   .BTINBMMPX   /PVHBU όϯυϧɺϦϓϥΠɺελΠϧ௥Ճ   /PVHBU   0SFP νϟϯωϧɺόοδ   0SFP
  11. "1*MFWFM όʔδϣϯ໊ ίʔυωʔϜ ओͳػೳ   *$4   *$4

      +FMMZ#FBO ΞΫγϣϯɺελΠϧ௥Ճ   +FMMZ#FBO   +FMMZ#FBO   ,JU,BU   -PMMJQPQ ϚςϦΞϧσβΠϯɺϩοΫεΫϦʔϯɺ
 ϔουΞοϓɺελΠϧ௥Ճ   -PMMJQPQ   .BTINBMMPX   /PVHBU όϯυϧɺϦϓϥΠɺελΠϧ௥Ճ   /PVHBU   0SFP νϟϯωϧɺόοδ   0SFP
  12. "1*MFWFM όʔδϣϯ໊ ίʔυωʔϜ ओͳػೳ   *$4   *$4

      +FMMZ#FBO ΞΫγϣϯɺελΠϧ௥Ճ   +FMMZ#FBO   +FMMZ#FBO   ,JU,BU   -PMMJQPQ ϚςϦΞϧσβΠϯɺϩοΫεΫϦʔϯɺ
 ϔουΞοϓɺελΠϧ௥Ճ   -PMMJQPQ   .BTINBMMPX   /PVHBU όϯυϧɺϦϓϥΠɺελΠϧ௥Ճ   /PVHBU   0SFP νϟϯωϧɺόοδ   0SFP
  13. جຊతͳ࣮૷

  14. ඞਢ • title • text • small icon • id

  15. Small icon • എܠಁա & നృΓ • ΨΠυϥΠϯ௨Γʹ࡞͍ͬͯΕ͹໰୊ͳ͍ • https://developer.android.com/guide/practices/

    ui_guidelines/icon_design_status_bar.html • ϥϯνϟʔΞΠίϯΛͦͷ··࢖͍ͬͯΔ৔߹ɺ API 21Ҏ߱Ͱ͸നృΓʹͳΔͷͰ஫ҙ
  16. γϯϓϧͳ࣮૷ val notification = NotificationCompat.Builder(context, CH_ID_NORMAL) .setContentTitle("This is title") .setContentText("This

    is message") .setSmallIcon(R.drawable.ic_notification) .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  17. ΄΅ඞਢ • color • defaults • pending intent • auto

    cancel • ticker (※Android 4.4·ͰͰ࢖༻)
  18. ݱ࣮తͳ࣮૷ val intent = Intent(context, MainActivity::class.java) val pendingIntent = PendingIntent.getActivity(context,

    0, intent, PendingIntent.FLAG_UPDATE_CURRENT) val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is title") .setContentText("This is message") .setTicker("This is ticker") // for legacy Android .setSmallIcon(R.drawable.ic_notification) .setColor(ContextCompat.getColor(context, R.color.colorPrimary)) .setDefaults(Notification.DEFAULT_ALL) .setContentIntent(pendingIntent) .setAutoCancel(true) .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  19. Large icon

  20. Large icon • ը૾μ΢ϯϩʔυΛؚΉ௨஌Λදࣔ͢Δͱ͖͸ Serviceਪ঑ • BroadcastReceiver͸10ඵλΠϜΞ΢τ͕
 ͋ΔͷͰɺ͕͔͔࣌ؒΔॲཧʹ͸޲͔ͳ͍ • ݸਓతʹ͸FirebaseJobDispatcherͳͲඇಉ

    ࣌δϣϒΛ࢖͏ͱָ
  21. VIBRATE_PERMISSION • Android 4.1·Ͱ͸ඞਢ • ๨ΕΔͱSecurityException͕ൃੜ • Android 4.2Ҏ߱͸ෆཁ

  22. ϚςϦΞϧσβΠϯ • API 21͔Β • ௨஌ͷσβΠϯ΋େ෯ʹมΘͬͨ

  23. Android 4.1

  24. Android 8.1

  25. Action (API 16~)

  26. Action • ௨஌ʹ෇͘Ϙλϯ • ෳ਺ઃఆՄೳ • ΞΫγϣϯ͝ͱʹIntentΛઃఆ

  27. Actionͷ஫ҙࣄ߲ • ICSͰ͸࢖͑ͳ͍ʢAPI 16Ҏ߱ͷΈʣ • ΞΠίϯ͸๨Εͣʹઃఆ͠Α͏ • API 16~19: Χϥʔදࣔ

    • API 21~23: άϨʔදࣔ • API 24~: ΞΠίϯදࣔͳ͠ • SVG࢖͑ͳ͍ͷͰ஫ҙ
  28. Action (API 16~19)

  29. Action (API 21~23)

  30. Action (API 24~)

  31. Action val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) ... .setContentIntent(pendingIntent) .addAction(R.drawable.ic_action_done, "Done",

    donePendingIntent) .addAction(R.drawable.ic_action_close, "Close", closePendingIntent) .setAutoCancel(true) .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  32. Direct Reply • API 24Ҏ߱ • ௨஌Ϗϡʔ্ͰΞϓϦىಈͤͣʹฦ৴͢Δػ ೳ • LINE,

    SlackͳͲ
  33. None
  34. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() }
  35. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() } API levelͰ෼ذ
  36. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() } RemoteInput࡞੒
  37. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() } Reply࣌ͷIntent
  38. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() } Action࡞੒
  39. Direct Reply val action = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

    val remoteInput = RemoteInput.Builder(KEY_REMOTE_INPUT) .setLabel("Reply Label") .build() val replyIntent = Intent(context, MyBroadcastReceiver::class.java) val replyPendingIntent = PendingIntent.getBroadcast(context, 1001, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT) NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build() } else { NotificationCompat.Action.Builder(R.drawable.ic_action_reply, "Reply", pendingIntent) .build() } API 23ҎԼ༻ͷී௨ͷAction
  40. Direct Reply val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) ... .addAction(action) .build()

    val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  41. Style (API 16~)

  42. Style • ௨஌Ϗϡʔͷݟͨ໨Λม͑Δػೳ • styles.xmlͱ͸ؔ܎ͳ͍ • API 16Ҏ߱

  43. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle
  44. ΊͬͪΌଟ͍

  45. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle ࠷සग़ɻೋߦҎ্ͷςΩετͰ࢖༻
  46. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle ը૾ܥΞϓϦͰ࢖༻
  47. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle ԻָɾಈըܥΞϓϦͰ࢖༻ com.android.support-media-compat
  48. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle ௨஌ϏϡʔΛΧελϚΠζ
 ͢Δ࣌ʹ࢖༻ʢ͋ͱͰઆ໌ʣ
  49. Style • API 16~ • BigTextStyle • BigPictureStyle • InboxStyle

    • API 21~ • MediaStyle • API 24~ • DecoratedCustomViewStyle • DecoratedMediaCustomViewStyle • MessagingStyle ϝοηʔδܥΞϓϦͰ࢖༻ ʢޙͰઆ໌͠·͢ʣ
  50. Big Text Style࣮૷ val style = NotificationCompat.BigTextStyle() .setBigContentTitle("Big content title")

    .setSummaryText("Big text summary") .bigText("This is long text. This is long text. This is long text. This is long text. This is long text.") val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is title") .setContentText("This is message") .setTicker("This is ticker") // for legacy Android .setStyle(style) ... .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  51. Big Text Style࣮૷ val style = NotificationCompat.BigTextStyle() .setBigContentTitle("Big content title")

    .setSummaryText("Big text summary") .bigText("This is long text. This is long text. This is long text. This is long text. This is long text.") val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is title") .setContentText("This is message") .setTicker("This is ticker") // for legacy Android .setStyle(style) ... .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification) StyleͷΠϯελϯε࡞੒
  52. Big Text Style࣮૷ val style = NotificationCompat.BigTextStyle() .setBigContentTitle("Big content title")

    .setSummaryText("Big text summary") .bigText("This is long text. This is long text. This is long text. This is long text. This is long text.") val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is title") .setContentText("This is message") .setTicker("This is ticker") // for legacy Android .setStyle(style) ... .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  53. None
  54. BigTextStyleͷ
 ɾBigContentTitle ɾBigText

  55. Notification.Builderͷ Title, Text

  56. ௕จͩͱ..Ͱলུ͞ΕΔ

  57. ௨஌ͷΧελϚΠζ

  58. ΧελϜϨΠΞ΢τ • Notification.Builder#setContent • API 24Ҏ߱ • DecoratedCustomViewStyle, DecoratedMediaCustomViewStyle

  59. Notification.Builder#setContent

  60. val customView = RemoteViews(context.packageName, R.layout.custom_layout) val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL)

    ... .setContent(customView) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notificationBuilder.build()) Notification.Builder#setContent
  61. val customView = RemoteViews(context.packageName, R.layout.custom_layout) val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL)

    ... .setContent(customView) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notificationBuilder.build()) Notification.Builder#setContent RemoteViews࡞੒
  62. val customView = RemoteViews(context.packageName, R.layout.custom_layout) val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL)

    ... .setContent(customView) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notificationBuilder.build()) Notification.Builder#setContent
  63. RemoteViews • ଞϓϩηεͷϏϡʔͷ֊૚ߏ଄Λද͢Ϋϥε • ViewͷαϒΫϥεͰ͸ͳ͍ • findViewByIdͰchild viewʹΞΫηεͰ͖ͳ ͍ •

    RemoteViews#setString(viewId, methodName, value)
 ͳͲͰૢ࡞͢Δ
  64. DecoratedCustomViewStyle • API 24Ҏ߱ • RemoteViewsΛɺΞΠίϯɺλΠτϧͳͲ
 ඪ४ͷཁૉͰϥοϓ͢ΔελΠϧ • ޙํޓ׵ੑ͋Γ •

    NotificationCompat.DecoratedCustomViewStyle
  65. DecoratedCustomViewStyle

  66. DecoratedCustomViewStyle
 (API 15)

  67. DecoratedCustomViewStyle val customView = RemoteViews(context.packageName, R.layout.custom_layout) val notificationBuilder = NotificationCompat.Builder(context,

    CHANNEL_ID_NORMAL) ... .setCustomContentView(customView) .setStyle(NotificationCompat.DecoratedCustomViewStyle()) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  68. DecoratedCustomViewStyle val customView = RemoteViews(context.packageName, R.layout.custom_layout) val notificationBuilder = NotificationCompat.Builder(context,

    CHANNEL_ID_NORMAL) ... .setCustomContentView(customView) .setStyle(NotificationCompat.DecoratedCustomViewStyle()) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  69. Colorized • ਐߦதͷॏཁͳ௨஌ʹͷΈɺഎܠ৭Λ෇͚Δ͜ͱ͕Ͱ͖Δ • ௨࿩தɺΧʔφϏͳͲ • Foreground ServiceͱηοτͰ࢖͏ • ςΩετΧϥʔ͸എܠ৭͔ΒࣗಈͰܾ·ΔʢઃఆෆՄʣ

    • BLACK or WHITE • ίϯτϥετΛߟྀͨ͠എܠ৭Λઃఆ͢Δ͜ͱ • API 26Ҏ߱
  70. Colorized

  71. Colorized fun createColorizedNotification(service: Service): Notification { val context = service.applicationContext

    val intent = Intent(context, MainActivity::class.java) val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) return NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) ... .setColor(Color.DKGRAY) .setColorized(true) .setPriority(Notification.PRIORITY_HIGH) .build() } Colorized༗ޮԽ
  72. Colorized: Service class SampleForegroundService : IntentService("sample") { override fun onHandleIntent(intent:

    Intent?) { startForeground(1, createColorizedNotification(this)) // do something... } } ForegroundϞʔυʹೖͬͯ
 ௨஌Λදࣔ
  73. ௨஌νϟϯωϧ (API 26~)

  74. ௨஌νϟϯωϧ • API 26Ҏ߱ • Ϣʔβʔ͕௨஌OFFɺԻɾόΠϒઃఆͳͲΛ੾ Γସ͑ΒΕΔ • targetSdkVersion=26Ҏ্Ͱ͸ରԠඞਢ •

    ࣮૷͸ࣗ෼ͰAPI levelͰ෼ذΛॻ͘
  75. None
  76. ௨஌νϟϯωϧͷ࡞੒ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel1 = NotificationChannel(CHANNEL_ID_NORMAL,

    "ී௨ͷνϟϯωϧ", NotificationManager.IMPORTANCE_DEFAULT) val channel2 = NotificationChannel(CHANNEL_ID_IMPORTANT, "ॏཁͳνϟϯω ϧ", NotificationManager.IMPORTANCE_HIGH) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.createNotificationChannel(channel1) nm.createNotificationChannel(channel2) }
  77. ௨஌νϟϯωϧͷ࡞੒ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel1 = NotificationChannel(CHANNEL_ID_NORMAL,

    "ී௨ͷνϟϯωϧ", NotificationManager.IMPORTANCE_DEFAULT) val channel2 = NotificationChannel(CHANNEL_ID_IMPORTANT, "ॏཁͳνϟϯω ϧ", NotificationManager.IMPORTANCE_HIGH) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.createNotificationChannel(channel1) nm.createNotificationChannel(channel2) } API 26Ҏ߱ͷΈ࣮ߦ
  78. ௨஌νϟϯωϧͷ࡞੒ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel1 = NotificationChannel(CHANNEL_ID_NORMAL,

    "ී௨ͷνϟϯωϧ", NotificationManager.IMPORTANCE_DEFAULT) val channel2 = NotificationChannel(CHANNEL_ID_IMPORTANT, "ॏཁͳνϟϯω ϧ", NotificationManager.IMPORTANCE_HIGH) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.createNotificationChannel(channel1) nm.createNotificationChannel(channel2) }
  79. ௨஌νϟϯωϧͷ࡞੒ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel1 = NotificationChannel(CHANNEL_ID_NORMAL,

    "ී௨ͷνϟϯωϧ", NotificationManager.IMPORTANCE_DEFAULT) val channel2 = NotificationChannel(CHANNEL_ID_IMPORTANT, "ॏཁͳνϟϯω ϧ", NotificationManager.IMPORTANCE_HIGH) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.createNotificationChannel(channel1) nm.createNotificationChannel(channel2) } IDॱͰιʔτ͞ΕΔ
  80. ௨஌νϟϯωϧͷ࡞੒ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel1 = NotificationChannel(CHANNEL_ID_NORMAL,

    "ී௨ͷνϟϯωϧ", NotificationManager.IMPORTANCE_DEFAULT) val channel2 = NotificationChannel(CHANNEL_ID_IMPORTANT, "ॏཁͳνϟϯω ϧ", NotificationManager.IMPORTANCE_HIGH) val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.createNotificationChannel(channel1) nm.createNotificationChannel(channel2) }
  81. ௨஌νϟϯωϧͷࢦఆ val notification = NotificationCompat.Builder(context, CH_ID_NORMAL) .setContentTitle("This is title") .setContentText("This

    is message") .setSmallIcon(R.drawable.ic_notification) .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification) νϟϯωϧIDΛࢦఆ
  82. ϝλσʔλ

  83. ϝλσʔλ • ௨஌ʹඥͮ͘ϝλσʔλɻ௨஌ͷදࣔॱংʹӨڹ ͢Δ • setPriority • setCategory • addPerson

    • API 26͔Β͸௨஌νϟϯωϧ͕࢖ΘΕΔ
  84. Priority vs Importance • Priority…௨஌ͷ༏ઌ౓ • Importance…νϟϯωϧͷॏཁ౓ • ։ൃऀ͸ॳظ஋Λڭ͑Δ͚ͩͰɺ͋ͱͰϢʔ βʔ͕มߋՄೳ

    • ޓ׵ੑͷͨΊʹ྆ํઃఆ͠·͠ΐ͏
  85. ϔουΞοϓ௨஌
 (API 21~)

  86. ϔουΞοϓ • API 21Ҏ߱ • ΞϓϦʹ͔Ϳͤͯදࣔ͞ΕΔɺ༏ઌ౓ͷߴ͍௨஌ • දࣔϩδοΫ͕όʔδϣϯ͝ͱʹҧ͏ • API

    21 ~ 25 • ௨஌ͷpriority • API 26~ • ௨஌νϟϯωϧͷઃఆ
  87. ϔουΞοϓ

  88. ϔουΞοϓ࣮૷ val notification = NotificationCompat.Builder(context, CHANNEL_ID_IMPORTANT) ... .setPriority(Notification.PRIORITY_HIGH) .build() val

    nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification) API 26Ҏ߱ API 25ҎԼ
  89. ϩοΫը໘௨஌ (API 21~)

  90. ϩοΫը໘௨஌ • API 21Ҏ߱ • ϩοΫը໘ʹ௨஌Λදࣔ • ϓϥΠϕʔτͳ಺༰ΛӅ͢͜ͱ΋Մೳ • ୺຤ͷ௨஌ઃఆͷઃఆ࣍ୈ

  91. None
  92. None
  93. None
  94. PublicʢϩοΫը໘༻ʣ val publicNotification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is public title")

    .setContentText("This is public message") ... .build()
  95. PrivateʢඇϩοΫ࣌༻ʣ val notification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setContentTitle("This is private title")

    .setContentText("This is private message") ... .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) .setPublicVersion(publicNotification) .build() val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(1, notification)
  96. όϯυϧ௨஌

  97. όϯυϧ௨஌ • εϚϗ͸API 24Ҏ߱ • ෳ਺ͷ௨஌Λ·ͱΊͯදࣔ͢Δػೳ • ϝʔϧɺϝοηϯδϟʔɺχϡʔεΞϓϦͰ සग़

  98. όϯυϧ௨஌

  99. όϯυϧ௨஌ͷ᠘ • WearͰAPI௥Ճ͞ΕͨͷͰɺεϚϗʗλϒ ϨοτͰ࢖͑Δͷ͸24͔Β • ࣮૷ʹ͸APIϨϕϧͷ෼ذඞཁ

  100. αϚϦʔ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val summaryNotification = NotificationCompat.Builder(context,

    CHANNEL_ID_NORMAL) ... .setGroupSummary(true) .setGroup(GROUP_KEY) .setAutoCancel(true) .build() nm.notify(1, summaryNotification) }
  101. αϚϦʔ API 24Ҏ߱ͰͷΈදࣔ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val summaryNotification

    = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) ... .setGroupSummary(true) .setGroup(GROUP_KEY) .setAutoCancel(true) .build() nm.notify(1, summaryNotification) }
  102. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val summaryNotification = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL)

    ... .setGroupSummary(true) .setGroup(GROUP_KEY) .setAutoCancel(true) .build() nm.notify(1, summaryNotification) } αϚϦʔ
  103. ݸผͷ௨஌ // ֤௨஌͸લόʔδϣϯڞ௨Ͱग़͢ val notification1 = NotificationCompat.Builder(context, CHANNEL_ID_NORMAL) .setGroup(GROUP_KEY) .setContentTitle("This

    is title 1") .setContentText("This is message 1") ... .build() val notification2 = ... nm.notify(2, notification1) nm.notify(2, notification2)
  104. ϝοηʔδͬΆ͍Style • Inbox style (API 16~) • Messaging style (API

    24~) • όϯυϧ௨஌ (API 24~) • ݁ہͲΕΛ࢖͑͹͍͍ͷʁ
  105. Inbox Style

  106. Messaging Style

  107. όϯυϧ௨஌

  108. ࢖͍෼͚ʢࢲݟʣ • ݪଇόϯυϧ௨஌Λ࢖͏ • API 23ҎԼͰ͸ɺΧελϜϏϡʔΛ࣮૷͢Δ • Ͱ΋໘౗ͳΒී௨ͷ௨஌Ͱ΋OK?

  109. None
  110. ௨஌Λ࣮૷͢Δ্Ͱͷ
 ϙΠϯτ

  111. None
  112. υΩϡϝϯτ • ඞͣӳޠ൛ΛݟΔ͜ͱ • ޓ׵ੑ·Ͱ͸ॻ͍ͯ͘Εͯͳ͍ͷͰɺͪΌΜ ͱओཁͳόʔδϣϯͰಈ࡞֬ೝ͠·͠ΐ͏

  113. ಈ࡞֬ೝ • αϙʔτͷ্ݶͱԼݶ͸ඞͣ֬ೝ • ϚςϦΞϧσβΠϯ͔ͭNougatલ΋஫ҙ • ୺຤ϝʔΧʔʹΑͬͯ͸ΧελϚΠζ͞Ε͍ͯ ΔͷͰɺNexus/Pixelਪ঑ • ྫ:

    Huawei
  114. None
  115. None
  116. ·ͱΊ

  117. ·ͱΊ • ௨஌APIͷྺ࢙ΛৼΓฦΓɺ֤ػೳΛޓ׵ੑΛ ߟྀ࣮ͯ͠૷͢Δࡍͷ஫ҙ఺Λ঺հͨ͠ • ͪΌΜͱυΩϡϝϯτͱಡΜͰಈ࡞֬ೝ͠ɺ Ϣʔβʔʹͱͬͯշదͳ௨஌Λ࣮૷͠Α͏

  118. αϯϓϧίʔυ • ࠓ೔ͷ࣮૷͸GitHubʹ্͛·ͨ͠ • https://github.com/kobakei/ AndroidNotificationShowcase

  119. and one more thing…

  120. ͳΔ΄ͲɺAndroid 4ܥ
 αϙʔτ͍ͯ͘͠ͷਏ͍ͧ

  121. Kyashͷbuild.gradle

  122. None
  123. None
  124. We are hiring!!!

  125. Thanks!