Flutter 移动应用如何接入 Sham Cash 官方 API 或 SDK?
结论
现有资料无法证明 Sham Cash 提供面向第三方应用的公开 API、Flutter SDK、商户接入文档,也无法确认是否有可直接使用的 redirect flow、deep link 或 partner API。
目前不宜直接把 Sham Cash 作为已有公开接口的支付渠道进行开发。官网没有公开文档,不代表内部一定没有合作伙伴接口;即使有,也通常需要通过 Sham Cash 官方审核,并取得协议、凭据和技术文档。在拿到这些材料前,不要猜测接口地址、参数或回调格式。
建议的接入流程
先通过 Sham Cash 官方客服或商务渠道申请商户合作,并确认:
- 是否接受第三方移动应用或互联网商户接入。
- 是否提供 merchant API、partner API、托管收银台或支付链接。
- 是否支持测试环境、测试账户和测试币种。
- 是否有 Android、iOS、Flutter 或通用 REST API 文档。
- 是否支持 redirect URL、return URL 和 webhook。
- 是否提供请求签名、回调验签和订单查询机制。
- 是否允许通过 deep link 唤起 Sham Cash 客户端。
- 商户审核、结算、退款和争议处理有哪些规则。
如果官方确认暂不支持第三方集成,Flutter 端也没有可靠的技术手段绕过这一限制。可以暂时隐藏该支付方式,或者使用官方提供的线下收款流程,但不能把线下流程包装成未经授权的自动支付接口。
官方可能提供的接入形式
如果 Sham Cash 后续开放合作,接入方式可能包括以下几类,具体以正式文档和合同为准。
原生 SDK
如果官方分别提供 Android 和 iOS SDK,Flutter 可以通过 platform channel 调用原生能力。具体实现要等拿到 SDK、初始化参数和回调说明后才能确定。
import 'package:flutter/services.dart';
class ShamCashBridge {
static const MethodChannel _channel =
MethodChannel('example.app/sham_cash');
Future<Map<String, dynamic>> startPayment({
required String merchantOrderId,
required String paymentToken,
}) async {
final result = await _channel.invokeMapMethod<String, dynamic>(
'startPayment',
{
'merchantOrderId': merchantOrderId,
'paymentToken': paymentToken,
},
);
if (result == null) {
throw StateError('Payment SDK returned no result');
}
return result;
}
}
这段代码只展示 Flutter 与原生 SDK 之间的桥接结构,并不表示 Sham Cash 已经提供对应的方法或参数。实际的 channel 名称、方法名和字段都要按照官方 SDK 调整。
托管收银台或 redirect flow
如果官方接口会返回托管支付页面的地址,可以由自己的服务端创建支付会话,再让 Flutter 打开该页面。
import 'package:url_launcher/url_launcher.dart';
Future<void> openCheckout(String checkoutUrl) async {
final uri = Uri.parse(checkoutUrl);
if (uri.scheme != 'https') {
throw ArgumentError('Checkout URL must use HTTPS');
}
final opened = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!opened) {
throw StateError('Unable to open checkout page');
}
}
checkoutUrl 应由应用后端通过官方接口获取。客户端不应自行拼接未经文档确认的 Sham Cash URL,也不能只凭浏览器跳转结果将订单标记为支付成功。
Deep link 或 App Link
只有官方公布 URI scheme、Universal Link 或 Android App Link 格式后,才能采用这种方式。自行猜测 shamcash://pay 一类地址并不可靠,也可能违反平台或服务条款。
即使支付客户端能通过 deep link 返回应用,返回结果通常也只能用于更新界面。最终支付状态仍要由后端查询,或者通过验签后的 webhook 确认。
Partner API
私有 partner API 通常没有公开注册入口。商户完成商务签约或技术审核后,才可能取得:
- 接口文档和测试环境;
- merchant ID、API key 或证书;
- 请求签名及回调验签规则;
- IP 白名单或证书要求;
- 退款、撤销和订单查询接口;
- 上线检查要求与生产环境凭据。
没有正式凭据时,即使发现疑似接口,也不应通过抓包或逆向消费者客户端来调用。
Flutter 项目如何预留支付接口
等待官方答复期间,可以先将业务层和具体支付渠道分开,避免把尚未确认的字段写死在页面里。
abstract interface class PaymentGateway {
Future<PaymentStartResult> startPayment({
required String orderId,
});
}
class PaymentStartResult {
const PaymentStartResult({
required this.checkoutUri,
});
final Uri checkoutUri;
}
class ShamCashGateway implements PaymentGateway {
ShamCashGateway(this.backend);
final PaymentBackend backend;
@override
Future<PaymentStartResult> startPayment({
required String orderId,
}) async {
// 此处调用的是应用自己的后端,不是未经确认的 Sham Cash API。
final checkoutUrl = await backend.createShamCashSession(orderId);
return PaymentStartResult(
checkoutUri: Uri.parse(checkoutUrl),
);
}
}
abstract interface class PaymentBackend {
Future<String> createShamCashSession(String orderId);
}
如果官方最终提供 SDK,可以替换 ShamCashGateway 的实现。如果提供托管收银台,则由后端创建会话并返回支付地址,无需整体重写业务页面。
服务端负责的工作
支付密钥、签名私钥和商户凭据不应放入 Flutter 安装包。移动端代码可以被反编译,编译时写入的所谓“隐藏密钥”仍有可能被提取。
正式接入后,服务端至少要负责:
- 根据内部订单创建支付请求。
- 保存第三方交易号与商户订单号的对应关系。
- 验证 webhook 的签名、时间戳和金额。
- 使用幂等机制处理重复通知。
- 必要时调用官方订单查询接口复核状态。
- 服务端确认到账后,再将订单更新为已支付。
不能只凭客户端收到的 success、返回页面参数或截图确认到账。
接入前需要确认的细节
拿到接口文档后,需要检查金额单位、币种、订单号长度、超时时间、退款能力和回调重试策略。金额究竟使用小数还是最小货币单位尤其要确认,否则可能出现数量级错误。
安全要求也要逐项核对:
- API 是否强制使用 HTTPS。
- 请求签名包含哪些字段。
- webhook 是否提供证书、签名或来源校验。
- 同一订单能否重复发起支付。
- 回调结果与主动查询结果冲突时,以哪个为准。
- 用户取消、处理中、超时和失败分别如何表示。
这些规则不能照搬其他支付平台,必须以 Sham Cash 的正式说明为准。
不建议采用的做法
缺少官方接入方案时,不要:
- 抓取或调用 Sham Cash 消费者应用的内部接口;
- 模拟登录、短信验证码或用户操作;
- 猜测 deep link、接口路径和签名算法;
- 把账号密码、API key 或私钥写入 Flutter 代码;
- 根据网页 DOM、截图或客户端跳转判断支付成功;
- 使用来源不明的第三方“Sham Cash SDK”。
这些方案容易失效,也会增加账户安全、资金对账和合规风险。
如果 Sham Cash 官方无法提供商户接入文档或书面确认,Flutter 应用目前就无法进行受官方支持的自动化支付集成。取得官方技术资料后,再根据其提供的 SDK、托管收银台或 partner API 选择接入方案。
备注:内容仅供参考。
