telebirr_inapp 0.1.0 copy "telebirr_inapp: ^0.1.0" to clipboard
telebirr_inapp: ^0.1.0 copied to clipboard

Flutter plugin for telebirr InApp SDK payments on Android and iOS, with an explicit Gradle switch between the testbed and production SDK.

example/lib/main.dart

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:telebirr_inapp/telebirr_inapp.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'telebirr InApp example',
      theme: ThemeData(colorSchemeSeed: Colors.green),
      home: const CheckoutPage(),
    );
  }
}

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

  @override
  State<CheckoutPage> createState() => _CheckoutPageState();
}

class _CheckoutPageState extends State<CheckoutPage> {
  // Pre-fill the form at build time, e.g.
  // flutter run --dart-define=TELEBIRR_APP_ID=... --dart-define=TELEBIRR_SHORT_CODE=...
  //             --dart-define=TELEBIRR_BACKEND_URL=...
  final _backendUrl = TextEditingController(
    text: const String.fromEnvironment('TELEBIRR_BACKEND_URL'),
  );
  final _appId = TextEditingController(
    text: const String.fromEnvironment('TELEBIRR_APP_ID'),
  );
  final _shortCode = TextEditingController(
    text: const String.fromEnvironment('TELEBIRR_SHORT_CODE'),
  );
  final _title = TextEditingController(text: 'Test order');
  final _amount = TextEditingController(text: '1');
  final _receiveCode = TextEditingController();

  TelebirrEnvironment _environment = TelebirrEnvironment.test;
  TelebirrEnvironment? _nativeEnvironment;
  bool _busy = false;
  String _status = '';

  @override
  void initState() {
    super.initState();
    _loadNativeEnvironment();
  }

  @override
  void dispose() {
    for (final c in [
      _backendUrl,
      _appId,
      _shortCode,
      _title,
      _amount,
      _receiveCode,
    ]) {
      c.dispose();
    }
    super.dispose();
  }

  Future<void> _loadNativeEnvironment() async {
    final native = await Telebirr.nativeEnvironment();
    if (!mounted) return;
    setState(() {
      _nativeEnvironment = native;
      if (native != null) _environment = native;
    });
  }

  /// Asks your backend to create the order. The backend applies the fabric
  /// token, calls telebirr's createOrder and answers with the receiveCode,
  /// either as plain text or as JSON.
  Future<String> _createOrder() async {
    final response = await http.post(
      Uri.parse(_backendUrl.text.trim()),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'title': _title.text.trim(),
        'amount': _amount.text.trim(),
        'environment': _environment.name,
      }),
    );
    if (response.statusCode != 200) {
      throw Exception(
        'Backend answered ${response.statusCode}: ${response.body}',
      );
    }
    final body = response.body.trim();
    if (!body.startsWith('{')) return body;
    final json = jsonDecode(body) as Map<String, dynamic>;
    final bizContent = json['biz_content'];
    final code =
        json['receiveCode'] ??
        (bizContent is Map ? bizContent['receiveCode'] : null);
    if (code is! String || code.isEmpty) {
      throw Exception('No receiveCode in the backend response: $body');
    }
    return code;
  }

  Future<void> _pay() async {
    setState(() {
      _busy = true;
      _status = 'Starting…';
    });
    try {
      await Telebirr.initialize(
        appId: _appId.text,
        shortCode: _shortCode.text,
        environment: _environment,
      );
      var receiveCode = _receiveCode.text.trim();
      if (receiveCode.isEmpty) {
        receiveCode = await _createOrder();
      }
      final result = await Telebirr.pay(receiveCode: receiveCode);
      _status = result.isSuccess
          ? 'telebirr reported success. Confirm it on your backend before delivering.'
          : 'Not paid: ${result.status.name} (code ${result.code}) ${result.message}';
    } catch (e) {
      _status = '$e';
    }
    if (mounted) setState(() => _busy = false);
  }

  @override
  Widget build(BuildContext context) {
    final native = _nativeEnvironment;
    return Scaffold(
      appBar: AppBar(title: const Text('telebirr InApp example')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          Text(
            native == null
                ? 'Native SDK: one binary for test and live'
                : 'Native SDK in this build: ${native.name}',
          ),
          const SizedBox(height: 12),
          SegmentedButton<TelebirrEnvironment>(
            segments: const [
              ButtonSegment(
                value: TelebirrEnvironment.test,
                label: Text('Test'),
              ),
              ButtonSegment(
                value: TelebirrEnvironment.live,
                label: Text('Live'),
              ),
            ],
            selected: {_environment},
            onSelectionChanged: (s) => setState(() => _environment = s.first),
          ),
          _field(_appId, 'Merchant App ID'),
          _field(_shortCode, 'Short code', number: true),
          _field(_backendUrl, 'Backend create-order URL'),
          _field(_title, 'Title'),
          _field(_amount, 'Amount (ETB)', number: true),
          _field(
            _receiveCode,
            'receiveCode (optional, skips the backend call)',
          ),
          const SizedBox(height: 16),
          FilledButton(
            onPressed: _busy ? null : _pay,
            child: Text(_busy ? 'Waiting for telebirr…' : 'Pay with telebirr'),
          ),
          const SizedBox(height: 16),
          SelectableText(_status),
        ],
      ),
    );
  }

  Widget _field(
    TextEditingController controller,
    String label, {
    bool number = false,
  }) {
    return Padding(
      padding: const EdgeInsets.only(top: 12),
      child: TextField(
        controller: controller,
        keyboardType: number ? TextInputType.number : TextInputType.text,
        decoration: InputDecoration(
          labelText: label,
          border: const OutlineInputBorder(),
        ),
      ),
    );
  }
}
0
likes
150
points
78
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for telebirr InApp SDK payments on Android and iOS, with an explicit Gradle switch between the testbed and production SDK.

Repository (GitHub)
View/report issues

Topics

#telebirr #payments #ethiopia

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on telebirr_inapp

Packages that implement telebirr_inapp