@reeple/sdk is a browser/DOM-based library (it renders a modal and iframe) — it does not run inside Flutter’s Dart runtime. There is no native Reeple SDK for Flutter. The pattern below is the standard workaround used for web-based checkout SDKs on mobile: load a small hosted HTML page in a WebView and bridge its events back to Dart via a JavaScript channel.
1. Host a bridge HTML page
Host this page yourself (e.g. as a static file on your own domain) — it embeds the CDN script and posts SDK events back through a JavaScript channel named ReepleChannel.
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8" /></head>
<body>
<script src="https://payment.reeple.ai/reeple.iife.min.js"></script>
<script>
function post(type, payload) {
ReepleChannel.postMessage(JSON.stringify({ type, payload }));
}
const params = new URLSearchParams(window.location.search);
const reeple = new Reeple({
publicKey: params.get('publicKey'),
amount: Number(params.get('amount')),
currency: params.get('currency'),
narration: params.get('narration'),
customer: {
email: params.get('email'),
firstName: params.get('firstName'),
lastName: params.get('lastName'),
phoneNumber: params.get('phoneNumber'),
},
meta: {},
callbackUrl: window.location.href,
onSuccess: (data) => post('success', data),
onClose: () => post('close'),
onError: (err) => post('error', { message: err.message }),
});
reeple.open();
</script>
</body>
</html>
Pass the payment details as query params when loading the page from the WebView (see below).
2. Load it from Flutter
dependencies:
webview_flutter: ^4.0.0
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class CheckoutScreen extends StatefulWidget {
const CheckoutScreen({super.key});
@override
State<CheckoutScreen> createState() => _CheckoutScreenState();
}
class _CheckoutScreenState extends State<CheckoutScreen> {
late final WebViewController controller;
@override
void initState() {
super.initState();
final checkoutUrl = Uri.parse('https://yoursite.com/reeple-checkout.html').replace(
queryParameters: {
'publicKey': 'pk_live_your_key_here',
'amount': '5000',
'currency': 'NGN',
'narration': 'Order #1234',
'email': 'customer@example.com',
'firstName': 'John',
'lastName': 'Doe',
'phoneNumber': '+2348012345678',
},
);
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'ReepleChannel',
onMessageReceived: (message) {
final data = jsonDecode(message.message);
switch (data['type']) {
case 'success':
debugPrint('Payment successful: ${data['payload']}');
break;
case 'close':
debugPrint('Modal closed');
break;
case 'error':
debugPrint('Payment error: ${data['payload']['message']}');
break;
}
},
)
..loadRequest(checkoutUrl);
}
@override
Widget build(BuildContext context) {
return WebViewWidget(controller: controller);
}
}
Verify the payment on your server using the reference from the success payload — see Callbacks & Verification. Never mark an order paid based solely on the WebView message.