Skip to main content

khalti_checkout_flutter 2.0.0-beta.1 copy "khalti_checkout_flutter: ^2.0.0-beta.1" to clipboard
khalti_checkout_flutter: ^2.0.0-beta.1 copied to clipboard

An official Flutter plugin for Khalti Payment Gateway, with all the necessary interface that make it easy to integrate with your app.

example/lib/main.dart

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:khalti_checkout_flutter/khalti_checkout_flutter.dart';

void main() {
  runApp(
    const MaterialApp(
      home: KhaltiSDKDemo(),
    ),
  );
}

class KhaltiSDKDemo extends StatefulWidget {
  const KhaltiSDKDemo({super.key});

  @override
  State<KhaltiSDKDemo> createState() => _KhaltiSDKDemoState();
}

class _KhaltiSDKDemoState extends State<KhaltiSDKDemo> {
  final _formKey = GlobalKey<FormState>();
  final _paymentUrlController = TextEditingController();

  PaymentResult? paymentResult;

  /// Last non-payment outcome reported through `onMessage` (cancelled, expired, error...).
  String? message;

  @override
  void dispose() {
    _paymentUrlController.dispose();
    super.dispose();
  }

  Future<void> _pay() async {
    if (!_formKey.currentState!.validate()) return;

    final paymentUrl = _paymentUrlController.text.trim();
    setState(() {
      paymentResult = null;
      message = null;
    });

    final khalti = await Khalti.init(
      enableDebugging: true,
      payConfig: KhaltiPayConfig(
        publicKey:
            '4aa1b684f4de4860968552558fc8487d', // This is a dummy public key for example purpose
        environment: _environmentOf(paymentUrl),
        paymentUrl: paymentUrl,
      ),
      onPaymentResult: (paymentResult, khalti) {
        log(paymentResult.toString());
        setState(() {
          this.paymentResult = paymentResult;
          message = null;
        });
        khalti.close(context);
      },
      onMessage: (
        khalti, {
        description,
        statusCode,
        event,
        needsPaymentConfirmation,
      }) async {
        log(
          'Description: $description, Status Code: $statusCode, Event: $event, NeedsPaymentConfirmation: $needsPaymentConfirmation',
        );
        setState(() {
          paymentResult = null;
          message = 'Event: $event\n'
              'Description: ${_shorten(description)}\n'
              'Status Code: $statusCode\n'
              'Needs Payment Confirmation: $needsPaymentConfirmation';
        });
        khalti.close(context);
      },
      onReturn: () => log('Successfully redirected to return_url.'),
    );

    if (!mounted) return;
    await khalti.open(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(24),
          child: Form(
            key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                const SizedBox(height: 24),
                Image.asset(
                  'assets/seru.png',
                  height: 160,
                  width: 160,
                ),
                const SizedBox(height: 32),
                TextFormField(
                  controller: _paymentUrlController,
                  keyboardType: TextInputType.url,
                  autocorrect: false,
                  textInputAction: TextInputAction.done,
                  decoration: const InputDecoration(
                    labelText: 'Payment URL',
                    hintText: 'https://test-pay.khalti.com/?pidx=...',
                    helperText:
                        'The payment_url received after initiating the payment.',
                    border: OutlineInputBorder(),
                  ),
                  validator: _validatePaymentUrl,
                  onFieldSubmitted: (_) => _pay(),
                ),
                const SizedBox(height: 16),
                OutlinedButton(
                  onPressed: _pay,
                  child: const Text('Pay with Khalti'),
                ),
                const SizedBox(height: 32),
                if (message != null)
                  Text(
                    message!,
                    textAlign: TextAlign.center,
                    style: const TextStyle(fontSize: 15, color: Colors.red),
                  )
                else if (paymentResult != null)
                  Column(
                    children: [
                      Text('pidx: ${paymentResult!.payload?.pidx}'),
                      Text('Status: ${paymentResult!.payload?.status}'),
                      Text(
                        'Amount Paid: ${paymentResult!.payload?.totalAmount}',
                      ),
                      Text(
                        'Transaction ID: ${paymentResult!.payload?.transactionId}',
                      ),
                    ],
                  ),
                const SizedBox(height: 32),
                const Text(
                  'This is a demo application developed by some merchant.',
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 12),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

/// Validates that the input is an http(s) URL carrying a non-empty `pidx`,
/// which is what the SDK reads the payment identifier from.
String? _validatePaymentUrl(String? value) {
  final input = value?.trim() ?? '';
  if (input.isEmpty) return 'Enter the payment URL';

  final uri = Uri.tryParse(input);
  if (uri == null ||
      !uri.hasScheme ||
      !uri.isScheme('https') && !uri.isScheme('http')) {
    return 'Enter a valid URL';
  }

  if ((uri.queryParameters['pidx'] ?? '').isEmpty) {
    return 'The URL has no pidx';
  }
  return null;
}

/// Payment URLs on the test host run against the test environment.
Environment _environmentOf(String paymentUrl) {
  final host = Uri.tryParse(paymentUrl)?.host ?? '';
  return host.startsWith('test-') ? Environment.test : Environment.prod;
}

/// Keeps long descriptions (e.g. an HTML error page) from filling the screen.
String _shorten(Object? description, {int max = 120}) {
  final text = description.toString().replaceAll(RegExp(r'\s+'), ' ').trim();
  return text.length <= max ? text : '${text.substring(0, max)}...';
}
11
likes
130
points
296
downloads

Documentation

Documentation
API reference

Publisher

verified publisherkhalti.com

Weekly Downloads

An official Flutter plugin for Khalti Payment Gateway, with all the necessary interface that make it easy to integrate with your app.

Homepage
Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

equatable, flutter, flutter_inappwebview, http, internet_connection_checker_plus, khalti_checkout_core, meta, url_launcher

More

Packages that depend on khalti_checkout_flutter

Packages that implement khalti_checkout_flutter