Skip to main content

otp_flutter 0.3.1 copy "otp_flutter: ^0.3.1" to clipboard
otp_flutter: ^0.3.1 copied to clipboard

Phone and email verification for Flutter, over the native otp.com SDKs. Requires iOS 15 and Android API 26.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: OtpExampleScreen());
  }
}

/// A menu in front of the bridge, so each call can be made on a device.
///
/// Nothing here is part of the package. It is the app a customer would write, and it uses only
/// what a customer can see.
class OtpExampleScreen extends StatefulWidget {
  const OtpExampleScreen({super.key});

  @override
  State<OtpExampleScreen> createState() => _OtpExampleScreenState();
}

class _OtpExampleScreenState extends State<OtpExampleScreen> {
  // Blank means the SDK's own host, https://api.otp.com. This field exists to point at a local or
  // staging backend instead: an emulator shares the machine's loopback, so it reaches a backend
  // running here, while a physical device needs the machine's address on the network instead.
  final _baseUrlController = TextEditingController();
  final _publishableKeyController = TextEditingController(
    text: 'otp_pk_test_…',
  );
  final _recipientController = TextEditingController(text: '+14155552671');
  final _codeController = TextEditingController();

  PendingOtp? _pending;
  String _outcome = '';

  Future<void> _report(String label, Future<Object?> Function() call) async {
    setState(() => _outcome = '$label…');
    try {
      final result = await call();
      setState(() => _outcome = '$label: $result');
    } on OtpException catch (error) {
      // Every call in the package throws this and nothing else, which is what makes a screen
      // like this able to branch rather than guess.
      setState(() {
        _outcome =
            '$label failed: ${error.kind.name}'
            '${error.type != null ? ' (${error.type})' : ''}'
            '${error.retryAfterSeconds != null ? ', retry after ${error.retryAfterSeconds}s' : ''}'
            '\n${error.message}';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('otp.com bridge')),
      body: SafeArea(
        child: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            const Text(
              'base url',
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
            TextField(
              controller: _baseUrlController,
              decoration: const InputDecoration(
                hintText: 'https://api.otp.com',
              ),
            ),
            const Text(
              'publishable key',
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
            TextField(controller: _publishableKeyController),
            const Text(
              'recipient',
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
            TextField(controller: _recipientController),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: () => _report(
                'configure',
                () => Otp.configure(
                  publishableKey: _publishableKeyController.text,
                  baseUrl: _baseUrlController.text.trim().isEmpty
                      ? null
                      : _baseUrlController.text.trim(),
                ),
              ),
              child: const Text('configure'),
            ),
            const SizedBox(height: 16),
            const Text(
              'Presented screens',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            ElevatedButton(
              onPressed: () => _report(
                'verify',
                () => Otp.verify(_recipientController.text, locale: 'en'),
              ),
              child: const Text('verify'),
            ),
            ElevatedButton(
              onPressed: () => _report(
                'verifyCollecting',
                () => Otp.verifyCollecting(RecipientKind.phone, locale: 'en'),
              ),
              child: const Text('verify, collecting a phone number'),
            ),
            ElevatedButton(
              onPressed: () => _report(
                'verifyCollecting',
                () => Otp.verifyCollecting(RecipientKind.email, locale: 'en'),
              ),
              child: const Text('verify, collecting an email address'),
            ),
            ElevatedButton(
              onPressed: () =>
                  _report('resumeInterrupted', () => Otp.resumeInterrupted()),
              child: const Text('resume an interrupted verification'),
            ),
            const SizedBox(height: 16),
            const Text(
              'Your own screen',
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            ElevatedButton(
              onPressed: () => _report('start', () async {
                final started = await Otp.start(
                  _recipientController.text,
                  locale: 'en',
                );
                setState(() => _pending = started);
                return started;
              }),
              child: const Text('start'),
            ),
            Text(
              'code${_pending != null ? ' (${_pending!.codeLength} digits)' : ''}',
              style: const TextStyle(fontSize: 12, color: Colors.grey),
            ),
            TextField(
              controller: _codeController,
              keyboardType: TextInputType.number,
            ),
            ElevatedButton(
              onPressed: () => _report(
                'submit',
                () => Otp.submit(_pending?.id ?? '', _codeController.text),
              ),
              child: const Text('submit'),
            ),
            ElevatedButton(
              onPressed: () =>
                  _report('resend', () => Otp.resend(_pending?.id ?? '')),
              child: const Text('resend'),
            ),
            ElevatedButton(
              onPressed: () =>
                  _report('resume', () => Otp.resume(_pending?.id ?? '')),
              child: const Text('resume'),
            ),
            ElevatedButton(
              onPressed: () => _report('interrupted', () => Otp.interrupted()),
              child: const Text('what is in flight'),
            ),
            const SizedBox(height: 20),
            Text(
              _outcome,
              style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
            ),
          ],
        ),
      ),
    );
  }
}
2
likes
160
points
397
downloads

Documentation

API reference

Publisher

verified publisherotp.com

Weekly Downloads

Phone and email verification for Flutter, over the native otp.com SDKs. Requires iOS 15 and Android API 26.

Homepage
Repository (GitHub)
View/report issues

Topics

#otp #verification #sms #authentication #whatsapp

License

Apache-2.0 (license)

Dependencies

flutter, meta

More

Packages that depend on otp_flutter

Packages that implement otp_flutter