حزم SDK للهاتف المحمول (المفاتيح العامة فقط)
تعرض حزم SDK للهاتف المحمول صفحة الدفع المستضافة من SOAMTAR داخل تطبيقك وتخبرك بكيفية انتهائها. لا تُنشئ هذه الحزم أي دفعة ولا تحتفظ بأي مفتاح سرّي: فهي تقبل المفاتيح العامة فقط (pk_test_… / pk_live_…) وترفض مفاتيح sk_….
| المنصة | الحزمة | نقاط الدخول الرئيسية |
|---|---|---|
| iOS (Swift) | SoamtarSDK (Swift Package) 1.0.1 | SoamtarCheckoutView، SoamtarCheckoutViewController |
| Android (Kotlin) | com.soamtar:soamtar-android:1.1.0 | Soamtar.checkoutIntent()، SoamtarCheckoutActivity |
| Flutter | soamtar_sdk 1.0.1 | المكوّن SoamtarCheckout |
| React Native | @soamtar/react-native 1.1.0 | المكوّن <Checkout /> |
التثبيت
لم تُنشر أي من هذه الحزم بعد في سجل عام: ثبّتها من مستودع SOAMTAR إلى حين نشرها.
آلية العمل
- يرسل التطبيق الطلب إلى خادمك الخلفي.
- يُنشئ خادمك الخلفي الدفعة باستخدام مفتاحه السرّي (
POST/v1/payments) معsuccess_urlوfailed_url، ثم يعيدdata.payment_url(https://app.so-amtar.com/pay/checkout/{id}) إلى التطبيق. - يفتح التطبيق
payment_urlعبر الحزمة. يُدخل الدافع رقم Orange Money الخاص به (+232متبوعًا بـ 8 أرقام) ويوافق على الطلب على هاتفه برمز PIN الخاص بـ Orange Money. لا يمر رمز PIN أبدًا عبر تطبيقك. - تعيد صفحة النتيجة المستضافة التوجيه إلى
success_urlأوfailed_url. تتوقف الحزمة عند هذا الانتقال وتستدعي الدالة الخاصة بك. - يؤكد خادمك الخلفي الحالة النهائية (webhook
payment.successأوGET/v1/payments/{id}) قبل تسليم الطلب.
استدعاء الحزمة ليس إثباتًا للدفع
onSuccess / STATUS_SUCCESS يعني فقط أن WebView وصل إلى success_url. وحده webhook موثَّق أو قراءة من الـ API بمفتاحك السرّي يؤكد الطلب.
طلب الخادم الخلفي (مثال)
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: تحتاجها الحزم لاكتشاف نهاية عملية الدفع. مع مفاتيح sk_test_ تمر الدفعة عبر المحاكاة على نفس المضيف.
استخدم مسارين مختلفين لـ success_url وfailed_url
تطابق حزم SDK الأربع التنقّل مع عناوين العودة تطابقًا تامًا في المخطط والمضيف والمسار. تُتجاهل سلسلة الاستعلام والجزء (fragment)، ولا تكون المطابقة أبدًا بالبادئة. يُفحص failed_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…، الرابط https://github.com/soamtar/soamtar-ios-sdk، المنتج SoamtarSDK. أو في Package.swift:
.package(url: "https://github.com/soamtar/soamtar-ios-sdk", from: "1.0.1")الإعداد (اختياري)
import SoamtarSDK
Soamtar.shared.configure(publicKey: "pk_test_your_public_key")
// Anything other than pk_test_ / pk_live_ stops the app (fatalError).SwiftUI
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
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 | يرمي SoamtarError.invalidPublicKey إذا لم يبدأ المفتاح بـ pk_test_ / pk_live_. |
Soamtar.shared.isCheckoutURL(_:) -> Bool | true لصفحة HTTPS من الشكل …/pay/checkout/{id} على المضيف المُعدّ. |
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+. يصرّح ملف manifest الخاص بالمكتبة بإذن INTERNET وبنشاط صفحة الدفع.
التثبيت
dependencies {
implementation 'com.soamtar:soamtar-android:1.1.0'
}التهيئة
import com.soamtar.sdk.Soamtar
Soamtar.init("pk_test_your_public_key")
// أي مفتاح غير pk_test_… / pk_live_… يرمي IllegalArgumentException.فتح صفحة الدفع (Activity Result API)
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:
Soamtar.checkout(this, paymentUrl, REQUEST_PAY, successUrl, failedUrl)الحالات المُعادة
| الثابت | المعنى |
|---|---|
SoamtarCheckoutActivity.STATUS_SUCCESS | أعادت الصفحة المستضافة التوجيه إلى success_url |
SoamtarCheckoutActivity.STATUS_FAILED | أعادت الصفحة المستضافة التوجيه إلى failed_url (فشل أو انتهاء صلاحية أو إلغاء) |
SoamtarCheckoutActivity.STATUS_CANCELLED | أغلق الدافع صفحة الدفع قبل أي إعادة توجيه |
يجب أن يكون payment_url رابط HTTPS على مضيف SOAMTAR (app.so-amtar.com). بدون successUrl / failedUrl يبقى الدافع على صفحة نتيجة SOAMTAR ويعيد النشاط STATUS_CANCELLED عند إغلاقها.
تتوقف صفحة الدفع عندما يكون للتنقّل المخطط والمضيف والمسار نفسها لـ failedUrl أو successUrl (مع تجاهل الاستعلام والجزء، ودون مطابقة بالبادئة أبدًا)؛ ويُفحص failedUrl أولًا.
عرض مبلغ
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+.
التثبيت
dependencies:
soamtar_sdk:
git:
url: https://github.com/soamtar/soamtar_flutter_sdk
ref: v1.0.1flutter pub getAndroid: أضف <uses-permission android:name="android.permission.INTERNET"/> إلى android/app/src/main/AndroidManifest.xml. iOS: لا حاجة لأي إعداد.
الاستخدام
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),
),
);
}
}عرض مبلغ:
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
التثبيت
npm install @soamtar/react-native react-native-webviewالاستخدام
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 (إلزامية) | payment_url المُعاد من POST/v1/payments. يجب أن يكون https. |
successUrl | قيمة success_url التي أرسلتها. الوصول إليها يستدعي onSuccess(url) مرة واحدة. |
failureUrl | قيمة failed_url التي أرسلتها. الوصول إليها يستدعي onFailure(url) مرة واحدة. |
onResult(url) | تم الوصول إلى صفحة نتيجة SOAMTAR (/pay/result/{id}): أُرسلت الدفعة وجارٍ تأكيدها. |
onError(message) | رابط غير صالح أو انتقال محظور أو خطأ في تحميل WebView. |
loaderColor | لون مؤشر التحميل (الافتراضي #FF7900). |
يوفّر Client أيضًا isTestMode (true مع مفاتيح pk_test_). داخل صفحة الدفع تُحمَّل صفحات https، وتُحظر روابط http: وjavascript: وdata:، وتُسلَّم البروتوكولات الأخرى (مثل tel:) إلى نظام التشغيل.
أمان الهاتف المحمول
- المفاتيح العامة فقط: ترفض جميع الحزم المفاتيح السرّية (
sk_…) التي يمكن استخراجها من ملف APK/IPA. - عرض ويب معزول: تعمل صفحة الدفع داخل
WKWebView/WebViewعبر HTTPS فقط. يؤكد الدافع برمز PIN الخاص بـ Orange Money على هاتفه؛ لا يمر رمز PIN أبدًا عبر تطبيقك. - لا تخزين: لا تحتفظ الحزم بأي بيانات على الجهاز.
- تأكيد من جهة الخادم: التطبيق مجرد طبقة عرض لمعاملة أُنشئت وتأكدت على خادمك.