Cordova-plugin-firebase: ํ‘ธ์‹œ ์•Œ๋ฆผ ์•„์ด์ฝ˜ ๋ณ€๊ฒฝ - 2018๋…„ ๋นˆ Android ์•„์ด์ฝ˜ ๋ฌธ์ œ

์— ๋งŒ๋“  2018๋…„ 07์›” 06์ผ  ยท  22์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: arnesson/cordova-plugin-firebase

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„,

Cordova 8+์™€ ํ•จ๊ป˜ ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๊ฒฝ์šฐ ์•Œ๋ฆผ ์•„์ด์ฝ˜ ๋ณ€๊ฒฝ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๊ณ  Android์—์„œ ์ด์ „ '์•Œ๋ฆผ ์•„์ด์ฝ˜์ด ๋นˆ ์‚ฌ๊ฐํ˜•์ž…๋‹ˆ๋‹ค' ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•Œ๋ฆผ ์•„์ด์ฝ˜์ด ํˆฌ๋ช…ํ•œ ๋ฐฐ๊ฒฝ์— ๋‹จ์ˆœํ•œ 1์ƒ‰ ๋ชจ์–‘์ด์–ด์•ผ ํ•˜๊ณ  ์ด๋Ÿฌํ•œ ์•„์ด์ฝ˜์„ ์ œ๊ณตํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์•ˆ๋“œ๋กœ์ด๋“œ๊ฐ€ ๋Œ€์‹  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์ด์ฝ˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํˆฌ๋ช…ํ•œ ๋ฐฐ๊ฒฝ์ด ์—†๋Š” ์™„์ „ํ•˜๊ณ  ๋‹ค์ฑ„๋กœ์šด ์‚ฌ๊ฐํ˜•์ผ ๊ฐ€๋Šฅ์„ฑ์ด ํฝ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ƒˆ๋กœ์šด Ionic 3 ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋งค์šฐ ์„ฑ๊ฐ€์‹ญ๋‹ˆ๋‹ค.

Readme here atm์€ ์•„์ด์ฝ˜์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ€๊ฒฝํ•˜๋Š” ๊ณผ์ •์„ ์„ค๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์•„์ด์ฝ˜์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค.

0) ์ธํ„ฐ๋„ท ๊ฒ€์ƒ‰์„ ๋ฉˆ์ถ”๊ณ  ๋จธ๋ฆฌ์นด๋ฝ์„ ๋ฝ‘์œผ์‹ญ์‹œ์˜ค. ์ด ์ง€์นจ์„ ๋‹จ๊ณ„๋ณ„๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉด ์ž‘๋™ํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €๋ฅผ ๋ฏฟ์œผ์‹ญ์‹œ์˜ค.
1) ํˆฌ๋ช…ํ•œ ๋ฐฐ๊ฒฝ์— 1์ƒ‰ ๋ชจ์–‘๋งŒ ์žˆ๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์•„์ด์ฝ˜ ๋ฒ„์ „์„ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.
2) ์—ฌ๊ธฐ๋กœ ์ด๋™: http://romannurik.github.io/AndroidAssetStudio/icons-notification.html#source.type=clipart&source.clipart=ac_unit&source.space.trim=1&source.space.pad=0&name=notification_icon "์ด๋ฏธ์ง€" ๋ˆ„๋ฅด๊ธฐ ์™ผ์ชฝ ์ƒ๋‹จ์—์„œ ์•„์ด์ฝ˜์„ ์—…๋กœ๋“œํ•˜๊ณ  ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ž˜๋ผ๋‚ด๊ฑฐ๋‚˜ ํŒจ๋”ฉ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
3) ์ž˜ ๋ณด์ด๋ฉด ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ์˜ ํ™”์‚ดํ‘œ๋ฅผ ๋ˆŒ๋Ÿฌ 'drawable' ํด๋”๋ฅผ ๋‹ค์šด๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ถ€์— res ํด๋”๊ฐ€ ์žˆ๊ณ  ์•„์ด์ฝ˜ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅธ 5๊ฐœ์˜ drawable-xxx ํด๋”๊ฐ€ ์žˆ๋Š” zip ํŒŒ์ผ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.
4) ํ•ด๋‹น ๋“œ๋กœ์–ด๋ธ” ํด๋”๋ฅผ ํ”„๋กœ์ ํŠธ ์–ด๋”˜๊ฐ€์— ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋ฅผ ์œ„ํ•ด ์•„์ด์ฝ˜ ๋ฐ ์Šคํ”Œ๋ž˜์‹œ ํ™”๋ฉด ๋ฆฌ์†Œ์Šค ์˜†์— ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค. project-root/resources/android/notification_icon
5) <resource-file /> ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ Android ์•ฑ ๋‚ด๋ถ€์— ํ•ด๋‹น ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๋„๋ก config.xml ํŒŒ์ผ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. crodova 8.x ์ดํ›„ ์˜ฌ๋ฐ”๋ฅธ ๋Œ€์ƒ ๊ฒฝ๋กœ๋Š” app/src/main/res ์ž…๋‹ˆ๋‹ค. ์ฝ”๋ฅด๋„๋ฐ” < 8์—์„œ๋Š” res ์— ๋ถˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค (์ด์ „์— ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์€ platforms/android/res ๋””๋ ‰ํ† ๋ฆฌ์— ๋ณด๊ด€๋˜์—ˆ์œผ๋ฉฐ ์ง€๊ธˆ์€ platforms/android/app/main/res ). ๋นˆ ์•ˆ๋“œ๋กœ์ด๋“œ ์•Œ๋ฆผ ์•„์ด์ฝ˜์—์„œ ์˜จ๋ผ์ธ์œผ๋กœ 'ํ•ด๊ฒฐ๋œ' ๋ฌธ์ œ์˜ ๋Œ€๋ถ€๋ถ„์€ ์ด์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

