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

Android端Java代码从FCM Legacy API迁移至HTTP V1指南

迁移FCM Legacy API到HTTP V1版本的完整Java实现

前置步骤

  • 登录Firebase控制台,进入项目设置 > 服务账号,生成并下载私钥JSON文件,将其放在项目资源目录下
  • 确保项目依赖中包含以下库(以Gradle为例):
implementation 'com.google.auth:google-auth-library-oauth2-http:1.20.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'org.json:json:20231013'

完整替换代码

下面是替换原有Legacy API代码的完整实现,包含令牌获取、通知构建和API调用:

import com.google.auth.oauth2.GoogleCredentials;
import okhttp3.*;
import org.json.JSONObject;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

// 全局OkHttpClient实例,复用连接
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .build();

// 缓存OAuth2令牌,避免重复请求
private String cachedFcmToken;
private long tokenExpiryTime;

private void sendPushNotification(String notificationTitle, String hisFcmToken, String notificationBody, String myUserID, String notificationPhotoUrl, String hisUserID) {
    try {
        // 1. 构建FCM V1请求体
        JSONObject message = new JSONObject();
        JSONObject notification = new JSONObject();
        JSONObject data = new JSONObject();
        JSONObject androidConfig = new JSONObject();
        JSONObject androidNotification = new JSONObject();

        // 设置通知内容
        notification.put("title", notificationTitle);
        notification.put("body", notificationBody);
        notification.put("image", notificationPhotoUrl);

        // 设置Android端高优先级(对应Legacy的priority:high)
        androidNotification.put("priority", "high");
        androidConfig.put("notification", androidNotification);

        // 设置自定义数据
        data.put("isNewUncheckedLikeNotification", "true");
        data.put("likerUserID", myUserID);

        // 组装完整消息结构
        message.put("token", hisFcmToken); // 替代Legacy的"to"字段
        message.put("notification", notification);
        message.put("data", data);
        message.put("android", androidConfig);

        JSONObject requestBody = new JSONObject();
        requestBody.put("message", message);

        // 2. 获取FCM V1授权令牌
        String authToken = getFcmAuthToken();
        if (authToken == null) {
            Log.d("PushNotification", "Failed to get FCM auth token");
            return;
        }

        // 3. 调用FCM V1 API
        callV1Api(requestBody, authToken, hisUserID);

    } catch (Exception e) {
        Log.d("sendLikePushNotification", "Exception: " + e.getMessage());
    }
}

private String getFcmAuthToken() throws IOException {
    // 检查令牌是否未过期
    if (cachedFcmToken != null && System.currentTimeMillis() < tokenExpiryTime) {
        return cachedFcmToken;
    }

    // 从服务账号JSON文件加载凭据
    GoogleCredentials credentials = GoogleCredentials.fromStream(
            new FileInputStream("path/to/your/service-account-key.json")) // 替换为你的JSON文件路径
            .createScoped(Collections.singletonList("https://www.googleapis.com/auth/firebase.messaging"));

    credentials.refreshIfExpired();
    String token = credentials.getAccessToken().getTokenValue();
    // 缓存令牌,设置过期时间(提前5分钟刷新)
    tokenExpiryTime = System.currentTimeMillis() + (credentials.getAccessToken().getExpirationTime().getTime() - System.currentTimeMillis() - 300000);
    cachedFcmToken = token;
    return token;
}

private void callV1Api(JSONObject requestBody, String authToken, String hisUserID) {
    MediaType JSON = MediaType.get("application/json; charset=utf-8");
    RequestBody body = RequestBody.create(requestBody.toString(), JSON);

    // 替换为你的Firebase项目ID
    String projectId = "your-firebase-project-id";
    String url = "https://fcm.googleapis.com/v1/projects/" + projectId + "/messages:send";

    Request request = new Request.Builder()
            .url(url)
            .post(body)
            .addHeader("Authorization", "Bearer " + authToken)
            .addHeader("Content-Type", "application/json")
            .build();

    OK_HTTP_CLIENT.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
            Log.d("PushNotification", "Request failed: " + e.getMessage());
        }

        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
            if (response.isSuccessful()) {
                Log.d("PushNotification", "Notification successfully sent to user: " + hisUserID);
            } else {
                String errorBody = response.body() != null ? response.body().string() : "No error details";
                Log.d("PushNotification", "Failed to send notification: " + response.code() + " " + response.message() + " | Details: " + errorBody);
            }
            response.close();
        }
    });
}

关键变化说明

  • 请求URL:从https://fcm.googleapis.com/fcm/send改为https://fcm.googleapis.com/v1/projects/{项目ID}/messages:send,需替换为你的实际项目ID
  • 授权方式:不再使用Legacy的服务器密钥,改为通过服务账号获取OAuth2令牌
  • 消息结构:
    • 目标令牌从to字段改为token字段
    • 高优先级设置需要放在android.notification.priority下(iOS对应apns.payload.aps.priority)
    • 整体消息需要包裹在message对象中
  • 令牌缓存:添加了令牌缓存逻辑,避免每次请求都重新获取,提升效率

注意事项

  • 确保服务账号JSON文件的路径正确,且在打包时能被正确读取
  • 令牌过期时间设置了提前5分钟刷新,避免令牌在请求过程中过期
  • 错误处理中增加了错误体的读取,方便排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:47:03