gatewire_dart 1.0.10 copy "gatewire_dart: ^1.0.10" to clipboard
gatewire_dart: ^1.0.10 copied to clipboard

Official Flutter SDK for the GateWire decentralized SMS infrastructure.

GateWire Flutter SDK #

The official Flutter plugin for the GateWire SMS Infrastructure.

Easily integrate SMS notifications, OTPs, and alerts into your Flutter Android & iOS applications using our decentralized mesh network.

Features #

  • 🚀 Cross-Platform: Works on Android, iOS, Web, and Desktop.
  • 🇩🇿 Local Optimized: Designed for reliable delivery to Mobilis, Djezzy, and Ooredoo.
  • 🛡️ Type Safe: Full typed models for responses and errors.

Installation #

Add this to your pubspec.yaml:

dependencies:
  gatewire: ^1.0.10

Usage #

1. Initialization #

import 'package:gatewire_dart/gatewire_dart.dart';

final gatewire = GateWireClient(apiKey: 'sk_live_YOUR_KEY_HERE');

2. Sending an OTP #

try {
  final response = await gatewire.dispatch(
    phone: '+213555123456', 
  );
  
  print('SMS Sent! Ref ID: ${response.referenceId}');
  
} on GateWireException catch (e) {
  print('Failed: ${e.message}');
}

Templates allow you to skip the standard queue (Priority Route).

final response = await gatewire.dispatch(
  phone: '+213555123456',
  templateKey: 'login_otp', // Example configured in client dashboard
);

4. Verify a CODE #

try {
  final response = await gatewire.verifyOtp(
    referenceId: 'REFERENCE_ID_KEY',
    code: 'VERFICATION_CODE' 
  );
  
  print('Verification response : ${response.message}, ${response.status}');
  
} on GateWireException catch (e) {
  print('Failed: ${e.message}');
}

Use verifyPhone() when you want a single call that automatically picks the best method for the platform — no if (Platform.isAndroid) in your app code.

final result = await gatewire.verifyPhone(
  phoneNumber: '+213770123456',
  onSessionCreated: (s) {
    // Android only — fires before the USSD dialog appears.
    print('Dialing ${s.ussdCode} via ${s.operatorName}...');
  },
);

if (result.method == VerificationMethod.pnv) {
  // Android — phone verified immediately via USSD.
  print('Verified: ${result.verified}');
} else {
  // iOS / other — OTP SMS was sent; ask the user for the code.
  final code = await promptUserForCode();
  final otpResult = await gatewire.verifyOtp(
    referenceId: result.referenceId!,
    code: code,
  );
  print('OTP verified: ${otpResult.status}');
}
Platform Method used result.verified result.referenceId
Android PNV (USSD) true / false null
iOS / other OTP (SMS) null (pending) OTP session ID

Phone Number Verification (PNV) #

PNV verifies that a user owns their phone number by dialing a USSD code directly on the device — no SMS is sent and no code needs to be typed.

Android only. USSD is a carrier-level feature. Calling dialAndVerify on iOS, web, or desktop will throw a GateWireException immediately.

Prerequisites — Accessibility Service #

ussd_launcher reads the carrier's USSD response dialog using Android's Accessibility Service. Without it the USSD code can be dialed but the response string cannot be captured, so verification will fail.

Step 1 — Declare the service in your app's Android manifest

Your app will not appear in the system Accessibility list until it explicitly registers an AccessibilityService. This is required — Android will not list apps that haven't declared one.

Create android/app/src/main/res/xml/accessibility_service_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/accessibility_service_description"
    android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
    android:accessibilityFlags="flagReportViewIds|flagRequestFilterKeyEvents"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:notificationTimeout="100"
    android:canRetrieveWindowContent="true"
    android:canPerformGestures="true" />

Add inside <application> in android/app/src/main/AndroidManifest.xml:

<service
    android:name="com.kavina.ussd_launcher.UssdAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    android:exported="false">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>

Add inside <manifest>:

<uses-permission android:name="android.permission.CALL_PHONE" />

Add to android/app/src/main/res/values/strings.xml (create if missing):

<resources>
    <string name="app_name">YourAppName</string>
    <string name="accessibility_service_description">
        Required to capture USSD responses for phone number verification.
    </string>
</resources>

Then do a clean rebuild:

flutter clean && flutter run

Step 2 — User enables it (once)