<platform name="android">
(...) 
  <resource-file src="resources/android/notification_icon/drawable-mdpi/notification_icon.png" target="app/src/main/res/drawable-mdpi/notification_icon.png" />
  <resource-file src="resources/android/notification_icon/drawable-hdpi/notification_icon.png" target="app/src/main/res/drawable-hdpi/notification_icon.png" />
  <resource-file src="resources/android/notification_icon/drawable-xhdpi/notification_icon.png" target="app/src/main/res/drawable-xhdpi/notification_icon.png" />
  <resource-file src="resources/android/notification_icon/drawable-xxhdpi/notification_icon.png" target="app/src/main/res/drawable-xxhdpi/notification_icon.png" />
  <resource-file src="resources/android/notification_icon/drawable-xxxhdpi/notification_icon.png" target="app/src/main/res/drawable-xxxhdpi/notification_icon.png" />
</platform>

6) ์ด์ œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์•„์ด์ฝ˜์ด ๋“œ๋กœ์–ด๋ธ” ๋ฆฌ์†Œ์Šค๋กœ ์žˆ์œผ๋ฏ€๋กœ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์ด ์•„์ด์ฝ˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐ•์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ readme์— ์ž‘์„ฑ๋œ ๋‚ด์šฉ์— ๊ด€๊ณ„์—†์ด 'notification_icon'์ด๋ผ๋Š” ๋“œ๋กœ์–ด๋ธ” ๋ฆฌ์†Œ์Šค์˜ ์ž๋™ ๊ฒ€์ƒ‰์ด ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/FirebasePluginMessagingService.java#L140์˜ ์ฝ”๋“œ๋ฒ ์ด์Šค์— ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ๊ทธ ์ด์œ ๋ฅผ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €๋Š” ์ตœ์‹  ๋ฒ„์ „์˜ Android์—์„œ ๋ฆฌ์†Œ์Šค ๊ฒ€์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์ด ์žˆ๋‹ค๊ณ  ์ถ”์ธกํ•ฉ๋‹ˆ๋‹ค.
7) ๊ทธ ๋•Œ๋ฌธ์— ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์€ Firebase์— ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ๋•Œ ๋ฐฑ์—”๋“œ์—์„œ icon ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ๋ฟ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด๋กœ๋“œ์˜ notification ๋ฐ android ๋ถ€๋ถ„์„ โ€‹โ€‹์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น API๊ฐ€ ์ผ๋ถ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ด์œ ๋กœ json์˜ notification ๋ถ€๋ถ„์— icon ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Android ์ „์šฉ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ฐฑ์—”๋“œ์—์„œ Firebase๋กœ ๋ณด๋‚ด๋Š” ์•Œ๋ฆผ ํŽ˜์ด๋กœ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ž‘๋™ํ•˜๋Š” ์œ ์ผํ•œ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

