Skip to content

移动端 SDK(仅限公钥) ​

移动端 SDK 在您的应用内显示 SOAMTAR 托管收银台,并告诉您它是如何结束的。它们从不创建付款,也从不持有私钥:只接受公钥(pk_test_… / pk_live_…),并拒绝 sk_… 密钥。

平台包主要入口
iOS (Swift)SoamtarSDK(Swift Package)1.0.1SoamtarCheckoutView、SoamtarCheckoutViewController
Android (Kotlin)com.soamtar:soamtar-android:1.1.0Soamtar.checkoutIntent()、SoamtarCheckoutActivity
Fluttersoamtar_sdk 1.0.1SoamtarCheckout 组件
React Native@soamtar/react-native 1.1.0<Checkout /> 组件

安装

这些包目前都尚未发布到公共仓库:在发布之前,请从 SOAMTAR 代码仓库安装。

工作原理 ​

  1. 应用将订单发送到您的后端。
  2. 您的后端使用私钥创建付款(POST/v1/payments),并传入您的 success_url 和 failed_url,然后把 data.payment_url(https://app.so-amtar.com/pay/checkout/{id})返回给应用。
  3. 应用通过 SDK 打开 payment_url。付款人输入其 Orange Money 号码(+232 加 8 位数字),并在自己的手机上用 Orange Money PIN 批准请求。PIN 绝不会经过您的应用。
  4. 托管结果页会重定向到您的 success_url 或 failed_url。SDK 在该跳转处停止并回调您。
  5. 您的后端在交付订单之前确认最终状态(webhook payment.success,或 GET/v1/payments/{id})。

SDK 回调不是付款凭证

onSuccess / STATUS_SUCCESS 仅表示 WebView 到达了您的 success_url。只有经过验证的 webhook 或使用私钥读取 API 的结果才能确认订单。

后端请求(示例) ​

bash
curl -X POST https://app.so-amtar.com/v1/payments \
  -H "Authorization: Bearer sk_test_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0c6f3a52-6a0e-4f43-9a0e-2a7f4b1d9e11" \
  -d '{
    "merchant_ref": "ORDER-42",
    "amount": "150.00",
    "currency": "SLE",
    "provider": "orange_money_sl",
    "success_url": "https://shop.example/orders/42/paid",
    "failed_url": "https://shop.example/orders/42/failed"
  }'

将 payment_url 连同相同的 success_url / failed_url 一起发送给应用:SDK 需要它们来识别收银台何时结束。使用 sk_test_ 密钥时,付款在同一主机上走模拟流程。

success_url 与 failed_url 请使用两个不同的路径