After the rebuild your app will appear in the system list. You cannot request this permission programmatically — deep-link the user to the settings screen:

// Using android_intent_plus or similar
AndroidIntent(
  action: 'android.settings.ACCESSIBILITY_SETTINGS',
).launch();

Samsung One UI (Android 13+): the path is Settings → Accessibility → Installed apps → Your App → toggle on

final catalog = await gatewire.services.fetchCatalog();

if (catalog.isPnvAvailableOnThisDevice) {
  final hasAccess = await checkAccessibilityEnabled(); // your own check
  if (!hasAccess) {
    // Show a one-time onboarding card explaining why,
    // then deep-link to Accessibility Settings.
    // Do NOT block the user — fall back to OTP if they decline.
    await gatewire.dispatch(phone: phoneNumber); // OTP fallback
    return;
  }
  // Proceed with PNV
  final result = await gatewire.pnv.dialAndVerify(phoneNumber: phoneNumber);
}

Tip: verifyPhone() handles this fallback automatically. If ussd_launcher throws because the Accessibility Service is missing or disabled, it falls back to OTP. Prefer verifyPhone() over calling pnv.dialAndVerify() directly.

Devices where Accessibility Service may be blocked:

Scenario Behaviour
Manifest not configured / first install App absent from Accessibility list — rebuild required
User declines to enable it USSD response not captured → fall back to OTP
Enterprise MDM / managed device Accessibility Services may be disabled system-wide
Some OEM ROMs (e.g. MIUI, HyperOS) May restrict third-party Accessibility Services

In all cases the recommended approach is to detect the failure and silently fall back to OTP rather than blocking the user.

One-call flow (Android only) #

try {
  final result = await gatewire.pnv.dialAndVerify(
    phoneNumber: '+213770123456',
    onSessionCreated: (session) {
      // Called before the USSD dialog appears.
      // Use session.ussdCode to show a "Dialing *555#…" indicator.
      print('Dialing ${session.ussdCode} via ${session.operatorName}...');
    },
  );

  if (result.verified) {
    print('Phone verified! ${result.message}');
  } else {
    print('Verification failed: ${result.message}');
  }
} on GateWireException catch (e) {
  // e.code == 'service_disabled' when PNV is not enabled for your account.
  print('PNV error: ${e.message} (status: ${e.statusCode}, code: ${e.code})');
}

Manual two-step flow #

// Step 1 — create a session and get the USSD code.
final session = await gatewire.pnv.initiate(phoneNumber: '+213770123456');
print('Dial ${session.ussdCode} — expires at ${session.expiresAt}');

// … dial session.ussdCode yourself and capture the carrier response string …

// Step 2 — submit the raw USSD response for verification.
final result = await gatewire.pnv.verify(
  referenceId: session.referenceId,
  ussdResponse: rawUssdResponseString,
);
print('Verified: ${result.verified}');

Service Discovery #

Check which services are enabled for your API key before showing verification UI. Results are cached for 5 minutes automatically.

final catalog = await gatewire.services.fetchCatalog();

if (catalog.otp.enabled) {
  // Show OTP option — works on all platforms.
  print('OTP: ${catalog.otp.pricePerRequestCents} ${catalog.otp.currency} / request');
}

if (catalog.isPnvAvailableOnThisDevice) {
  // Show PNV option — only true when backend-enabled AND running on Android.
  print('PNV: ${catalog.pnv.pricePerRequestCents} ${catalog.pnv.currency} / request');
}

isPnvAvailableOnThisDevice combines both checks (pnv.enabled && Platform.isAndroid) so you never need to write that condition yourself.

To force a refresh (e.g. after the user enables a service in your settings UI):

gatewire.services.invalidateCache();
final fresh = await gatewire.services.fetchCatalog();

Service-disabled errors #

If a service is disabled and you call it anyway, a GateWireException is thrown with code == 'service_disabled':

try {
  await gatewire.dispatch(phone: '+213555123456');
} on GateWireException catch (e) {
  if (e.code == 'service_disabled') {
    print('OTP is not enabled. Visit your dashboard to activate it.');
  }
}

License #

The GateWire flutter package is open-sourced software licensed under the MIT license.

0
likes
155
points
188
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Official Flutter SDK for the GateWire decentralized SMS infrastructure.

Homepage

License

MIT (license)

Dependencies

flutter, http, ussd_launcher

More

Packages that depend on gatewire_dart