Guide
Guide Flutter pour exécuter le flux de transaction YKNPG depuis une app mobile (démo de développement).
Guide Flutter pour exécuter le flux de transaction YKNPG depuis une app mobile (démo de développement).
Note sécurité
- Stockez le jeton bearer de façon sûre (config distante ou proxy backend). Utiliser
.envdans l'app sert uniquement aux tests locaux.
Pré-requis
- SDK Flutter, Dart 3+.
- Créer l'app
flutter create demo_yknpg && cd demo_yknpg
- Ajouter les dépendances
flutter pub add http flutter_dotenv
- Ajouter le fichier d'environnement
- Fichier :
.env
YKNPG_API_TOKEN=remplacez-par-votre-jeton
YKNPG_BASE_URL=https://yknpg.ngoul.com/api/v1
- Mettre à jour
pubspec.yamlpour inclure le fichier :
flutter:
assets:
- .env
- Créer un helper API
- Fichier :
lib/yknpg_api.dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:http/http.dart' as http;
final _baseUrl = dotenv.env['YKNPG_BASE_URL'] ?? 'https://yknpg.ngoul.com/api/v1';
final _headers = {
HttpHeaders.authorizationHeader: 'Bearer ${dotenv.env['YKNPG_API_TOKEN']}',
HttpHeaders.contentTypeHeader: 'application/json',
};
Future<Map<String, dynamic>> startTransaction(int amount, String phone) async {
final payload = {
'amount': amount,
'provider': 'ORANGE_MONEY',
'user_infos': {'number': phone},
'callback_url': 'http://example.com',
'callback_method': 'POST',
'your_message': 'pay this',
'your_order_ref': 'demo-1',
'provider_fees_on_customer': true,
};
final create = await http.post(Uri.parse("$_baseUrl/transactions/"),
headers: _headers, body: jsonEncode(payload));
if (create.statusCode >= 400) throw create.body;
final created = jsonDecode(create.body) as Map<String, dynamic>;
final pay = await http.post(
Uri.parse("$_baseUrl/transactions/${created['uuid']}/pay/"),
headers: _headers);
if (pay.statusCode >= 400) throw pay.body;
final paid = jsonDecode(pay.body) as Map<String, dynamic>;
var status = paid['status'] as String;
while (status == 'new' || status == 'paying') {
await Future.delayed(const Duration(seconds: 5));
final poll = await http.get(
Uri.parse("$_baseUrl/transactions/${created['uuid']}/"),
headers: _headers);
if (poll.statusCode >= 400) throw poll.body;
status = (jsonDecode(poll.body) as Map<String, dynamic>)['status'] as String;
}
return {
'created': created,
'paid': paid,
'finalStatus': status,
};
}
- Mettre à jour l'UI
- Fichier :
lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'yknpg_api.dart';
Future<void> main() async {
await dotenv.load(fileName: ".env");
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PaymentPage(),
);
}
}
class PaymentPage extends StatefulWidget {
@override
State<PaymentPage> createState() => _PaymentPageState();
}
class _PaymentPageState extends State<PaymentPage> {
final _phoneCtrl = TextEditingController();
final _amountCtrl = TextEditingController(text: '1000');
String _status = '';
bool _loading = false;
Future<void> _submit() async {
setState(() {
_loading = true;
_status = '';
});
try {
final result = await startTransaction(
int.parse(_amountCtrl.text), _phoneCtrl.text);
setState(() {
_status =
"Gateway: ${result['created']['instructions']}\nPost-pay: ${result['paid']['instructions']}\nFinal status: ${result['finalStatus']}";
});
} catch (e) {
setState(() {
_status = 'Error: $e';
});
} finally {
setState(() {
_loading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Start payment')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextField(controller: _phoneCtrl, decoration: const InputDecoration(labelText: 'Phone')),
TextField(
controller: _amountCtrl,
decoration: const InputDecoration(labelText: 'Amount'),
keyboardType: TextInputType.number,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _loading ? null : _submit,
child: Text(_loading ? 'Processing...' : 'Pay'),
),
const SizedBox(height: 16),
Text(_status),
],
),
),
);
}
}
- Exécuter
flutter run
Remarques
- Déplacez le jeton vers un backend sécurisé ou une gestion de clés pour la production.