当前位置: 首页 > article >正文

从零到一:构建支持FCM推送的Android应用实战指南

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如个推、极光来简化多通道管理但要注意评估其合规性和隐私政策。

相关文章:

从零到一:构建支持FCM推送的Android应用实战指南

1. 为什么需要FCM推送? 移动应用推送功能就像餐厅的叫号系统——没有它,用户就不知道自己的"菜品"(新消息/内容)是否已经准备好。FCM(Firebase Cloud Messaging)作为Google官方推荐的推送解决方…...

QQ空间备份工具:将青春记忆永久保存到本地的完整指南

QQ空间备份工具:将青春记忆永久保存到本地的完整指南 【免费下载链接】QZoneExport QQ空间导出助手,用于备份QQ空间的说说、日志、私密日记、相册、视频、留言板、QQ好友、收藏夹、分享、最近访客为文件,便于迁移与保存 项目地址: https://…...

KNIME Server值不值得买?中小团队协作与自动化部署的深度体验报告

KNIME Server值不值得买?中小团队协作与自动化部署的深度体验报告 当你的数据分析团队从三五人扩展到十几人,每天早上的第一件事不再是喝咖啡,而是处理各种工作流版本冲突、手动执行定时任务、反复解释流程逻辑时,KNIME Server这个…...

从老古董NE555到单片机:手把手教你做一个简易数字频率计(STC89C52)

从NE555到STC89C52:打造高性价比数字频率计的完整指南 在电子爱好者的世界里,测量信号频率是一项基础却至关重要的技能。想象一下,当你调试一个振荡电路时,能够实时看到信号频率的变化;或者当你需要验证一个传感器输出…...

手把手教你为STM32G474RET6逆变器项目添加阿里云和蓝牙APP远程监控

STM32G474RET6逆变器项目的智能化升级:云平台与蓝牙监控实战指南 在电力电子领域,逆变器作为能量转换的核心设备,其智能化升级已成为行业趋势。本文将深入探讨如何为基于STM32G474RET6的三相逆变器项目添加远程监控能力,通过4G模块…...

Windows Cleaner:释放C盘空间,让你的Windows系统重获新生

Windows Cleaner:释放C盘空间,让你的Windows系统重获新生 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否经历过Windows系统越用越慢…...

JDspyder:京东商品秒杀自动化解决方案终极指南

JDspyder:京东商品秒杀自动化解决方案终极指南 【免费下载链接】JDspyder 京东预约&抢购脚本,可以自定义商品链接 项目地址: https://gitcode.com/gh_mirrors/jd/JDspyder JDspyder是一款专为京东平台设计的Python自动化脚本工具,…...

书匠策AI:期刊论文创作界的“全能魔法师”

在学术的奇幻世界里,期刊论文是学者们展示智慧与研究成果的“魔法咒语”,每一篇高质量的论文都像是一道闪耀的光芒,照亮学术前行的道路。然而,创作一篇优秀的期刊论文并非易事,从选题时的迷茫、文献收集的繁琐&#xf…...

阅读效率低下,读后即忘,还怎么写文献综述?

对于每一位研究生来说,开题报告的文献综述环节堪称“第一道难关”。面对领域内成百上千篇中英文文献,熬了几个通宵精读,合上文献却记不清核心观点;好不容易整理出一堆笔记,拼凑起来的综述却逻辑混乱、重点模糊&#xf…...

论文“瘦身”新纪元:书匠策AI,一键解锁降重降AIGC的双重秘籍!

在学术圈的“健身房”里,每篇论文都是一位亟待“塑形”的运动员。它们渴望以最精炼、最原创的姿态,在查重的“体脂秤”上展现出完美的“身材比例”。但现实往往不尽如人意,高重复率、AIGC痕迹过重,成了许多论文“健身”路上的绊脚…...

深度剖析:动态规划的分类及实例

如你所知,动态规划可以根据问题特性分为多种类型,以下是几种经典问题类型及对应的实例。背包问题背包问题是一种资源类问题,涉及在给定约束条件下如何最大化目标值。常见的是 0-1 背包、完全背包、多重背包。0-1 背包问题:每个物品…...

扔掉Zabbix!OpenClaw一键搭建7×24服务器监控,告警零误报+自动故障自愈

前言 做运维的同学,肯定都有过这样的噩梦:凌晨3点被电话吵醒,说服务器挂了;赶到公司排查了半小时,发现只是Nginx进程死了;刚躺下没多久,又一个电话打过来,说磁盘满了。我之前管着公司…...

5分钟解决Windows软件运行错误:Visual C++运行库终极修复指南

5分钟解决Windows软件运行错误:Visual C运行库终极修复指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 当您打开软件时突然弹出"缺少MSVCR1…...

产品经理和开发者必看:如何为你的项目规划Alpha、Beta到Release的发布路线图?

产品经理和开发者必看:如何为你的项目规划Alpha、Beta到Release的发布路线图? 在软件开发的旅程中,从最初的构想到最终的产品发布,每一个阶段都承载着不同的目标和挑战。对于产品经理、项目经理和技术负责人来说,如何科…...

【免费降AI教程】论文降AIGC工具怎么选?实测DeepSeek等10款软件,手把手教你零成本降AI率

说起来都是泪,上个月我交毕业论文的时候,明明自己一个字一个字敲出来的,结果一检测,AI率居然飙到73%!当时距离截止日期只剩三天,导师还在催稿,那种绝望的感觉现在想起来还心有余悸。 这一个多月…...

如何在Windows上实现macOS风格三指拖拽:ThreeFingerDragOnWindows终极指南

