push-notifications
AndroidのFCMやiOSのAPNsといったプッシュ通知設定、通知チャンネル、ペイロード処理、フォアグラウンド/バックグラウンド動作、リッチ通知などを扱い、効果的なプッシュ通知を実装するSkill。
📜 元の英語説明(参考)
Push notification patterns - FCM setup for Android, APNs for iOS, notification channels, payload handling, foreground/background behavior, and rich notifications.
🇯🇵 日本人クリエイター向け解説
AndroidのFCMやiOSのAPNsといったプッシュ通知設定、通知チャンネル、ペイロード処理、フォアグラウンド/バックグラウンド動作、リッチ通知などを扱い、効果的なプッシュ通知を実装するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o push-notifications.zip https://jpskill.com/download/16438.zip && unzip -o push-notifications.zip && rm push-notifications.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/16438.zip -OutFile "$d\push-notifications.zip"; Expand-Archive "$d\push-notifications.zip" -DestinationPath $d -Force; ri "$d\push-notifications.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
push-notifications.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
push-notificationsフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
プッシュ通知のパターン
Android / Firebase Cloud Messaging
Firebase の設定
google-services.json を app/ ディレクトリに追加し、依存関係を設定します。
// build.gradle.kts (project)
plugins {
id("com.google.gms.google-services") version "4.4.0" apply false
}
// build.gradle.kts (app)
plugins {
id("com.google.gms.google-services")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
implementation("com.google.firebase:firebase-messaging-ktx")
}
FirebaseMessagingService の実装
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// ターゲット設定のために、トークンをサーバーに送信します
TokenRepository.syncTokenToServer(token)
}
override fun onMessageReceived(message: RemoteMessage) {
// データメッセージは常にここに到達します
val data = message.data
val title = data["title"] ?: message.notification?.title ?: return
val body = data["body"] ?: message.notification?.body ?: ""
when (data["type"]) {
"chat" -> showChatNotification(title, body, data)
"promo" -> showPromoNotification(title, body, data)
else -> showDefaultNotification(title, body)
}
}
private fun showDefaultNotification(title: String, body: String) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_DEFAULT)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(System.currentTimeMillis().toInt(), notification)
}
companion object {
const val CHANNEL_DEFAULT = "default"
const val CHANNEL_CHAT = "chat_messages"
const val CHANNEL_PROMO = "promotions"
}
}
通知チャネル (Android 8+)
object NotificationChannels {
fun createAll(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val manager = context.getSystemService(NotificationManager::class.java)
val defaultChannel = NotificationChannel(
"default",
"General",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "General notifications"
}
val chatChannel = NotificationChannel(
"chat_messages",
"Chat Messages",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "New chat messages"
enableVibration(true)
enableLights(true)
}
val promoChannel = NotificationChannel(
"promotions",
"Promotions",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Promotional offers and deals"
}
manager.createNotificationChannels(listOf(defaultChannel, chatChannel, promoChannel))
}
}
Application.onCreate() で NotificationChannels.createAll(this) を呼び出します。
データメッセージと通知メッセージの比較
| 側面 | Notification Message | Data Message |
|---|---|---|
| フォアグラウンド | onMessageReceived |
onMessageReceived |
| バックグラウンド | システムトレイ (自動) | onMessageReceived |
| カスタマイズ性 | 限定的 | 完全な制御 |
| ペイロードキー | "notification": {} |
"data": {} |
ベストプラクティス: 表示動作を完全に制御するには、データ専用メッセージを使用します。
トークンの登録とサーバーとの同期
class TokenRepository(private val api: ApiService) {
suspend fun syncTokenToServer(token: String) {
val deviceInfo = DeviceInfo(
token = token,
platform = "android",
appVersion = BuildConfig.VERSION_NAME,
locale = Locale.getDefault().toLanguageTag()
)
api.registerPushToken(deviceInfo)
}
suspend fun getAndSyncToken() {
val token = FirebaseMessaging.getInstance().token.await()
syncTokenToServer(token)
}
}
通知の許可 (Android 13+)
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// 許可された場合、トークンを同期します
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
iOS / APNs
プッシュ通知の機能
Xcode で有効にします: Target > Signing & Capabilities > + Push Notifications。 Background Modes > Remote notifications も有効にします。
UNUserNotificationCenter の設定と許可
import UserNotifications
final class NotificationManager: NSObject, UNUserNotificationCenterDelegate {
static let shared = NotificationManager()
func requestAuthorization() async -> Bool {
let center = UNUserNotificationCenter.current()
center.delegate = self
do {
let granted = try await center.requestAuthorization(
options: [.alert, .badge, .sound, .provisional]
)
if granted {
await MainActor.run {
UIApplication.shared.registerForRemoteNotifications()
}
}
return granted
} catch {
return false
}
}
// フォアグラウンドでの通知表示
func userNotificationCenter(
_ center: UNUserNo 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Push Notification Patterns
Android / Firebase Cloud Messaging
Firebase Setup
Add google-services.json to the app/ directory and configure dependencies:
// build.gradle.kts (project)
plugins {
id("com.google.gms.google-services") version "4.4.0" apply false
}
// build.gradle.kts (app)
plugins {
id("com.google.gms.google-services")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
implementation("com.google.firebase:firebase-messaging-ktx")
}
FirebaseMessagingService Implementation
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
// Send token to your server for targeting
TokenRepository.syncTokenToServer(token)
}
override fun onMessageReceived(message: RemoteMessage) {
// Data messages always arrive here
val data = message.data
val title = data["title"] ?: message.notification?.title ?: return
val body = data["body"] ?: message.notification?.body ?: ""
when (data["type"]) {
"chat" -> showChatNotification(title, body, data)
"promo" -> showPromoNotification(title, body, data)
else -> showDefaultNotification(title, body)
}
}
private fun showDefaultNotification(title: String, body: String) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, CHANNEL_DEFAULT)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build()
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(System.currentTimeMillis().toInt(), notification)
}
companion object {
const val CHANNEL_DEFAULT = "default"
const val CHANNEL_CHAT = "chat_messages"
const val CHANNEL_PROMO = "promotions"
}
}
Notification Channels (Android 8+)
object NotificationChannels {
fun createAll(context: Context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val manager = context.getSystemService(NotificationManager::class.java)
val defaultChannel = NotificationChannel(
"default",
"General",
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "General notifications"
}
val chatChannel = NotificationChannel(
"chat_messages",
"Chat Messages",
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "New chat messages"
enableVibration(true)
enableLights(true)
}
val promoChannel = NotificationChannel(
"promotions",
"Promotions",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Promotional offers and deals"
}
manager.createNotificationChannels(listOf(defaultChannel, chatChannel, promoChannel))
}
}
Call NotificationChannels.createAll(this) in Application.onCreate().
Data vs Notification Messages
| Aspect | Notification Message | Data Message |
|---|---|---|
| Foreground | onMessageReceived |
onMessageReceived |
| Background | System tray (auto) | onMessageReceived |
| Customizable | Limited | Full control |
| Payload key | "notification": {} |
"data": {} |
Best practice: Use data-only messages for full control over display behavior.
Token Registration and Server Sync
class TokenRepository(private val api: ApiService) {
suspend fun syncTokenToServer(token: String) {
val deviceInfo = DeviceInfo(
token = token,
platform = "android",
appVersion = BuildConfig.VERSION_NAME,
locale = Locale.getDefault().toLanguageTag()
)
api.registerPushToken(deviceInfo)
}
suspend fun getAndSyncToken() {
val token = FirebaseMessaging.getInstance().token.await()
syncTokenToServer(token)
}
}
Notification Permission (Android 13+)
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// Permission granted, sync token
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
iOS / APNs
Push Notification Capability
Enable in Xcode: Target > Signing & Capabilities > + Push Notifications. Also enable Background Modes > Remote notifications.
UNUserNotificationCenter Setup and Permissions
import UserNotifications
final class NotificationManager: NSObject, UNUserNotificationCenterDelegate {
static let shared = NotificationManager()
func requestAuthorization() async -> Bool {
let center = UNUserNotificationCenter.current()
center.delegate = self
do {
let granted = try await center.requestAuthorization(
options: [.alert, .badge, .sound, .provisional]
)
if granted {
await MainActor.run {
UIApplication.shared.registerForRemoteNotifications()
}
}
return granted
} catch {
return false
}
}
// Foreground notification display
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
return [.banner, .badge, .sound]
}
// Notification tap handling
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse
) async {
let userInfo = response.notification.request.content.userInfo
handleNotificationPayload(userInfo)
}
private func handleNotificationPayload(_ userInfo: [AnyHashable: Any]) {
guard let type = userInfo["type"] as? String else { return }
switch type {
case "chat":
let chatId = userInfo["chat_id"] as? String ?? ""
DeepLinkRouter.shared.destination = .chat(id: chatId)
case "product":
let productId = userInfo["product_id"] as? String ?? ""
DeepLinkRouter.shared.destination = .product(id: productId)
default:
break
}
}
}
AppDelegate Registration
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Task { await TokenService.shared.syncToken(token) }
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("Push registration failed: \(error.localizedDescription)")
}
Notification Service Extension (Rich Notifications)
Create a new target: File > New > Target > Notification Service Extension.
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
guard let content = bestAttemptContent,
let imageURLString = content.userInfo["image_url"] as? String,
let imageURL = URL(string: imageURLString) else {
contentHandler(request.content)
return
}
downloadImage(from: imageURL) { attachment in
if let attachment = attachment {
content.attachments = [attachment]
}
contentHandler(content)
}
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}
Provisional Authorization (iOS 12+)
Provisional auth delivers notifications quietly to Notification Center without prompting:
let granted = try await center.requestAuthorization(options: [.alert, .sound, .provisional])
Users can then promote to prominent delivery or turn off from the notification itself.
Testing
# Android - send test via Firebase CLI
firebase messaging:send --project=my-project --json '{
"message": {
"token": "DEVICE_TOKEN",
"data": { "type": "chat", "title": "Test", "body": "Hello" }
}
}'
# iOS - local notification for testing UI
let content = UNMutableNotificationContent()
content.title = "Test Notification"
content.body = "This is a local test."
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger)
try await UNUserNotificationCenter.current().add(request)