四个 SDK 都按 scheme、host 和 path 精确匹配 您的返回 URL。查询字符串和片段会被忽略,且绝不做前缀匹配。failed_url 优先检查:如果两个 URL 路径相同(例如 https://shop.example/return?status=ok 和 https://shop.example/return?status=ko),所有支付都会被报告为失败。请使用不同的路径,例如 /orders/42/paid 和 /orders/42/failed。

iOS (Swift) ​

要求:iOS 14+、Swift 5.7+、Xcode 14+。

安装(Swift Package Manager) ​

在 Xcode 中:File → Add Package Dependencies…,URL 填 https://github.com/soamtar/soamtar-ios-sdk,产品选 SoamtarSDK。或在 Package.swift 中:

swift
.package(url: "https://github.com/soamtar/soamtar-ios-sdk", from: "1.0.1")

配置(可选) ​

swift
import SoamtarSDK

Soamtar.shared.configure(publicKey: "pk_test_your_public_key")
// Anything other than pk_test_ / pk_live_ stops the app (fatalError).

SwiftUI ​

swift
import SwiftUI
import SoamtarSDK

struct PayButton: View {
    let paymentUrl: URL                 // from your backend
    @State private var showCheckout = false

    private let returnURLs = SoamtarReturnURLs(
        success: URL(string: "https://shop.example/orders/42/paid")!,
        failure: URL(string: "https://shop.example/orders/42/failed")!
    )

    var body: some View {
        Button("Pay \(SoamtarMoney.format("150.00") ?? "")") { showCheckout = true }  // "Pay Le 150.00"
            .sheet(isPresented: $showCheckout) {
                SoamtarCheckoutView(
                    paymentUrl: paymentUrl,
                    returnURLs: returnURLs,
                    onSuccess: { _ in showCheckout = false /* then confirm with your backend */ },
                    onFailure: { _ in showCheckout = false }
                )
            }
    }
}

UIKit ​

swift
let checkout = SoamtarCheckoutViewController(
    paymentUrl: paymentUrl,
    returnURLs: returnURLs,
    onSuccess: { [weak self] _ in self?.dismiss(animated: true) },
    onFailure: { [weak self] _ in self?.dismiss(animated: true) }
)
present(checkout, animated: true)

API ​

符号说明
Soamtar.shared.configure(publicKey:baseURL:)保存公钥。baseURL 默认为 https://app.so-amtar.com。
Soamtar.validatePublicKey(_:) throws密钥不以 pk_test_ / pk_live_ 开头时抛出 SoamtarError.invalidPublicKey。
Soamtar.shared.isCheckoutURL(_:) -> Bool对已配置主机上的 HTTPS …/pay/checkout/{id} 页面返回 true。
SoamtarReturnURLs(success:failure:)您的 success_url / failed_url;outcome(for:) 比较协议、主机和路径。
SoamtarCheckoutView(paymentUrl:returnURLs:onSuccess:onFailure:)SwiftUI 收银台(WKWebView)。每个回调都会收到匹配到的 URL。
SoamtarCheckoutViewController(…)UIKit 收银台,参数相同。
SoamtarMoney.format(_:currency:)Decimal 或十进制字符串 → "Le 1,250.00"。

Android (Kotlin) ​

要求:Android API 21+、Kotlin 1.8+。库的清单文件已声明 INTERNET 权限和收银台 Activity。

安装 ​

groovy
dependencies {
    implementation 'com.soamtar:soamtar-android:1.1.0'
}

初始化 ​

kotlin
import com.soamtar.sdk.Soamtar

Soamtar.init("pk_test_your_public_key")
// 非 pk_test_… / pk_live_… 的密钥会抛出 IllegalArgumentException。

打开收银台(Activity Result API) ​

kotlin
import com.soamtar.sdk.ui.SoamtarCheckoutActivity

private val checkoutLauncher = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { result ->
    when (result.data?.getStringExtra(SoamtarCheckoutActivity.RESULT_STATUS)) {
        SoamtarCheckoutActivity.STATUS_SUCCESS -> showPending("Confirming your payment…")
        SoamtarCheckoutActivity.STATUS_FAILED -> showError("Payment not completed.")
        else -> showPending("Checking your payment…") // closed by the payer
    }
    refreshOrderFromBackend() // the backend status is the source of truth
}

// paymentUrl, successUrl and failedUrl come from your backend
checkoutLauncher.launch(
    Soamtar.checkoutIntent(this, paymentUrl, successUrl = successUrl, failedUrl = failedUrl)
)

旧版 onActivityResult:

kotlin
Soamtar.checkout(this, paymentUrl, REQUEST_PAY, successUrl, failedUrl)

返回状态 ​

常量含义
SoamtarCheckoutActivity.STATUS_SUCCESS托管页面重定向到了 success_url
SoamtarCheckoutActivity.STATUS_FAILED托管页面重定向到了 failed_url(失败、过期或取消)
SoamtarCheckoutActivity.STATUS_CANCELLED付款人在任何重定向之前关闭了收银台

payment_url 必须是 SOAMTAR 主机(app.so-amtar.com)上的 HTTPS 地址。如果不传 successUrl / failedUrl,付款人会停留在 SOAMTAR 结果页,关闭时 Activity 返回 STATUS_CANCELLED。

当某次导航的 scheme、host 和 path 与 failedUrl 或 successUrl 完全相同时(忽略查询和片段,绝不按前缀匹配),收银台结束;failedUrl 优先检查。

显示金额 ​

kotlin
SoamtarMoney.formatLe(BigDecimal("1250"))   // "Le 1,250.00"
SoamtarMoney.formatLe("150.5")              // "Le 150.50" (null)
Soamtar.formatLe("2000000.00")              // "Le 2,000,000.00"

Flutter ​

要求:Dart 3.0+、Flutter 3.10+、webview_flutter 4.0+。

安装 ​

yaml
dependencies:
  soamtar_sdk:
    git:
      url: https://github.com/soamtar/soamtar_flutter_sdk
      ref: v1.0.1
bash
flutter pub get

Android:在 android/app/src/main/AndroidManifest.xml 中添加 <uses-permission android:name="android.permission.INTERNET"/>。iOS:无需额外配置。

使用 ​

dart
import 'package:flutter/material.dart';
import 'package:soamtar_sdk/soamtar_sdk.dart';

class PaymentPage extends StatelessWidget {
  const PaymentPage({super.key, required this.paymentUrl});

  /// `payment_url` received from your backend.
  final String paymentUrl;

  @override
  Widget build(BuildContext context) {
    final client = SoamtarClient('pk_test_your_public_key'); // ArgumentError on sk_
    if (!client.isCheckoutUrl(paymentUrl)) {
      return const Center(child: Text('Invalid payment link.'));
    }

    return Scaffold(
      appBar: AppBar(title: const Text('Pay with Orange Money')),
      body: SoamtarCheckout(
        paymentUrl: Uri.parse(paymentUrl),
        returnUrls: SoamtarReturnUrls(
          success: Uri.parse('https://shop.example/orders/42/paid'),
          failure: Uri.parse('https://shop.example/orders/42/failed'),
        ),
        onSuccess: (_) => Navigator.pop(context, true),  // then confirm with your backend
        onFailure: (_) => Navigator.pop(context, false),
      ),
    );
  }
}

显示金额:

dart
SoamtarMoney.format('1250.00');                    // "Le 1,250.00"
SoamtarMoney.formatMinorUnits(BigInt.from(15000)); // "Le 150.00"
符号说明
SoamtarClient(String publicKey, {Uri? baseUrl})仅限 pk_test_ / pk_live_。默认主机 https://app.so-amtar.com。isCheckoutUrl(url) 检查 HTTPS、主机和 /pay/checkout/…。
SoamtarCheckout({paymentUrl, returnUrls, onSuccess, onFailure})WebView 组件;只触发一个回调,且只触发一次。
SoamtarReturnUrls({success, failure})resultFor(uri) → SoamtarCheckoutResult.success / .failure / null。
SoamtarMoney.format / formatMinorUnits十进制字符串或整数分 → "Le 1,250.00"(从不使用 double)。

React Native ​

安装 ​

bash
npm install @soamtar/react-native react-native-webview

使用 ​

jsx
import { Client, Checkout } from '@soamtar/react-native';

const soamtar = new Client('pk_test_...'); // throws on a sk_ key

export function PayScreen({ navigation, route }) {
  // payment_url returned by your backend (must be https)
  const paymentUrl = soamtar.getCheckoutUrl(route.params.paymentUrl);

  return (
    <Checkout
      paymentUrl={paymentUrl}
      successUrl="https://shop.example/orders/42/paid"
      failureUrl="https://shop.example/orders/42/failed"
      onSuccess={() => navigation.replace('OrderStatus', { orderId: route.params.orderId })}
      onFailure={() => navigation.replace('PaymentFailed')}
      onError={(message) => console.warn(message)}
    />
  );
}
属性说明
paymentUrl(必填)POST/v1/payments 返回的 payment_url,必须是 https。
successUrl您发送的 success_url。到达时调用一次 onSuccess(url)。
failureUrl您发送的 failed_url。到达时调用一次 onFailure(url)。
onResult(url)已到达 SOAMTAR 结果页(/pay/result/{id}):付款已提交,正在确认。
onError(message)URL 无效、导航被拦截或 WebView 加载错误。
loaderColor加载指示器颜色(默认 #FF7900)。

Client 还提供 isTestMode(pk_test_ 密钥时为 true)。在收银台内,https 页面正常加载,http:、javascript: 和 data: URL 被拦截,其他协议(如 tel:)交给操作系统处理。

移动端安全 ​

  • 仅限公钥:所有 SDK 都拒绝私钥(sk_…),因为私钥可能被从 APK/IPA 中提取。
  • 隔离的 Web 视图:付款页面运行在 WKWebView / WebView 中,仅限 HTTPS。付款人在自己的手机上用 Orange Money PIN 确认;PIN 绝不会经过您的应用。
  • 不存储任何数据:SDK 不在设备上保存任何数据。
  • 服务端确认:应用只是一个展示层,交易在您的服务器上创建并确认。

SOAMTAR Payment API Documentation.