The WebView Approach
Instead of a native SDK, our gateway is integrated into Flutter applications using the official webview_flutter package. This method is simple, secure, and allows you to use our web-based payment pages directly inside your app, ensuring a consistent user experience without requiring any changes to our backend.
Step 1: Add Dependency
First, add the webview_flutter package to your project's pubspec.yaml file. Always check pub.dev for the latest version.
dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.7.0
Then, run flutter pub get in your terminal to install the package.
Step 2: Construct the Payment URL
In your Dart code, build the payment URL with your credentials and transaction details. This URL will be loaded into the WebView.
final String username = 'YOUR_USERNAME';
final String apiKey = 'YOUR_API_KEY';
final double amount = 50.00;
// Use a unique success URL to detect when the payment is complete.
final String successUrl = 'https://yourdomain.com/flutter/payment-success';
final String callbackUrl = 'https://yourbackend.com/payment_callback.php';
final Uri paymentUri = Uri.parse('https://pay.netpaybd.com/').replace(
queryParameters: {
'username': username,
'api': apiKey,
'amount': amount.toString(),
'success_url': successUrl,
'callback_url': callbackUrl,
},
);
Step 3: Implement the WebView Screen
Create a new Flutter screen (e.g., payment_webview_screen.dart) to display the payment page. This screen will contain the WebView and the logic to detect a successful payment.
The key part is the NavigationDelegate, which listens for URL changes. When the URL matches your successUrl, it means the payment was successful, and you can close the WebView.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class PaymentWebViewScreen extends StatefulWidget {
final Uri paymentUrl;
final String successUrl;
const PaymentWebViewScreen({
super.key,
required this.paymentUrl,
required this.successUrl,
});
@override
State createState() => _PaymentWebViewScreenState();
}
class _PaymentWebViewScreenState extends State {
late final WebViewController _controller;
var _loadingPercentage = 0;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (url) {
setState(() { _loadingPercentage = 0; });
},
onProgress: (progress) {
setState(() { _loadingPercentage = progress; });
},
onPageFinished: (url) {
setState(() { _loadingPercentage = 100; });
},
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith(widget.successUrl)) {
Navigator.pop(context, 'success');
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(widget.paymentUrl);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Complete Your Payment')),
body: Stack(
children: [
WebViewWidget(controller: _controller),
if (_loadingPercentage < 100)
LinearProgressIndicator(
value: _loadingPercentage / 100.0,
color: const Color(0xFF00BCD4),
),
],
),
);
}
}
Step 4: Launch the WebView and Get the Result
From your checkout page, launch the PaymentWebViewScreen and wait for it to return a result. You can use await Navigator.push(...) to handle this.
ElevatedButton(
onPressed: () async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PaymentWebViewScreen(
paymentUrl: paymentUri, // The URL you built in Step 2
successUrl: successUrl, // The same successUrl
),
),
);
if (result == 'success') {
// Payment was successful!
// Show a success message to the user.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment Successful!')),
);
} else {
// Payment failed or was cancelled.
// Show an error or cancellation message.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment Failed or Cancelled.')),
);
}
},
child: const Text('Pay Now'),
)
Important: While the app handles the user interface flow, your server should always rely on the Server-to-Server Callback (IPN) sent to your callback_url to securely verify the payment and update your database.