调试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
相关产品推荐
相关产品推荐