{
  notification: {
    body: 'Imma push your notification if you know what i mean!',
    icon: 'notification_icon',
  },
  data: { someExtraData: 'goes_here' }
}

๋‹ค์‹œ ๋ง์”€ ๋“œ๋ฆฌ์ง€๋งŒ - 2018๋…„ 7์›” ๊ธฐ์ค€์œผ๋กœ Android ํŠน์ • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Firebase์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค .

{
  notification: {
    body: 'Imma push your notification if you know what i mean!'
  },
  data: { someExtraData: 'goes_here_if_you_need_it' },
  android: { 
    icon: 'notification_icon'
  } 
}

8) ๋ชจ๋“  ๋‹จ๊ณ„๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ด์ œ ์ƒˆ ์•„์ด์ฝ˜์„ ํ…Œ์ŠคํŠธํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Android ์—๋ฎฌ๋ ˆ์ดํ„ฐ ๋‚ด์—์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ Android ์Šคํ‚จ์€ ์„ค์ •ํ•œ ํ•ญ๋ชฉ(์˜ˆ: xiaomi์˜ MIUI)์— ๊ด€๊ณ„์—†์ด ์•Œ๋ฆผ ํ‘œ์‹œ์ค„์„ ์ธ์ˆ˜ํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์ด์ฝ˜์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์•„์ด์ฝ˜์ด ์บ์‹œ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ด์œ ๋กœ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ AVD์˜ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์บ์‹ฑ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‚ฌ์ด์— ์•ฑ์„ ์ˆ˜๋™์œผ๋กœ ์ œ๊ฑฐํ•˜๊ณ  ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ/์žฅ์น˜๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์‹ญ์‹œ์˜ค.

์ž‘์€ 10x10 ์•„์ด์ฝ˜์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๊ฑฐ์ณ์•ผ ํ•˜๋Š” ์žฅ์• ๋ฌผ์˜ ์–‘์ด ๋„ˆ๋ฌด ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธด ๊ธ€์ด ๋ฏธ๋ž˜์— ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

config.xml <platform name="android"> ํƒœ๊ทธ์— ์ถ”๊ฐ€๋œ ์ด ์ฝ”๋“œ๊ฐ€ ์•„์ด์ฝ˜์„ ๊ธฐ๋ณธ ์•Œ๋ฆผ ์•„์ด์ฝ˜์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜์‹ญ์‹œ์˜ค.

<config-file parent="/manifest/application/" target="app/src/main/AndroidManifest.xml">
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon" />
</config-file>

์ด๊ฒƒ์€ ํŽ˜์ด๋กœ๋“œ์— ์•„์ด์ฝ˜์ด ์—†๋Š” Firebase ํด๋ผ์šฐ๋“œ ๋ฉ”์‹œ์ง• ํŒจ๋„ ๋˜๋Š” ๋ฐฑ์—”๋“œ๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ํ”ผ๋“œ๋ฐฑ์„ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค.
์ž‘๋™ํ•œ๋‹ค๋ฉด ์ด ์ฝ”๋“œ์— ์ถ”๊ฐ€๋œ ํŠœํ† ๋ฆฌ์–ผ์ด ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ฉฐ README์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์—ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  22 ๋Œ“๊ธ€

config.xml <platform name="android"> ํƒœ๊ทธ์— ์ถ”๊ฐ€๋œ ์ด ์ฝ”๋“œ๊ฐ€ ์•„์ด์ฝ˜์„ ๊ธฐ๋ณธ ์•Œ๋ฆผ ์•„์ด์ฝ˜์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜์‹ญ์‹œ์˜ค.

