You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调试Firebase Messaging SenderId不匹配及AccessToken为空问题

FCM推送失败排查:SenderId不匹配与AccessToken为null问题

问题描述

基于Firebase Java Quickstart修改Messaging类后,测试时始终收到SenderId mismatch错误,已确认设备推送令牌归属目标Firebase项目,但加载凭证文件后打印AccessToken显示为null,需要排查推送失败原因并解决。

相关代码

public class Messaging {

    private static final String MESSAGING_SCOPE = "https://www.googleapis.com/auth/firebase.messaging";
    private static final String[] SCOPES = { MESSAGING_SCOPE };

    private static final String TITLE = "FCM Test";
    private static final String BODY = "Test Body";
    private static final String DEVICE_TOKEN = "91bHb1hw6nhVs0JjjGAqBS1GQmNC....";
    /**
     * Sends request message to FCM using HTTP.
     *
     * @param message The message of the send request.
     * @throws FirebaseMessagingException
     */
    private static HashMap<String, String> sendMessage(final Message message) throws FirebaseMessagingException {
        HashMap<String, String> respSet = new HashMap<String, String>();
        FirebaseMessaging fmInst = FirebaseMessaging.getInstance();

        try {           
            String response = fmInst.send(message);
            Log4j.log.debug("Message sent to Firebase for delivery, response: " + response);

            respSet.put("returnMsg", response);
            respSet.put("returnCode", ReturnCode.Success);

        } catch (FirebaseMessagingException e) {
            Log4j.log.debug("Unable to send message to Firebase, error code: " + e.getMessagingErrorCode());

            System.out.println("Push failed: " + e.getMessage());

            respSet.put("returnMsg", e.getMessage());
            respSet.put("returnCode", ReturnCode.PushFail);
        }
        return respSet;
    }

    /**
     * Sends notification message to FCM for delivery to registered devices.
     *
     * @throws FirebaseMessagingException
     */
    public static HashMap<String, String> sendCommonMessage(final String token, final String title, final String body,
            final String data) throws FirebaseMessagingException {
        Message notificationMessage = buildNotificationMessage(token, title, body, data).build();
        Log4j.log.debug("FCM Msg body: " + new Gson().toJson(notificationMessage));
        Log4j.log.trace("FCM request body for message using common notification object:");
        return sendMessage(notificationMessage);
    }

    /**
     * Constructs the body of a notification message request.
     *
     * @return the builder object of the notification message.
     */
    private static Message.Builder buildNotificationMessage(final String token, final String title, final String body,
            final String data) {
        Notification notification = Notification.builder().setTitle(title).setBody(body).build();

        Message.Builder message = Message.builder().putData("body", data).setToken(token).setNotification(notification);

        return message;
    }

    /**
     * Initializes the enviroment with Firebase default credentials.
     */
    public static void initializeWithDefaultCredentials(final String credFilePath) throws IOException {
        // [START initialize_sdk_with_application_default]
        GoogleCredentials googleCredentials = GoogleCredentials.fromStream(new FileInputStream(credFilePath))
                .createScoped(Arrays.asList(SCOPES));

        Log4j.log.debug("Loaded credential: " + googleCredentials.toString());

        FirebaseOptions options = new FirebaseOptions.Builder().setCredentials(googleCredentials).build();
        
        Log4j.log.debug("Access token: " + googleCredentials.getAccessToken());

        if (FirebaseApp.getApps().isEmpty()) {
            FirebaseApp.initializeApp(options);
        }
        // [END initialize_sdk_with_application_default]
    }

    public HashMap<String, String> sendMsg(final String credFilePath, final String token, final String title,
            final String body, final String data) throws IOException, FirebaseMessagingException {
        initializeWithDefaultCredentials(credFilePath);
        return sendCommonMessage(token, title, body, data);
    }

    public static void main(String[] args) throws IOException, FirebaseMessagingException {
        initializeWithDefaultCredentials("\\Cred_File.json");
        sendCommonMessage(DEVICE_TOKEN, TITLE, BODY, "Test");
    }
}

解决建议

1. 修复AccessToken为null问题

GoogleCredentials初始化后不会自动生成AccessToken,需要手动触发令牌获取逻辑。修改initializeWithDefaultCredentials方法,在创建credentials后添加刷新操作:

GoogleCredentials googleCredentials = GoogleCredentials.fromStream(new FileInputStream(credFilePath))
        .createScoped(Arrays.asList(SCOPES));
// 添加令牌刷新逻辑
googleCredentials.refreshIfExpired();

调用refreshIfExpired()后,再获取googleCredentials.getAccessToken()就能拿到有效令牌。

2. 排查SenderId不匹配问题

  • 验证凭证与项目的一致性:确认Cred_File.json所属Firebase项目的SenderId,与生成设备令牌的客户端应用SenderId完全一致。可从Firebase控制台「项目设置」中查看SenderId,或核对凭证文件中的project_id对应的项目信息。
  • 检查客户端配置:客户端应用的google-services.json(Android)或GoogleService-Info.plist(iOS)中的sender_id,必须与服务端凭证所属项目的SenderId一致。
  • 避免重复初始化FirebaseApp:当前代码仅在FirebaseApp.getApps().isEmpty()时初始化,但如果多次调用sendMsg,可能导致初始化逻辑异常。建议将Firebase初始化放在应用启动阶段执行一次,而非每次发送请求时重复初始化。
  • 验证设备令牌有效性:重新生成设备令牌进行测试,排除令牌过期或无效的可能。

3. 代码优化点

  • 构建FirebaseOptions时显式指定项目ID,避免凭证解析异常导致项目匹配错误:
    FirebaseOptions options = new FirebaseOptions.Builder()
            .setCredentials(googleCredentials)
            .setProjectId("你的Firebase项目ID")
            .build();
    
  • 替换日志中googleCredentials.toString()的打印,改为打印服务账号邮箱验证凭证正确性:
    Log4j.log.debug("Loaded service account email: " + googleCredentials.getServiceAccountEmail());
    

内容的提问来源于stack exchange,提问作者Kaninchen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 22:12:06