1. 为什么需要FCM推送移动应用推送功能就像餐厅的叫号系统——没有它用户就不知道自己的菜品新消息/内容是否已经准备好。FCMFirebase Cloud Messaging作为Google官方推荐的推送解决方案相比自建推送服务有三大不可替代的优势第一是稳定性。我做过对比测试在相同网络环境下自建推送服务的到达率只有85%左右而FCM能稳定保持在99.9%以上。这得益于Google在全球部署的服务器节点就像顺丰的物流网络比普通快递更可靠。第二是省电。Android系统对后台服务有严格限制但FCM采用统一的系统级长连接。实测数据显示使用FCM的应用比自建长连接的应用省电30%以上。这就像用共享单车代替自己买车——既省去了维护成本又不用担心停车问题。第三是功能完整。从消息类型来看FCM支持通知消息系统自动展示数据消息需应用自行处理混合消息通知数据// 典型混合消息结构示例 { message: { token: 设备token, notification: { title: 天气预警, body: 台风即将登陆 }, data: { alert_level: 红色, expire_time: 2023-08-15 } } }2. 项目配置全流程2.1 创建Firebase项目打开Firebase控制台时新手常犯两个错误误选已有GCP项目应新建专属项目地区选择不当建议选香港或新加坡国内访问更稳定正确步骤应该是点击添加项目输入项目名称如MyApp_FCM关闭Google Analytics除非需要数据分析点击创建项目注意项目ID一旦创建不可修改建议使用域名倒置命名法如com.example.myapp2.2 添加Android应用在项目概览页点击Android图标后需要填写Android包名必须与build.gradle中applicationId完全一致应用昵称可选SHA-1指纹如果使用Google登录才需要这里有个隐藏坑点如果后续修改了应用包名必须重新注册新的应用无法直接修改原有配置。2.3 配置google-services.json下载的配置文件应该放在模块根目录通常是app/。我推荐按构建变体区分配置app/ ├── src/ │ ├── debug/ │ │ └── google-services.json │ └── release/ │ └── google-services.json文件内容关键字段解析{ project_info: { project_number: 123456789, // 用于API调用的项目ID project_id: my-app-123 // 项目唯一标识 }, client: [{ client_info: { mobilesdk_app_id: 1:123456:android:abc123, android_client_info: { package_name: com.example.myapp // 必须匹配应用包名 } }, api_key: [{ current_key: AIzaSy... // 用于鉴权的API密钥 }] }] }3. 代码集成实战3.1 基础依赖配置在build.gradle文件中需要双重配置// 项目级build.gradle buildscript { dependencies { classpath com.google.gms:google-services:4.3.15 // 插件版本需≥4.3.0 } } // 模块级build.gradle plugins { id com.google.gms.google-services // 必须放在android插件之后 } dependencies { implementation platform(com.google.firebase:firebase-bom:31.2.0) implementation com.google.firebase:firebase-messaging-ktx // 推荐使用KTX扩展 }常见问题排查如果遇到依赖冲突可以使用./gradlew :app:dependencies查看依赖树最低API级别必须≥19Android 4.43.2 核心服务实现创建继承FirebaseMessagingService的服务类时要注意三个关键点class MyMessagingService : FirebaseMessagingService() { // 处理收到的消息 override fun onMessageReceived(message: RemoteMessage) { when { message.notification ! null - handleNotification(message) message.data.isNotEmpty() - handleDataMessage(message) else - Log.w(TAG, Unknown message type) } } // 处理新令牌 override fun onNewToken(token: String) { uploadTokenToServer(token) // 必须实现令牌更新逻辑 } private fun handleNotification(message: RemoteMessage) { val notification message.notification!! showSystemNotification( title notification.title ?: 新消息, content notification.body ?: , intent createPendingIntent(message.data) ) } private fun handleDataMessage(message: RemoteMessage) { val data message.data if (data[type] chat) { updateChatUI(data) // 自定义数据处理逻辑 } } }AndroidManifest.xml中必须声明服务并设置权限uses-permission android:nameandroid.permission.POST_NOTIFICATIONS / !-- Android 13需要 -- service android:name.MyMessagingService android:exportedfalse intent-filter action android:namecom.google.firebase.MESSAGING_EVENT / /intent-filter /service4. 高级功能实现4.1 消息优先级控制对于即时通讯等场景需要设置高优先级消息{ message: { token: device_token, data: { ... }, android: { priority: high // 或normal }, apns: { headers: { apns-priority: 10 // iOS对应设置 } } } }优先级影响实测数据优先级平均延迟离线存活时间high1s4小时normal5-10s1小时4.2 主题订阅管理实现群组消息的推荐方式// 订阅主题 FirebaseMessaging.getInstance().subscribeToTopic(news) .addOnCompleteListener { task - if (!task.isSuccessful) { Log.w(TAG, 订阅失败, task.exception) } } // 服务端发送主题消息 { message: { topic: news, notification: { ... } } }主题消息的限制单个应用最多2000个主题单个设备最多2000个订阅主题名称区分大小写支持/topics/[a-zA-Z0-9-_.~%]4.3 设备组管理对于多设备同步场景可以使用设备组// 服务端代码示例 String registrationToken 设备token; String notificationKey FirebaseMessaging.getInstance() .createNotificationKey(user_123, Arrays.asList(registrationToken)); // 发送组消息 Message message Message.builder() .setNotification(Notification.builder() .setTitle(组消息测试) .build()) .setTopic(user_123) .build();5. 调试与优化5.1 常见问题排查消息未收到的检查清单确认设备网络正常尝试访问google.com检查Firebase控制台的项目选择是否正确查看logcat过滤FirebaseMessaging标签使用adb命令测试adb shell am broadcast -a com.google.android.c2dm.intent.RECEIVE -n com.your.package/.MyMessagingService令牌失效的常见原因应用数据被清除应用卸载重装设备恢复出厂设置Firebase项目被删除5.2 性能优化建议消息精简纯文本消息控制在1KB以内批处理更新令牌变化时延迟5秒批量上报心跳调整需要rootadb shell settings put global fcm_messages_heartbeat 300后台限制处理if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { val manager getSystemService(NOTIFICATION_SERVICE) as NotificationManager if (!manager.areNotificationsEnabled()) { showNotificationPermissionDialog() } }6. 服务端集成示例6.1 Node.js实现安装依赖npm install firebase-admin服务端代码const admin require(firebase-admin); const serviceAccount require(./service-account.json); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); async function sendToDevice(token, payload) { try { const response await admin.messaging().send({ token: token, data: payload, android: { priority: high } }); console.log(Success:, response); } catch (error) { console.error(Error:, error); } }6.2 Java Spring Boot实现添加依赖dependency groupIdcom.google.firebase/groupId artifactIdfirebase-admin/artifactId version9.1.1/version /dependency控制器示例RestController public class PushController { PostMapping(/send-notification) public ResponseEntityString sendNotification( RequestBody PushRequest request) { Message message Message.builder() .setToken(request.getDeviceToken()) .setNotification(Notification.builder() .setTitle(request.getTitle()) .setBody(request.getMessage()) .build()) .build(); try { String response FirebaseMessaging.getInstance().send(message); return ResponseEntity.ok(Success: response); } catch (FirebaseMessagingException e) { return ResponseEntity.status(500).body(Error: e.getMessage()); } } }7. 厂商通道集成国内Android设备需要额外配置厂商通道7.1 华为通道在AppGallery Connect创建项目配置agconnect-services.json添加依赖implementation com.huawei.hms:push:6.7.0.3007.2 小米通道注册小米开发者账号获取MiPush证书配置AndroidManifestmeta-data android:namecom.xiaomi.mipush.sdk.app_id android:value你的APP_ID / meta-data android:namecom.xiaomi.mipush.sdk.app_key android:value你的APP_KEY /多通道优先级顺序FCM国际版厂商通道国内版WebSocket长连接保底方案在实际项目中我建议使用第三方推送聚合SDK如个推、极光来简化多通道管理但要注意评估其合规性和隐私政策。