<config-file parent="/manifest/application/" target="app/src/main/AndroidManifest.xml">
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon" />
</config-file>

์ด๊ฒƒ์€ ํŽ˜์ด๋กœ๋“œ์— ์•„์ด์ฝ˜์ด ์—†๋Š” Firebase ํด๋ผ์šฐ๋“œ ๋ฉ”์‹œ์ง• ํŒจ๋„ ๋˜๋Š” ๋ฐฑ์—”๋“œ๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ํ”ผ๋“œ๋ฐฑ์„ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค.
์ž‘๋™ํ•œ๋‹ค๋ฉด ์ด ์ฝ”๋“œ์— ์ถ”๊ฐ€๋œ ํŠœํ† ๋ฆฌ์–ผ์ด ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ฉฐ README์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์—ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@madsheep ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!! ๋‹น์‹ ์€ ๋‚ด ์ƒ๋ช…์„ ๊ตฌํ–ˆ๋‹ค !!

์•ˆ๋…•ํ•˜์„ธ์š”. ๋„๋•์  ์ง€์›์— ๊ฐ์‚ฌ๋“œ๋ฆฌ๋ฉฐ ์ด ํ˜ผ๋ž€์— ๋น ์ง„ ์‚ฌ๋žŒ์€ ์ € ํ˜ผ์ž๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๋Š๋‚Œ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•ˆํƒ€๊น๊ฒŒ๋„ 0๋‹จ๊ณ„ ์ „์œผ๋กœ ๋˜๋Œ์•„๊ฐ€๋Š” ๋„์ค‘์— ๋จธ๋ฆฌ์นด๋ฝ์ด ๋น ์ง€๊ณ  ๋ง์•˜์Šต๋‹ˆ๋‹ค.

http/post ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋ ค๊ณ  ํ•˜๋ฉด Firebase API์—์„œ json์ด ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋ชจ๋‘ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์•„์ด์ฝ˜์„ message: { notification: { icon: 'notification_icon', ... }, ... } ๋กœ ํฌํ•จํ•  ๋•Œ ์–ป๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Error code=400, message=Invalid JSON payload received. Unknown name "icon" at 'message.notification': Cannot find field., status=INVALID_ARGUMENT, details=[@type=type.googleapis.com/google.rpc.BadRequest, fieldViolations=[field=message.notification, description=Invalid JSON payload received. Unknown name "icon" at 'message.notification': Cannot find field.]]

message: { android: { icon: 'notification_icon' }, ... } ๋กœ ์•„์ด์ฝ˜์„ ํฌํ•จํ•  ๋•Œ ๋ฐ›๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.

Error code=400, message=Invalid JSON payload received. Unknown name "icon" at 'message.android': Cannot find field., status=INVALID_ARGUMENT, details=[@type=type.googleapis.com/google.rpc.BadRequest, fieldViolations=[field=message.android, description=Invalid JSON payload received. Unknown name "icon" at 'message.android': Cannot find field.]]

ํ•˜์ง€๋งŒ ์•„๋งˆ๋„ ์ž˜๋ชป๋œ ์ปจํ…์ŠคํŠธ์—์„œ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(firebase ํด๋ผ์šฐ๋“œ ๋ฉ”์‹œ์ง•์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์•ฑ์— ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๋ฐฑ์—”๋“œ ํด๋ผ์šฐ๋“œ ์ฝ”๋“œ).

์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค (Firebase ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์•Œ๋ฆผ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค).
const payload = { notification: { title: ........, body: ........., icon: 'notification_icon' } };

