PAYATHON 2026

Firefox OS privileged packaged app 无法获取 fxpay 商品

支付阿杰

结论

404 BAD_API_RESPONSE 并不表示”商品列表为空”,而是 Firefox Marketplace 无法根据请求中的应用标识找到对应的应用。

日志显示,fxpay 使用的 origin 是:

http://url10.infinitgame.com

因此,请求地址变成了:

/api/v1/payments/http%3A%2F%2Furl10.infinitgame.com/in-app/

但这个 privileged packaged app 在清单中声明的应用源是:

app://url10.infinitgame.com

这两个 origin 并不相同。最常见的情况是,fxpay 实际运行在远程游戏门户页面中,而不是打包应用的 app:// 上下文中。

使用 real products 还有一个前提:应用已在 Firefox Marketplace 中建立对应记录,商品也归属于这个应用标识。至于应用是否必须”公开发布”,需要区分以下情况:

  • 应用必须先提交或注册到 Marketplace,才能为其创建真实商品并配置支付。
  • 是否需要向所有用户公开,取决于当时 Marketplace 的审核和发布流程。但未提交、未签名,或者仅通过 Simulator 本地安装的包,不能算作完整的 production Marketplace 应用。
  • Firefox OS Simulator 无法完整验证真实的运营商或 Bango 支付流程。最终测试需要在受支持的真实设备、国家和支付环境中完成。

为什么 fake products 可以正常工作

fake products 是 fxpay 在客户端生成的测试数据。它不查询 Marketplace,也不要求应用具有有效的 Marketplace 身份。

关闭 fake products 后:

fxpay.configure({
    fakeProducts: false
});

fxpay 会读取当前安装应用的信息,例如 navigator.mozApps.getSelf() 返回的应用对象及其 origin,然后访问 Marketplace 的商品 API。

如果 fxpay 运行在这个远程页面中:

http://url10.infinitgame.com

它拥有的只是普通 Web origin。即使该页面由 packaged app 打开,也不会自动继承:

app://url10.infinitgame.com

Marketplace 收到的因而是网站 origin,而不是 packaged app origin。应用标识不存在时,接口会返回 404 {"detail":"Not found"}。如果应用存在,只是没有启用任何商品,通常会成功返回一个空列表,而不是返回应用级别的 404。

将支付逻辑放回 packaged app

fxpay 库和调用支付 API 的代码应包含在应用包内,并由 app://url10.infinitgame.com 页面执行。例如:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>T-Games</title>
    <script src="/js/fxpay.min.js"></script>
    <script src="/js/payments.js"></script>
</head>
<body>
    <div id="portal"></div>
</body>
</html>

payments.js 可以先检查当前应用身份:

navigator.mozApps.getSelf().onsuccess = function () {
    var app = this.result;

    console.log("Installed app:", app);
    console.log("App origin:", app && app.origin);
    console.log("Manifest URL:", app && app.manifestURL);

    if (!app) {
        console.error("This page is not running as an installed packaged app");
        return;
    }

    fxpay.configure({
        fakeProducts: false
    });

    fxpay.getProducts().then(function (products) {
        console.log("Products:", products);
    }).catch(function (error) {
        console.error("Error getting products:", error);
    });
};

不同版本的 fxpay 可能使用略有差异的 Promise API,但有一点不变:调用代码必须运行在已安装 packaged app 的上下文中。

如果游戏门户仍需从服务器加载,可以由 packaged app 通过 XHR 获取数据,也可以把远程内容放进 iframe。支付操作应交给 packaged app 的父页面处理,远程页面通过 postMessage 请求父页面发起购买。不要让 iframe 或跳转后的远程页面直接调用 fxpay。

核对 Marketplace 中的应用 origin

Marketplace 商品必须绑定到同一个应用记录。请确认以下三处完全一致:

  1. 安装后的应用对象:
navigator.mozApps.getSelf().onsuccess = function () {
    console.log(this.result.origin);
    console.log(this.result.manifestURL);
};
  1. 提交到 Marketplace 的 packaged app manifest。
  2. 创建 real products 时选择的 Marketplace 应用。

如果安装后的结果是:

app://url10.infinitgame.com

商品 API 就应按这个 origin 查询,而不是使用:

http://url10.infinitgame.com

不要试图通过手工拼接 API URL 修复这个问题。应先修正 fxpay 的执行环境和应用安装方式,让它从已安装的应用对象中读取正确身份。

另外:

"developer": {
    "url": "http://url0.infinitgame.com"
}

这里填写的是开发者信息,不会决定支付 API 使用哪个应用 origin。

manifest 建议

可以继续使用自定义 packaged-app origin,但它必须与 Marketplace 中登记并签名的应用保持一致:

{
    "version": "1.0.0",
    "name": "T-Games",
    "description": "T-games service de malade",
    "launch_path": "/index.html",
    "type": "privileged",
    "origin": "app://url10.infinitgame.com",
    "icons": {
        "16": "/img/icon-16.png",
        "48": "/img/icon-48.png",
        "128": "/img/icon-128.png"
    },
    "developer": {
        "name": "Serial Screener",
        "url": "http://url0.infinitgame.com"
    },
    "permissions": {
        "systemXHR": {
            "description": "Required to access payment API"
        }
    },
    "chrome": {
        "navigation": true
    },
    "csp": "default-src 'self'; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'"
}

如果 Marketplace 在提交过程中为应用分配了其他 app:// origin,应以实际安装后的 app.origin 和 Marketplace 应用记录为准。创建商品或发放收据后,不要随意修改 origin。对支付系统来说,新的 origin 通常意味着另一个应用。

原配置中的:

"default-src *"

范围过宽。虽然这不是此次 404 的直接原因,但 privileged app 应尽量限制允许加载和连接的来源。如果需要访问远程游戏服务,可以明确添加 connect-src、img-src 或 frame-src,不必开放所有默认来源。

推荐的排查顺序

  1. 确认 fxpay 文件确实包含在 ZIP 包内,而不是只部署在游戏门户服务器上。
  2. 确认调用 fxpay.getProducts() 的页面仍是 app://... 页面,没有提前跳转到 http://...。
  3. 输出 navigator.mozApps.getSelf() 的 origin 和 manifestURL。
  4. 确认 Marketplace 中的商品属于同一个应用记录,并且处于 active 状态。
  5. 从 Marketplace 提供的正式或审核安装渠道安装签名包,不要只根据 Simulator 的本地开发安装结果判断 production payments 是否可用。
  6. 在真实 Firefox OS 设备上验证购买流程,同时检查国家、运营商、Bango 账户和商品可售区域是否匹配。

当前首先要修正的是请求中错误的 http:// 应用身份,而不是商品本身。只有让 fxpay 在正确的 packaged-app 上下文中运行,并确保该身份与 Marketplace 中的应用及商品记录一致,才能正确查询 real products。

备注:内容仅供参考。