如何在Windows上实现macOS风格三指拖拽:ThreeFingerDragOnWindows终极指南 【免费下载链接】ThreeFingersDragOnWindows Enables macOS-style three-finger dragging functionality on Windows Precision touchpads. 项目地址: https://gitcode.com/gh_mirrors/th…...

SAP采购订单行项目增强实战:用BADI ME_GUI_PO_CUST添加自定义字段(避坑指南)

SAP采购订单行项目增强实战:用BADI ME_GUI_PO_CUST添加自定义字段(避坑指南) 在SAP标准采购订单(ME21N/ME22N/ME23N)中扩展行项目字段是常见的业务需求,比如添加"紧急程度"或"内部备注"…...

Balsamiq Wireframes 从零到一:新手快速上手指南

1. 认识Balsamiq Wireframes:手绘风格的线框神器 第一次打开Balsamiq Wireframes时,你会被它独特的手绘风格吸引。这款工具就像是把设计师的草图本搬到了电脑里,所有UI元素都带着铅笔素描的质感。我刚开始接触产品设计时,最头疼的…...

已解决Spring Cloud 2022+中FeignClient启动报错:No Feign Client for loadBalancing defined

1. 问题现象与错误分析 最近在升级到Spring Cloud 2022.0.x和Spring Boot 3.x后,很多开发者都遇到了一个典型的启动报错:"No Feign Client for loadBalancing defined"。这个错误通常发生在服务启动阶段,控制台会打印出一长串的依赖…...

OpticsPy:用Python解决光学系统设计的矩阵计算与光线追迹难题

OpticsPy:用Python解决光学系统设计的矩阵计算与光线追迹难题 【免费下载链接】opticspy python optics module 项目地址: https://gitcode.com/gh_mirrors/op/opticspy 传统光学设计面临两大核心挑战:商业软件封闭昂贵,无法与现代化开…...

UG后处理TCL编程实战:手把手教你定制刀具信息输出格式(含完整代码)

UG后处理TCL编程实战:手把手教你定制刀具信息输出格式(含完整代码) 在数控加工领域,UG后处理的灵活定制能力直接决定了最终加工程序的可用性和效率。刀具信息作为程序中最关键的参数之一,其输出格式的合理设计不仅能减…...

别再只盯着batch-size了!用Tesla V100训练YOLO时,这些隐藏的显存杀手和监控技巧你知道吗?

别再只盯着batch-size了!用Tesla V100训练YOLO时,这些隐藏的显存杀手和监控技巧你知道吗? 当你手握一块Tesla V100这样的顶级GPU,却发现训练YOLO时依然频频遭遇"爆显存"的尴尬,这感觉就像开着跑车却堵在早高…...

当经典运筹学遇上深度强化学习:我们离‘一键最优’的智能工厂还有多远?

深度强化学习重构制造业调度:从理论到落地的关键突破 走进任何一家现代化制造工厂,你都会看到数百台设备在同步运转,成千上万的零件在不同工序间流转。这种复杂场景下的生产调度,堪称工业界的"终极算法挑战"。传统运筹学…...

终极风扇控制指南:5分钟让Windows风扇静音又高效

终极风扇控制指南:5分钟让Windows风扇静音又高效 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/FanC…...

STM32网络调试救星:用HostName+DHCP告别“IP地址猜猜看”,附FreeRTOS下LWIP 2.1.2完整工程配置

STM32网络调试实战:基于HostName的智能设备发现方案 实验室里五台相同的STM32设备同时上电,LED灯整齐闪烁,但哪台对应哪个IP?这个场景让多少嵌入式开发者抓狂地插拔网线、反复刷新路由器界面。传统DHCP方案虽然解决了IP分配问题&a…...

告别Samba和FTP:用Java NFS-Client 1.0.3实现跨平台文件操作,SpringBoot项目实战

告别Samba和FTP:用Java NFS-Client 1.0.3实现跨平台文件操作,SpringBoot项目实战 在分布式系统和云原生架构日益普及的今天,传统的文件共享方案如Samba和FTP逐渐暴露出性能瓶颈和兼容性问题。本文将带你探索一种更现代、更高效的替代方案——…...

终极窗口控制指南:如何用WindowResizer轻松管理任意窗口尺寸

终极窗口控制指南:如何用WindowResizer轻松管理任意窗口尺寸 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为那些无法调整大小的Windows应用程序窗口而烦恼吗&am…...

告别命令行:用Gradio为你的本地Qwen-7B-Chat快速搭建一个Web聊天界面

从终端到浏览器:用Gradio打造Qwen-7B-Chat的智能对话门户 当你已经在Ubuntu 22.04上成功部署了Qwen-7B-Chat模型,却还在终端里敲击命令与AI对话时,是否想过——这就像用DOS命令行操作智能手机?本文将带你突破命令行的桎梏&#xf…...

STM32 SPI模式SD卡驱动开发与FAT16文件系统实现

1. 项目概述:基于STM32的SD卡SPI协议库开发作为一名长期从事嵌入式开发的工程师,我最近完成了一个针对STM32平台的SD卡SPI协议库实现。这个项目的核心目标是构建一个严格遵循SD协议标准的轻量级库,特别适合资源受限的嵌入式环境。与常见的Ard…...

保姆级教程:用SageMath复现CTF中的AMM算法,手算有限域开方

密码学实战:用SageMath攻克RSA中的AMM算法与有限域开方难题 密码学竞赛中那些看似无解的RSA题目,往往隐藏着令人着迷的数学奥秘。当遇到e与φ(n)不互质的特殊场景时,传统解密方法失效,我们需要搬出数论中的"重型武器"—…...