๋•๋ถ„์— ๋‘ ๊ฐ€์ง€ ์˜ค๋ฅ˜ ์ค‘ ์ฒซ ๋ฒˆ์งธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. javascript/request ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด REST ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ https://firebase.google.com/docs/cloud-messaging/js/first-message ํ˜•์‹์— ๋”ฐ๋ผ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€/์•Œ๋ฆผ ํ˜•์‹์ด https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Notification ์— ์„ค๋ช…๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์‹ค, ๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ์ฝ์„ ๋•Œ, ์ด๊ฒƒ์€ ์•„์ด์ฝ˜์ด message.android.notification.icon , ์ฆ‰, ํ•œ ๋‹จ๊ณ„ ๋” ๊นŠ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•”์‹œํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋ฐฉ๊ธˆ ์‹œ๋„ํ–ˆ๊ณ  ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค! ๊ทธ๋ž˜์„œ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑ๋˜์–ด์•ผํ•˜๋Š”์ง€ serverprotocol์— ๋‹ฌ๋ ค ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค ...

ํ† ๋ก ์— ์ฐธ์—ฌํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๋จธ๋ฆฌ์นด๋ฝ ๋ฝ‘๋Š”๊ฑฐ ๋ฉˆ์ท„๋‹ค...

ํ•ด๊ฒฐ๋œ ๋Œ€๋กœ ์ข…๋ฃŒ

@madsheep ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํด๋ผ์šฐ๋“œ ๊ธฐ๋Šฅ์˜ ์•Œ๋ฆผ ์•„๋ž˜์— '์•„์ด์ฝ˜'์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

{ Error: Invalid JSON payload received. Unknown name "icon" at 'message.notification': Cannot find field

์˜ค๋ฅ˜ ์ •๋ณด:
{ ์ฝ”๋“œ: '๋ฉ”์‹œ์ง€/์ž˜๋ชป๋œ ์ธ์ˆ˜',
๋ฉ”์‹œ์ง€: '์ž˜๋ชป๋œ JSON ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์ˆ˜์‹ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. 'message.notification'์—์„œ ์•Œ ์ˆ˜ ์—†๋Š” ์ด๋ฆ„ "icon": ํ•„๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.' },
codePrefix: '๋ฉ”์‹œ์ง€' }

์‹œ๋„ message.android.notification.icon ๋Œ€์‹  message.notification.icon .

@madsheep @guilhermehtk ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค! ๊ณ ๋งˆ์›Œ.

config.xml <platform name="android"> ํƒœ๊ทธ์— ์ถ”๊ฐ€๋œ ์ด ์ฝ”๋“œ๊ฐ€ ์•„์ด์ฝ˜์„ ๊ธฐ๋ณธ ์•Œ๋ฆผ ์•„์ด์ฝ˜์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜์‹ญ์‹œ์˜ค.

<config-file parent="/manifest/application/" target="app/src/main/AndroidManifest.xml">
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon" />
</config-file>

์ด๊ฒƒ์€ ํŽ˜์ด๋กœ๋“œ์— ์•„์ด์ฝ˜์ด ์—†๋Š” Firebase ํด๋ผ์šฐ๋“œ ๋ฉ”์‹œ์ง• ํŒจ๋„ ๋˜๋Š” ๋ฐฑ์—”๋“œ๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ํ”ผ๋“œ๋ฐฑ์„ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค.
์ž‘๋™ํ•œ๋‹ค๋ฉด ์ด ์ฝ”๋“œ์— ์ถ”๊ฐ€๋œ ํŠœํ† ๋ฆฌ์–ผ์ด ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ฉฐ README์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์—ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์ง„์งœ ๋„ˆ ๋•๋ถ„์ด๋‹ค,

๋ˆ„๊ตฐ๊ฐ€ ๋นŒ๋“œ์—์„œ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๋ฉด

AAPT: ์˜ค๋ฅ˜: ์–ธ๋ฐ”์šด๋“œ ์ ‘๋‘์‚ฌ.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ 

xmlns:android= " http://schemas.android.com/apk/res/android "

์†์„ฑ์„ ๋ฃจํŠธ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.config.xml ๋‚ด๋ถ€์˜ ํƒœ๊ทธ

๋‹น์‹ ์€ ๋‚ด ํ•˜๋ฃจ๋ฅผ ๊ตฌํ–ˆ๋‹ค!

