You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Firebase云函数onCall返回null,Android端无法获取结果求助

解决Firebase Cloud Function返回null给Android的问题

你遇到的核心问题是Cloud Function的onCall函数没有返回异步操作的Promise,导致函数提前结束,没有把订阅验证结果传递回客户端。另外Android端的类型转换也存在小问题,需要同步调整。

第一步:修复Cloud Function的返回值问题

在你的index.js中,当前代码仅调用了subcheck.verifySubscription但没有返回它的执行结果。verifySubscription内部是异步操作,返回的是一个Promise,onCall函数必须返回这个Promise,Firebase才能等待异步流程完成后,再把结果返回给客户端。

修改index.js

'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const subcheck = require('./subcheck');
admin.initializeApp();

exports.subcheck = functions.https.onCall((data, context) => {
  // 关键:返回verifySubscription的Promise,让Firebase等待异步操作完成
  return subcheck.verifySubscription(data, context);
});

第二步:完善subcheck.js的错误处理逻辑

你的subcheck.js中catch块没有返回错误信息,这会导致如果验证过程中出错,函数仍会返回undefined,客户端拿到的还是null。需要用Firebase推荐的错误处理方式,把错误信息传递给客户端。

修改subcheck.js的catch部分:

'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const key = require('./service-account-key.json'); // JSON key file
const {google} = require('googleapis');
const authClient = new google.auth.JWT({
  email: key.client_email,
  key: key.private_key,
  scopes: ["https://www.googleapis.com/auth/androidpublisher"]
});
const playDeveloperApiClient = google.androidpublisher({
  version: 'v3',
  auth: authClient
});

exports.verifySubscription = function(data, context) {
  const skuId = data.sku_id;
  const purchaseToken = data.purchase_token;
  const packageName = data.package_name;
  return authClient.authorize()
  .then(function(result) {
    return playDeveloperApiClient.purchases.subscriptions.get({
      packageName: packageName,
      subscriptionId: skuId,
      token: purchaseToken
    }).then(function(result) {
      if (result.status === 200) {
        console.log(result.data);
        return { data: result.data, status: 200, message: "Verified Subscription" };
      } else {
        console.log("Failed to verify subscription, Try again!");
        return { data: result.data, status: 500, message: "Failed to verify subscription, Try again!" };
      }
    })
    .catch(function(error) {
      console.log(error);
      // 抛出标准的HttpsError,让客户端能捕获到错误详情
      throw new functions.https.HttpsError('internal', 'Failed to fetch subscription data', error);
    });
  })
  .catch(function(error) {
    console.log(error);
    // 同样处理授权阶段的错误
    throw new functions.https.HttpsError('unauthenticated', 'Authorization failed', error);
  });
}

第三步:修复Android端的类型转换问题

你的Android代码把返回的getData()强转为String,但实际上Cloud Function返回的是一个JSON对象(对应Android里的Map),直接强转会得到无效的字符串甚至null。需要调整代码解析返回的对象:

private Task<Map<String, Object>> checkUserSubscribed(PurchaseHistoryRecord purchase) {
  Map<String, Object> mapUserPurchase = new HashMap<>();
  mapUserPurchase.put("sku_id", purchase.getSku());
  mapUserPurchase.put("purchase_token", purchase.getPurchaseToken());
  mapUserPurchase.put("package_name", "xxxxxxx");
  return mFirebaseFunctions
  .getHttpsCallable("subcheck")
  .call(mapUserPurchase)
  .continueWith(new Continuation<HttpsCallableResult, Map<String, Object>>() {
    @Override
    public Map<String, Object> then(@NonNull Task<HttpsCallableResult> task) throws Exception {
      // 直接获取返回的Map对象,对应Cloud Function返回的JSON
      return (Map<String, Object>) task.getResult().getData();
    }
  }).addOnCompleteListener(new OnCompleteListener<Map<String, Object>>() {
    @Override
    public void onComplete(@NonNull Task<Map<String, Object>> task) {
      if (task.isSuccessful()) {
        Map<String, Object> result = task.getResult();
        int status = ((Long) result.get("status")).intValue();
        String message = (String) result.get("message");
        Map<String, Object> subscriptionData = (Map<String, Object>) result.get("data");
        Toast.makeText(MainActivity.this, "验证结果: " + message + ", 状态码: " + status, Toast.LENGTH_SHORT).show();
        // 这里可以进一步处理subscriptionData中的订阅详情,比如过期时间、自动续费状态等
      } else {
        // 处理Cloud Function抛出的错误
        Exception e = task.getException();
        if (e instanceof FirebaseFunctionsException) {
          FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
          String errorMsg = ffe.getMessage();
          Toast.makeText(MainActivity.this, "错误: " + errorMsg, Toast.LENGTH_SHORT).show();
        }
      }
    }
  });
}

问题根源总结

Firebase的onCall函数如果不返回Promise,会在同步代码执行完毕后立即结束,此时异步操作(比如调用Play Developer API)还未完成,因此没有任何数据返回给客户端,导致Android端拿到null。返回Promise后,Firebase会等待异步流程完成,再把最终结果传递给客户端。

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

火山引擎 最新活动