支付宝小程序是否支持航班飞行模式下的离线购物与支付?
结论
支付宝小程序可以通过定制开发实现这样的流程:起飞前联网进入商城,飞行期间离线浏览商品并暂存订单。但在完全断网的情况下,无法完成支付宝支付。
可行的流程是:
- 起飞前联网加载小程序、商品数据和必要图片。
- 飞行期间从本地缓存读取商品信息。
- 由乘务员协助创建离线订单草稿。
- 网络恢复后重新校验价格、库存和商品状态,再提交正式订单并发起支付。
如果要求旅客在飞行模式下直接完成扣款,并立即得到支付宝支付成功的结果,仅靠支付宝小程序无法实现。支付过程需要连接支付宝服务端和商户服务端。离线时无法创建、确认或查询有效的支付交易。
原因说明
小程序资源不等于业务数据自动离线
旅客联网打开小程序后,设备可能已经下载了部分小程序代码和静态资源,但商品列表、库存、价格、优惠资格和图片通常仍来自服务端。
因此,打开过小程序不代表商城断网后就能使用。开发方需要主动做好以下工作:
- 提前下载允许离线销售的商品快照。
- 将必要数据写入本地缓存。
- 确保关键图片等资源在断网前已经加载,或者直接打包进小程序资源包。
- 为离线页面单独设计数据读取和异常处理逻辑。
如果商城通过 web-view 加载 H5 页面,离线表现更难控制,不适合依赖浏览器缓存开展正式业务。
支付必须联网完成
支付宝支付涉及交易创建、身份验证、风控、扣款和支付结果确认。调用支付能力前,需要先取得服务端创建的交易信息,并连接支付宝服务。
以下调用只能在网络可用,并且已经取得有效 tradeNO 时执行:
my.tradePay({
tradeNO,
success(result) {
console.log('支付调用完成', result);
},
fail(error) {
console.error('支付失败', error);
}
});
离线时不能在本地预先生成一个”支付成功”结果,也不能把离线订单草稿当作已付款订单。商户服务端还需要确认最终支付结果,不能只依赖客户端回调。
推荐实现流程
1. 起飞前同步离线商品快照
联网时,从服务端获取本航班允许销售的商品、展示价格、图片地址和快照版本,并保存到本地。
function downloadOfflineCatalog(flightId) {
return new Promise((resolve, reject) => {
my.request({
url: 'https://example.com/api/offline-catalog',
method: 'GET',
data: { flightId },
success(res) {
const catalog = {
flightId,
version: res.data.version,
expiresAt: res.data.expiresAt,
products: res.data.products
};
my.setStorageSync({
key: `offline_catalog_${flightId}`,
data: catalog
});
resolve(catalog);
},
fail: reject
});
});
}
接口地址、字段和鉴权方式需要由业务系统自行定义。商品快照中不应保存支付凭证、密钥等敏感信息。
2. 飞行期间读取本地商品
断网后读取已经缓存的商品数据,并在页面上清楚显示数据更新时间和离线状态。
function getOfflineCatalog(flightId) {
const result = my.getStorageSync({
key: `offline_catalog_${flightId}`
});
const catalog = result && result.data;
if (!catalog || catalog.flightId !== flightId) {
throw new Error('未找到当前航班的离线商品数据');
}
if (catalog.expiresAt && Date.now() > catalog.expiresAt) {
throw new Error('离线商品数据已过期');
}
return catalog;
}
不能假设所有商品图片在离线时仍能显示。关键图片应提前下载或随小程序资源一起发布,同时还要评估小程序包体和本地存储限制。
3. 离线保存订单草稿
飞行期间只能创建状态为”待同步”的本地订单。订单中应包含客户端生成的幂等标识,以免恢复网络后重复提交。
function createOfflineOrderDraft({ flightId, items, operatorId }) {
const draft = {
clientOrderId: `${flightId}_${Date.now()}_${Math.random()
.toString(16)
.slice(2)}`,
flightId,
items,
operatorId,
createdAt: Date.now(),
status: 'PENDING_SYNC'
};
const result = my.getStorageSync({
key: 'offline_order_drafts'
});
const drafts = Array.isArray(result.data) ? result.data : [];
drafts.push(draft);
my.setStorageSync({
key: 'offline_order_drafts',
data: drafts
});
return draft;
}
Math.random() 在示例中仅用于拼接客户端标识,不适合生成安全令牌或支付凭证。生产环境应使用可靠的唯一标识方案,并由服务端通过幂等机制防止重复下单。
4. 联网后同步并重新确认
网络恢复后,将订单草稿提交给服务端。服务端必须重新检查:
- 商品是否仍然可售。
- 实际库存是否充足。
- 商品价格是否发生变化。
- 优惠和会员权益是否仍然有效。
- 同一个
clientOrderId是否已经处理。 - 订单是否属于对应的航班和操作人员。
function submitDraft(draft) {
return new Promise((resolve, reject) => {
my.request({
url: 'https://example.com/api/orders/sync',
method: 'POST',
data: draft,
success(res) {
if (!res.data || !res.data.tradeNO) {
reject(new Error('订单已同步,但暂时无法发起支付'));
return;
}
resolve(res.data);
},
fail: reject
});
});
}
订单同步成功后,再使用服务端返回的有效 tradeNO 调用 my.tradePay。如果价格或库存有变化,应先让旅客重新确认,不能直接按照离线快照扣款。
可选的业务方案
如果航空公司需要在飞行期间交付商品,可以采用”离线记账、联网后支付”的流程,但这不等于离线支付宝支付。是否允许先交付商品,需要航空公司自行评估坏账、退款、旅客身份核验和争议处理风险。
也可以在机上提供能够访问互联网的 Wi-Fi。只要旅客设备可以正常连接商户服务端和支付宝服务,支付就能按在线交易处理。如果只能连接机舱局域网,无法访问互联网,通常仍然不能完成支付宝支付。
注意事项
- “离线商城”是商户自行设计的离线业务能力,不能理解为支付宝提供了离线支付接口。
- 首次进入小程序、登录授权和更新小程序版本通常需要联网,必须在起飞前完成。
- 本地缓存可能被系统清理,不能作为唯一的订单存储方式。乘务员终端可以增加独立的订单留存和人工核对机制。
- 离线期间无法实时锁定中心库存,可能发生超卖,需要设置航班配额或机上独立库存。
- 订单草稿页面应明确标注”未提交”和”未支付”,避免旅客误以为已经付款。
- 支付状态、金额和库存结果不能由客户端自行判定,最终状态应以服务端校验结果为准。
- 存储旅客身份、手机号和订单信息时,应限制本地存储范围,并设计过期清理、加密和终端遗失处理方案。
my.getStorageSync、my.setStorageSync、my.request和my.tradePay的具体可用条件,应以目标支付宝小程序运行环境及当前官方文档为准,并在真机飞行模式下完成测试。
备注:内容仅供参考。