2019๋…„ Android ๋นŒ๋“œ 7.1.1์—์„œ ์ด ๋ฌธ์ œ์— ์ง๋ฉดํ•œ ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๋ฆฌ์†Œ์Šค ํด๋”๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!!

Android ์ŠคํŠœ๋””์˜ค์™€ ์ƒ์„ฑ๋œ ํŒŒ์ผ์„ ํ™•์ธํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚˜์—๊ฒŒ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

<resource-file src="resources/android/notification/notification_icon.png" target="app/src/main/res/drawable/notification_icon.png" />
<config-file parent="/manifest/application/" target="app/src/main/AndroidManifest.xml">
            <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon" />
</config-file>

์ฒซ ๋ฒˆ์งธ ์ค„์€ ๋‚˜์—๊ฒŒ ์ž˜๋ชป๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

@alarv ์ผ๋ถ€ Android ํœด๋Œ€์ „ํ™”์—์„œ๋Š” ์•„์ด์ฝ˜์ด ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋„์›€์„ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

@bioyeneye ์–ด๋–ค ๋ชจ๋ธ์ธ๊ฐ€์š”? ์–ด๋–ค ๋ฒ„์ „์˜ Android๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์žˆ๋‚˜์š”? ์ฃผ์‹ ๋˜๋Š” ๊ธฐํƒ€?

@bioyeneye ๋ชจ๋“  ์•ˆ๋“œ๋กœ์ด๋“œ ์žฅ์น˜์—์„œ ์•„์ด์ฝ˜์ด ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” Ionic 4์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์•„์ด์ฝ˜์— png๊ฐ€ ์•„๋‹ˆ๋ผ XML์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๊ฒƒ์„ ํฌํ•จํ•˜๊ธฐ ์œ„ํ•ด ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

'res/drawable-hdpi',
'res/drawable-mdpi',
'res/drawable-xhdpi',
'res/drawable-xxhdpi',
'res/drawable-xxxhdpi',
'res/mipmap-hdpi',
'res/mipmap-mdpi',
'res/mipmap-xhdpi',
'res/mipmap-xxhdpi',
'res/mipmap-xxxhdpi'

ํŒŒ์ผ ์˜ˆ์ œ ๋งŒ๋“ค๊ธฐ:
android_notification_resources.js

์ด ์ƒˆ ํ›„ํฌ ํŒŒ์ผ์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.


// ์‹œ์ž‘ํ•˜๋‹ค
const fs = ์š”๊ตฌ("fs");
const ๊ฒฝ๋กœ = ์š”๊ตฌ("๊ฒฝ๋กœ");
const Q = ์š”๊ตฌ("q");

var sourceDir = '๋ฆฌ์†Œ์Šค/์•ˆ๋“œ๋กœ์ด๋“œ/์•Œ๋ฆผ_์•„์ด์ฝ˜'; // ์ด๊ฒƒ์€ ๋‹น์‹ ์˜ ์•„์ด์ฝ˜์ด ์žˆ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค
var platformDir = 'ํ”Œ๋žซํผ/์•ˆ๋“œ๋กœ์ด๋“œ/์•ฑ/src/๋ฉ”์ธ/';
var ๋ฆฌ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ = [
'ํ•ด์ƒ๋„/๋“œ๋กœ์–ด๋ธ”-HDPI',
'res/drawable-mdpi',
'res/drawable-xhdpi',
'res/drawable-xxhdpi',
'res/drawable-xxxhdpi',
'res/mipmap-hdpi',
'res/mipmap-mdpi',
'res/mipmap-xhdpi',
'res/mipmap-xxhdpi',
'res/mipmap-xxxhdpi'
];

