如何从Android应用直接向浏览器发送FCM消息?
安全实现Android应用向指定浏览器设备发送FCM消息
问题背景
我已经完成了以下配置:
- 通过Firebase Hosting部署了Angular构建的网站,集成Firebase Messaging后,用CURL发送FCM消息能在浏览器正常显示
- Android应用集成了Firebase Messaging,可以接收网站发送的消息
现在需要实现从Android应用直接向指定浏览器设备发送FCM消息,但遇到了两个问题:
- Android端的
FirebaseMessaging和RemoteMessageAPI仅支持全局sender_id,没有CURL/HTTP请求中的to参数,无法指定单个设备 - 用HTTP POST请求虽然能实现,但需要在Android应用中存储Server-API-Key,存在被反编译泄露的安全风险
测试代码参考
浏览器接收的CURL调用:
curl -H "Content-type: application/json" -H "Authorization:key=<API-KEY>" -X POST -d "{\"data\": { \"score\": \"5x1\",\"time\": \"15:10\"},\"to\" : \"<token from the browser>\"}" https://fcm.googleapis.com/fcm/send
Android应用内测试用HTTP调用:
try { URL url = new URL("https://fcm.googleapis.com/fcm/send"); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setDoOutput(true); urlConnection.setRequestProperty("Content-Type", "application/json"); urlConnection.setRequestProperty("Authorization", "key=<API-KEY>"); String postJsonData = "{\"to\": \"<token from the browser>\", \"data\": {\"data\": \"" + data.getNote() + "\"}}"; urlConnection.setDoOutput(true); DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); wr.writeBytes(postJsonData); wr.flush(); wr.close(); int responseCode = urlConnection.getResponseCode(); Log.i(TAG, "POST Response Code :: " + responseCode); if (responseCode == HttpURLConnection.HTTP_OK){ Log.i(TAG, "succeeded"); } } catch(MalformedURLException e) { Log.e(TAG, "MalformedURLException" , e); } catch (IOException e) { Log.e(TAG, "IOException" , e); }
安全解决方案
方案1:使用Firebase Cloud Functions作为中间层(推荐)
这是最安全的实现方式,因为Server-API-Key只会存储在云端的Cloud Functions中,不会暴露给Android客户端。具体步骤:
- 创建一个Callable类型的Cloud Function,负责接收Android端传来的浏览器设备Token和消息内容,然后调用Firebase Admin SDK发送FCM消息
- Android应用只需要调用这个Cloud Function,不需要接触任何敏感密钥
- 可以给Cloud Function添加身份验证(比如验证请求来自已登录的Firebase用户),进一步防止滥用
Cloud Function示例代码(JavaScript):
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); // 定义Callable函数,用于向指定浏览器设备发送FCM消息 exports.sendFcmToBrowser = functions.https.onCall(async (data, context) => { // 可选:验证请求来自已认证用户 if (!context.auth) { throw new functions.https.HttpsError( "unauthenticated", "需要先登录才能发送消息" ); } const { browserToken, messageData } = data; const fcmMessage = { data: messageData, token: browserToken }; try { const sendResult = await admin.messaging().send(fcmMessage); return { success: true, messageId: sendResult }; } catch (error) { throw new functions.https.HttpsError("internal", "发送消息失败", error); } });
Android端调用Callable Function的代码:
// 初始化Firebase Functions FirebaseFunctions firebaseFunctions = FirebaseFunctions.getInstance(); // 准备要传递的数据:浏览器Token和消息内容 Map<String, Object> requestData = new HashMap<>(); requestData.put("browserToken", "<浏览器设备的FCM Token>"); requestData.put("messageData", new HashMap<String, String>() {{ put("score", "5x1"); put("time", "15:10"); }}); // 调用Cloud Function firebaseFunctions.getHttpsCallable("sendFcmToBrowser") .call(requestData) .addOnSuccessListener(result -> { Log.i(TAG, "消息发送成功,返回结果:" + result.getData()); }) .addOnFailureListener(e -> { Log.e(TAG, "消息发送失败", e); });
方案2:使用主题订阅(适合批量场景)
如果你的需求是向一组浏览器设备发送消息,而非单个指定设备,可以采用主题订阅的方式:
- 浏览器端:调用
messaging.subscribeToTopic("your_topic_name")订阅指定主题 - Android端:使用FirebaseMessaging API直接向主题发送消息,不需要任何敏感密钥
Android端主题消息发送代码:
// 构建消息内容 RemoteMessage remoteMessage = new RemoteMessage.Builder("<你的Sender ID>@fcm.googleapis.com") .setMessageId(String.valueOf(new Random().nextInt(999999))) .addData("score", "5x1") .addData("time", "15:10") .setTopic("your_topic_name") // 指定要发送的主题 .build(); // 发送消息 FirebaseMessaging.getInstance().send(remoteMessage) .addOnSuccessListener(unused -> Log.i(TAG, "主题消息发送成功")) .addOnFailureListener(e -> Log.e(TAG, "主题消息发送失败", e));
这个方案的优势是完全不需要暴露密钥,但局限是只能向订阅主题的所有设备群发消息,无法指定单个设备。
为什么不能在Android端存储Server-API-Key?
- Android APK很容易被反编译,一旦密钥泄露,攻击者可以用你的密钥发送任意FCM消息,甚至滥用你的Firebase资源
- 这违反了Firebase的安全最佳实践,Server-API-Key属于敏感凭证,应该只在受信任的后端环境(比如Cloud Functions、你的服务器)中使用
内容的提问来源于stack exchange,提问作者chrisonline
相关产品推荐
相关产品推荐

