flutter_payment_plugin 1.0.0 copy "flutter_payment_plugin: ^1.0.0" to clipboard
flutter_payment_plugin: ^1.0.0 copied to clipboard

Flutter Payment Plugin: simple payment initiation with WebView and return URL handling.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math';
import 'dart:async';
import 'dart:convert';

import 'package:flutter_payment_plugin/flutter_payment_plugin.dart';
import 'hash_generator.dart';


final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  final _plugin = FlutterPaymentPlugin();
  final _hasher = HashGenerator();
  StreamSubscription<String>? _logSub;

  // ====== Defaults (prefilled) ======
  final _baseUrlCtl = TextEditingController(text: 'https://pgbiz.omniware.in');

  // Merchant creds
  final _apiKeyCtl = TextEditingController(text: 'fb6bca86-b429-4abf-a42f-824bdd29022e');
  final _saltCtl   = TextEditingController(text: '80c67bfdf027da08de88ab5ba903fecafaab8f6d');

  // Payment fields (user inputs)
  final _orderIdCtl = TextEditingController();
  final _amountCtl = TextEditingController(text: '2');
  final _nameCtl = TextEditingController(text: 'Tester Sharma');
  final _phoneCtl = TextEditingController(text: '9876543210');
  final _emailCtl = TextEditingController(text: 'tester@example.com');
  final _returnUrlCtl = TextEditingController(text: 'https://pgbiz.omniware.in/tnpv2/return_page.php');
  final _descCtl = TextEditingController(text: 'Payment Short Description');
  final _currencyCtl = TextEditingController(text: 'INR');
  final _countryCtl = TextEditingController(text: 'IND');
  final _cityCtl = TextEditingController(text: 'Bangalore');
  final _stateCtl = TextEditingController(text: 'Karnataka');
  final _addr1Ctl = TextEditingController(text: 'ad1');
  final _addr2Ctl = TextEditingController(text: 'ad2');
  final _zipCtl = TextEditingController(text: '560001');
  final _enableAutoRefundCtl = TextEditingController(text: 'n');

  String _mode = 'LIVE'; // or TEST
  String _hash = '';
  String _lastStatusTitle = '';
  String _lastResponseJson = '';

  @override
  void initState() {
    super.initState();
    _initPlatformVersion();
    _orderIdCtl.text = _generateOrderId();
    _logSub = FlutterPaymentPlugin.logLines.listen((s) { debugPrint(s); });
  }

  Future<void> _initPlatformVersion() async {
    String pv;
    try {
      pv = await _plugin.getPlatformVersion() ?? 'Unknown platform version';
    } on PlatformException {
      pv = 'Failed to get platform version.';
    }
    if (!mounted) return;
    setState(() => _platformVersion = pv);
  }

  @override
  void dispose() {
    _logSub?.cancel();
    super.dispose();
  }

  String _generateOrderId() {
    const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const numbers = '0123456789';
    final r = Random();
    final letter = letters[r.nextInt(letters.length)];
    final digits = List.generate(3, (_) => numbers[r.nextInt(numbers.length)]).join();
    return '$letter$digits';
  }

  void _regenOrderId() {
    setState(() {
      _orderIdCtl.text = _generateOrderId();
    });
  }

  void _generateHash() {
    // CamelCase inputs for hashing (MUST match Swift keys)
    final camel = <String, String>{
      'mode': _mode,
      'amount': _amountCtl.text,
      'name': _nameCtl.text,
      'phone': _phoneCtl.text,
      'email': _emailCtl.text,
      'returnURL': _returnUrlCtl.text,
      'description': _descCtl.text,
      'currency': _currencyCtl.text,
      'country': _countryCtl.text,
      'city': _cityCtl.text,
      'state': _stateCtl.text,
      'addressLine1': _addr1Ctl.text,
      'addressLine2': _addr2Ctl.text,
      'zipCode': _zipCtl.text,
      'enable_auto_refund': _enableAutoRefundCtl.text,
      'orderID': _orderIdCtl.text,
    };

    final hash = _hasher.generateHash(
      salt: _saltCtl.text.trim(),
      apiKey: _apiKeyCtl.text.trim(),
      camelCaseInputs: camel,
    );

    setState(() => _hash = hash);
  }

  Future<void> _startPayment() async {
    // Basic field checks
    if (_baseUrlCtl.text.trim().isEmpty ||
        _apiKeyCtl.text.trim().isEmpty ||
        _saltCtl.text.trim().isEmpty) {
      _toast('Base URL, API Key and SALT are required');
      return;
    }
    if (_hash.isEmpty) {
      _generateHash(); // auto-generate if user forgot
      if (_hash.isEmpty) {
        _toast('Could not generate hash'); return;
      }
    }

    // Snake_case params for POST form
    final params = <String, String>{
      'api_key': _apiKeyCtl.text.trim(),
      'order_id': _orderIdCtl.text.trim(),
      'salt': _saltCtl.text.trim(),
      'hash': _hash,
      'mode': _mode,
      'amount': _amountCtl.text.trim(),
      'name': _nameCtl.text.trim(),
      'phone': _phoneCtl.text.trim(),
      'email': _emailCtl.text.trim(),
      'return_url': _returnUrlCtl.text.trim(),
      'description': _descCtl.text.trim(),
      'currency': _currencyCtl.text.trim(),
      'country': _countryCtl.text.trim(),
      'city': _cityCtl.text.trim(),
      'state': _stateCtl.text.trim(),
      'address_line_1': _addr1Ctl.text.trim(),
      'address_line_2': _addr2Ctl.text.trim(),
      'zip_code': _zipCtl.text.trim(),
      'udf1': '',
      'udf2': '',
      'udf3': '',
      'udf4': '',
      'udf5': '',
      'enable_auto_refund': _enableAutoRefundCtl.text.trim(),
    };

    try {
      final result = await FlutterPaymentPlugin.openPayment(
        url: _baseUrlCtl.text.trim(),
        params: params,
        title: 'Payment',
        javaScript: true,
        actionPath: 'v2/paymentrequest',
      );
      final message = result.cancelled
          ? 'Payment cancelled'
          : (result.success ? 'Payment success' : 'Payment finished with response');
      final pretty = _prettyJson(result.data);
      if (!mounted) return;
      setState(() {
        _lastStatusTitle = message;
        _lastResponseJson = pretty;
      });
    } on PlatformException catch (e) {
      if (!mounted) return;
      _toast('Failed to open Payment WebView: ${e.message}');
    }
  }

  String _prettyJson(String? s) {
    if (s == null || s.isEmpty) return '';
    try {
      final obj = jsonDecode(s);
      return const JsonEncoder.withIndent('  ').convert(obj);
    } catch (_) {
      return s;
    }
  }

  void _toast(String msg) {
    // Use the global key, not ScaffoldMessenger.of(context)
    final sm = scaffoldMessengerKey.currentState;
    sm?.clearSnackBars();
    sm?.showSnackBar(SnackBar(content: Text(msg)));
  }

  Widget _field(String label, TextEditingController ctl, {TextInputType? type, bool readOnly = false}) {
    return TextField(
      controller: ctl,
      readOnly: readOnly,
      keyboardType: type,
      decoration: InputDecoration(labelText: label, border: const OutlineInputBorder()),
    );
  }

  @override
  Widget build(BuildContext context) {
    final pad = const SizedBox(height: 12);

    return MaterialApp(
      scaffoldMessengerKey: scaffoldMessengerKey,
      home: Scaffold(
        appBar: AppBar(title: const Text('Omniware Payment Playground')),
        body: SafeArea(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Text('Running on: $_platformVersion • Plugin: ${FlutterPaymentPlugin.version}'),
                pad,
                _field('Base URL', _baseUrlCtl),
                pad,
                _field('API Key', _apiKeyCtl),
                pad,
                _field('SALT', _saltCtl),
                pad,
                Row(children: [
                  Expanded(child: _field('Order ID', _orderIdCtl)),
                  const SizedBox(width: 12),
                  ElevatedButton(onPressed: _regenOrderId, child: const Text('Generate Order ID')),
                ]),
                pad,
                Row(children: [
                  Expanded(
                    child: InputDecorator(
                      decoration: const InputDecoration(labelText: 'Mode', border: OutlineInputBorder()),
                      child: DropdownButtonHideUnderline(
                        child: DropdownButton<String>(
                          isExpanded: true,
                          value: _mode,
                          items: const [
                            DropdownMenuItem(value: 'LIVE', child: Text('LIVE')),
                            DropdownMenuItem(value: 'TEST', child: Text('TEST')),
                          ],
                          onChanged: (v) => setState(() => _mode = v ?? 'LIVE'),
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(width: 12),
                  Expanded(child: _field('Amount', _amountCtl, type: TextInputType.number)),
                ]),
                pad,
                _field('Name', _nameCtl),
                pad,
                Row(children: [
                  Expanded(child: _field('Phone', _phoneCtl, type: TextInputType.phone)),
                  const SizedBox(width: 12),
                  Expanded(child: _field('Email', _emailCtl, type: TextInputType.emailAddress)),
                ]),
                pad,
                _field('Return URL', _returnUrlCtl, type: TextInputType.url),
                pad,
                _field('Description', _descCtl),
                pad,
                Row(children: [
                  Expanded(child: _field('Currency', _currencyCtl)),
                  const SizedBox(width: 12),
                  Expanded(child: _field('Country', _countryCtl)),
                ]),
                pad,
                Row(children: [
                  Expanded(child: _field('City', _cityCtl)),
                  const SizedBox(width: 12),
                  Expanded(child: _field('State', _stateCtl)),
                ]),
                pad,
                Row(children: [
                  Expanded(child: _field('Address Line 1', _addr1Ctl)),
                  const SizedBox(width: 12),
                  Expanded(child: _field('Address Line 2', _addr2Ctl)),
                ]),
                pad,
                Row(children: [
                  Expanded(child: _field('ZIP Code', _zipCtl)),
                  const SizedBox(width: 12),
                  Expanded(child: _field('Enable Auto Refund (y/n)', _enableAutoRefundCtl)),
                ]),
                pad,
                Row(
                  children: [
                    Expanded(child: _field('Generated Hash (auto-upper)', TextEditingController(text: _hash), readOnly: true)),
                    const SizedBox(width: 12),
                    ElevatedButton(onPressed: _generateHash, child: const Text('Generate Hash')),
                  ],
                ),
                pad,
                ElevatedButton(
                  onPressed: _startPayment,
                  style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 14)),
                  child: const Text('Start Payment'),
                ),
                const SizedBox(height: 24),
                if (_lastStatusTitle.isNotEmpty || _lastResponseJson.isNotEmpty) ...[
                  Text(_lastStatusTitle, style: Theme.of(context).textTheme.titleMedium),
                  const SizedBox(height: 8),
                  Container(
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      color: Colors.black87,
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: SelectableText(
                      _lastResponseJson,
                      style: const TextStyle(fontFamily: 'monospace', color: Colors.white),
                    ),
                  ),
                  const SizedBox(height: 24),
                ],
              ],
            ),
          ),
        ),
      ),
    );
  }


}
0
likes
150
points
265
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter Payment Plugin: simple payment initiation with WebView and return URL handling.

Repository
View/report issues

Topics

#payments #webview #gateway #android #ios

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_web_plugins, plugin_platform_interface, web

More

Packages that depend on flutter_payment_plugin

Packages that implement flutter_payment_plugin