module.exports = ํ•จ์ˆ˜(ctx) {

if (ctx.opts.platforms.indexOf('์•ˆ๋“œ๋กœ์ด๋“œ') < 0) {
๋ฐ˜ํ’ˆ;
}

var ์ง€์—ฐ = Q.defer();
var androidPlatformDir = path.join(ctx.opts.projectRoot, platformDir);
var customResourcesDir = path.join(ctx.opts.projectRoot, sourceDir);

ํ•จ์ˆ˜ ๋ณต์‚ฌ(src, ๋Œ€์ƒ) {
var ์ง€์—ฐ = Q.defer();

fs.stat(src, function(err, stats) {
  if (err || !stats.isFile()) {
    return deferred.reject(err);
  }

  fs.stat(path.dirname(dest), function(err, stats) {
    if (err || !stats.isDirectory()) {
      return deferred.reject(err);
    }

    var rs = fs.createReadStream(src);

    rs.on('error', function(err) {
      console.error(err.stack);
      deferred.reject(err);
    });

    var ws = fs.createWriteStream(dest);

    ws.on('error', function(err) {
      console.error(err.stack);
      deferred.reject(err);
    });

    ws.on('close', function() {
      deferred.resolve();
    });

    rs.pipe(ws);
  });
});

return deferred.promise;

}

fs.stat(customResourcesDir, ํ•จ์ˆ˜(์˜ค๋ฅ˜, ํ†ต๊ณ„) {
if (err || !stats.isDirectory()) {
๋ฐ˜ํ™˜ deferred.resolve();
}

fs.readdir(customResourcesDir, function(err, files) {
  var copies = [];

  for (var i in files) {
    for (var j in resourceDirs) {
      var filePath = path.join(ctx.opts.projectRoot, sourceDir, files[i]);
      var destPath = path.join(androidPlatformDir, resourceDirs[j], files[i]);

      copies.push([filePath, destPath]);
    }
  }

  copies.map(function(args) {
    return copy.apply(copy, args);
  });

  Q.all(copies).then(function(r) {
    deferred.resolve();
  }, function(err) {
    console.error(err.stack);
    deferred.reject(err);
  });
});

});

deferred.promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
}
// ๋


config.xml์— ๋‹ค์Œ ์ค„์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ›„ํฌ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

ํ›„ํฌ๊ฐ€ ํ•˜๋Š” ์ผ์€ ๋ฆฌ์†Œ์Šค ํด๋”์—์„œ ์•„์ด์ฝ˜์„ ๋ณต์‚ฌํ•˜์—ฌ ๋‹ค๋ฅธ ๋“œ๋กœ์–ด๋ธ” ํด๋”์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์žฅ์น˜์—์„œ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌํƒœ๊นŒ์ง€๋Š” ๊ทธ๋Ÿฐ๋Œ€๋กœ ์ž˜๋๋‹ค.

๊ทธ๊ฒƒ์ด ๋‹น์‹ ์„ ์œ„ํ•ด ์ผํ–ˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค! ๊ฑด๋ฐฐ

@RobinGiel ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ์ €๋Š” ionic 3๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘๋™ํ• ๊นŒ์š”?

์•ˆ๋…•ํ•˜์„ธ์š” @Flucadetena
์•ˆ๋“œ๋กœ์ด๋“œ 9
์ฝ”๋ฅด๋„๋ฐ” ํ”Œ๋žซํผ: ์•ˆ๋“œ๋กœ์ด๋“œ 7.1.1

@bioyeneye ์ €๋„ ionic 3๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค ํ™•์ธํ•ด๋ณด๊ณ  ์•Œ๋ ค๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ;)

@bioyeneye ์˜ˆ, ํ›„ํฌ์—์„œ ๋ช‡ ์ค„์„ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

var sourceDir = '๋ฆฌ์†Œ์Šค/์•ˆ๋“œ๋กœ์ด๋“œ/์•Œ๋ฆผ_์•„์ด์ฝ˜';
var platformDir = 'ํ”Œ๋žซํผ/์•ˆ๋“œ๋กœ์ด๋“œ';

const Q = require("q"); ํ•ด๋‹น ์ค„์„ ์ œ๊ฑฐํ•˜๊ณ  ์—ฌ๊ธฐ์— ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์˜ˆ:

module.exports = ํ•จ์ˆ˜(ctx) {

if (ctx.opts.platforms.indexOf('์•ˆ๋“œ๋กœ์ด๋“œ') < 0) {
๋ฐ˜ํ’ˆ;
}

var Q = ctx.requireCordovaModule('q'); // ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉ
var ์ง€์—ฐ = Q.defer();
var androidPlatformDir = path.join(ctx.opts.projectRoot, platformDir);
var customResourcesDir = path.join(ctx.opts.projectRoot, sourceDir);


๋™์ผํ•œ ํ›„ํฌ before_build ๋ฐ before_run ์˜ˆ์ œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” config.xml์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

<hook type="before_run"         src="hooks/android_notification_resources.js" />
<hook type="before_build"       src="hooks/android_notification_resources.js" />

config.xml <platform name="android"> ํƒœ๊ทธ์— ์ถ”๊ฐ€๋œ ์ด ์ฝ”๋“œ๊ฐ€ ์•„์ด์ฝ˜์„ ๊ธฐ๋ณธ ์•Œ๋ฆผ ์•„์ด์ฝ˜์œผ๋กœ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜์‹ญ์‹œ์˜ค.

<config-file parent="/manifest/application/" target="app/src/main/AndroidManifest.xml">
    <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon" />
</config-file>

์ด๊ฒƒ์€ ํŽ˜์ด๋กœ๋“œ์— ์•„์ด์ฝ˜์ด ์—†๋Š” Firebase ํด๋ผ์šฐ๋“œ ๋ฉ”์‹œ์ง• ํŒจ๋„ ๋˜๋Š” ๋ฐฑ์—”๋“œ๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์— ํ”ผ๋“œ๋ฐฑ์„ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค.
์ž‘๋™ํ•œ๋‹ค๋ฉด ์ด ์ฝ”๋“œ์— ์ถ”๊ฐ€๋œ ํŠœํ† ๋ฆฌ์–ผ์ด ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ฉฐ README์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด PR์„ ์—ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์ง„์งœ ๋„ˆ ๋•๋ถ„์ด๋‹ค,

๋ˆ„๊ตฐ๊ฐ€ ๋นŒ๋“œ์—์„œ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๋ฉด

AAPT: ์˜ค๋ฅ˜: ์–ธ๋ฐ”์šด๋“œ ์ ‘๋‘์‚ฌ.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ 

xmlns:android= " http://schemas.android.com/apk/res/android "

์†์„ฑ์€ config.xml ๋‚ด๋ถ€์˜ ๋ฃจํŠธ ํƒœ๊ทธ์— ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•˜์ง€๋งŒ ์•„์ด์ฝ˜์ด ์—„์ฒญ๋‚˜๊ฒŒ ์ž‘์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ํŒŒ์ผ์˜ ์ ์ ˆํ•œ ํฌ๊ธฐ๋Š” ์–ผ๋งˆ์ž…๋‹ˆ๊นŒ?

ํŽธ์ง‘: 256x256์„ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์ƒํƒœ ํ‘œ์‹œ์ค„์— ์ž‘์€ ์ ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ƒํƒœ ํ‘œ์‹œ์ค„์„ ์•„๋ž˜์ชฝ์œผ๋กœ ๋“œ๋ž˜๊ทธํ•˜๋ฉด ์•ฝ๊ฐ„ ๋” ํฐ ํ‘œ์‹œ์ค„์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€

๋‹น์‹ ์€ ๋‚ด ์ƒ๋ช…์˜ ์€์ธ์ž…๋‹ˆ๋‹ค!! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!!
๋…ธํŠธ:
์•Œ๋ฆผ ์„น์…˜์— color: '#e50012'๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์•„์ด์ฝ˜์˜ ์ƒ‰์ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.(์ƒ‰์ƒ์ด ๋ฌด์—‡์ด๋“  ๋ณ€๊ฒฝ).
์ „:
{
"์ด๋ฆ„": "my_notification",
"์•Œ๋ฆผ": {
"๋ณธ๋ฌธ": "ํ†ต์ง€ ๋ณธ๋ฌธ",
"์ œ๋ชฉ": "์•Œ๋ฆผ ์ œ๋ชฉ",
"์ƒ‰์ƒ": "#e50012"
},
"๋ฐ์ดํ„ฐ":{ ... }
}

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