flutter_elavon 1.0.15 copy "flutter_elavon: ^1.0.15" to clipboard
flutter_elavon: ^1.0.15 copied to clipboard

PlatformAndroid

Flutter plugin for Elavon Payment Gateway SDK

Flutter Elavon Plugin #

Flutter plugin for integrating Elavon Payment Gateway SDK (Converge Commerce SDK 6.8.0) into Flutter applications.

Features #

  • Account creation and management
  • Device discovery and connection
  • Transaction processing (Sale, Refund, Pre-Auth, etc.)
  • Real-time transaction event streaming

Setup #

Android #

  1. Add the plugin and required dependencies to your pubspec.yaml:
dependencies:
  flutter_elavon: ^1.0.3  # or latest version from pub.dev
  path_provider: ^2.1.0  # Required by Elavon SDK

Important: The path_provider plugin is required because the Elavon SDK uses it internally. Make sure to add it explicitly to your app's dependencies.

  1. Add Elavon SDK Libraries: The Elavon SDK library files (JAR/AAR) are included in the plugin package (42MB, under pub.dev's 50MB limit).

    Important: When using the plugin from pub.dev, you have two options:

    Option 1: Copy libs to your app's directory (Simplest - Recommended):

    • Copy all AAR/JAR files from ~/.pub-cache/hosted/pub.dev/flutter_elavon-X.X.X/android/libs/
    • Paste them into your_project/android/app/libs/ (create the directory if needed)
    • Replace X.X.X with your installed plugin version
    • To find your version: flutter pub deps | grep flutter_elavon or check pubspec.lock

    Then update your app's android/app/build.gradle:

    repositories {
        flatDir {
            dirs 'libs'  // Points to android/app/libs/ directory
        }
    }
       
    dependencies {
        // Include all JAR files
        implementation fileTree(dir: 'libs', include: ['*.jar'])
           
        // ⚠️ REQUIRED: Include ALL AAR files below
        // The plugin uses compileOnly for AARs, so they're NOT transitive dependencies
        // You MUST declare them all here, otherwise you'll get "Could not find" errors
        implementation(name: 'commerce-android-6.8.0-obfuscated-release', ext: 'aar')
        implementation(name: 'commerce-common-android-6.8.0-release', ext: 'aar')
        implementation(name: 'deckard-android-6.8.0', ext: 'aar')
        implementation(name: 'PclServiceLib-pcl-2.21.01', ext: 'aar')
        implementation(name: 'PclUtilities-pcl-2.21.01', ext: 'aar')
        implementation(name: 'rba-android-6.8.0-release', ext: 'aar')
        implementation(name: 'roam-rua-wrapper-java-android-6.8.0', ext: 'aar')
        implementation(name: 'roamreaderunifiedapi-2.5.2.1', ext: 'aar')
        implementation(name: 'rua-android-6.8.0', ext: 'aar')
        implementation(name: 'saf-android-aar-6.8.0-release', ext: 'aar')
    }
    

    Option 2: Point directly to plugin's libs (Advanced - No manual version updates needed):

    • Update your app's android/app/build.gradle:
    // Automatically find the latest flutter_elavon plugin version
    def pubCache = new File("${System.getProperty('user.home')}/.pub-cache/hosted/pub.dev")
    def flutterElavonLibsPath = null
    def latestVersion = null
    def latestPluginDir = null
       
    if (pubCache.exists()) {
        pubCache.eachDir { pluginDir ->
            if (pluginDir.name.startsWith('flutter_elavon-')) {
                def libsDir = new File(pluginDir, "android/libs")
                if (libsDir.exists() && libsDir.isDirectory()) {
                    // Extract version from directory name (e.g., "flutter_elavon-1.0.0" -> "1.0.0")
                    def versionStr = pluginDir.name.replace('flutter_elavon-', '')
                       
                    // Compare versions to find the latest
                    if (latestVersion == null || compareVersions(versionStr, latestVersion) > 0) {
                        latestVersion = versionStr
                        latestPluginDir = pluginDir
                        flutterElavonLibsPath = libsDir.absolutePath
                    }
                }
            }
        }
    }
       
    if (flutterElavonLibsPath == null) {
        throw new GradleException("flutter_elavon plugin libs not found in pub cache. Make sure the plugin is installed.")
    }
       
    println "Using flutter_elavon version: ${latestVersion} (libs at: ${flutterElavonLibsPath})"
       
    repositories {
        flatDir {
            dirs flutterElavonLibsPath
        }
    }
       
    // Helper function to compare version strings (e.g., "1.0.0" vs "1.0.1")
    def compareVersions(String v1, String v2) {
        def parts1 = v1.split('\\.')
        def parts2 = v2.split('\\.')
        def maxLength = Math.max(parts1.length, parts2.length)
           
        for (int i = 0; i < maxLength; i++) {
            def part1 = i < parts1.length ? Integer.parseInt(parts1[i]) : 0
            def part2 = i < parts2.length ? Integer.parseInt(parts2[i]) : 0
               
            if (part1 > part2) return 1
            if (part1 < part2) return -1
        }
        return 0
    }
       
    dependencies {
        // Include all JAR files from plugin's libs
        implementation fileTree(dir: flutterElavonLibsPath, include: ['*.jar'])
           
        // REQUIRED: Include all AAR files (plugin uses compileOnly, so they're not transitive)
        implementation(name: 'commerce-android-6.8.0-obfuscated-release', ext: 'aar')
        implementation(name: 'commerce-common-android-6.8.0-release', ext: 'aar')
        implementation(name: 'deckard-android-6.8.0', ext: 'aar')
        implementation(name: 'PclServiceLib-pcl-2.21.01', ext: 'aar')
        implementation(name: 'PclUtilities-pcl-2.21.01', ext: 'aar')
        implementation(name: 'rba-android-6.8.0-release', ext: 'aar')
        implementation(name: 'roam-rua-wrapper-java-android-6.8.0', ext: 'aar')
        implementation(name: 'roamreaderunifiedapi-2.5.2.1', ext: 'aar')
        implementation(name: 'rua-android-6.8.0', ext: 'aar')
        implementation(name: 'saf-android-aar-6.8.0-release', ext: 'aar')
    }
    

    Important Notes:

    • ⚠️ CRITICAL: You MUST declare ALL AAR dependencies in your app's build.gradle
    • The plugin uses compileOnly for AARs (they're NOT transitive dependencies)
    • If you don't declare them, you'll get "Could not find" errors for AAR files
    • The repositories block with flatDir must be at the module level (inside android/app/build.gradle)
    • Option 2 automatically detects the plugin version - no manual updates needed when you upgrade the plugin
    • If you have multiple plugins with libs directories, you can add multiple dirs entries in the flatDir block
  2. The plugin requires the following permissions (already included in AndroidManifest.xml):

    • Bluetooth permissions (BLUETOOTH_SCAN, BLUETOOTH_CONNECT for API 31+)
    • Location permission (ACCESS_FINE_LOCATION)
    • Phone state permission (READ_PHONE_STATE)
    • USB host feature (for USB device discovery)
  3. Minimum SDK: 28

  4. Target SDK: 35

Usage #

⚠️ CRITICAL: Initialization Order

You MUST call WidgetsFlutterBinding.ensureInitialized() as the very first line in your main() function, before:

  • Any database initialization
  • Any file system access (path_provider)
  • Any plugin usage
  • Any other async operations
import 'package:flutter_elavon/flutter_elavon.dart';
import 'package:flutter/widgets.dart';

// ✅ CORRECT: ensureInitialized() is the first line
void main() async {
  WidgetsFlutterBinding.ensureInitialized(); // MUST be first!
  
  // Now you can safely use plugins, databases, path_provider, etc.
  runApp(MyApp());
}

// ❌ WRONG: Don't do this!
void main() async {
  // This will cause path_provider channel errors!
  final db = await DBHelper.openDb(); // ❌ Called before ensureInitialized()
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

// Initialize and create account
final elavon = FlutterElavon();
await elavon.createAccount(PaymentGatewayType.CONVERGE);

// Find and connect devices
final devices = await elavon.findDevices();
if (devices.isNotEmpty) {
  await elavon.connectDevice(devices.first);
}

// Process a sale transaction
final result = await elavon.processSale(
  amount: 10000, // Amount in cents
  currencyCode: 'USD',
);

// Process a sale with transaction options (card types, entry types, etc.)
import 'package:flutter_elavon/models/transaction_options.dart';
import 'package:flutter_elavon/models/enums.dart';

final transactionOptions = TransactionOptions(
  // Card account types: CREDIT, DEBIT, EBT_FOOD_STAMP, EBT_CASH_BENEFIT
  allowedCardTypes: [CardType.CREDIT, CardType.DEBIT],
  
  // Or card brands: VISA, MASTERCARD, AMEX, DISCOVER, etc.
  // allowedCardTypes: [CardType.VISA, CardType.MASTERCARD],
  
  // Card entry types (optional)
  // allowedCardEntryTypes: ['SWIPE', 'EMV_CONTACT', 'EMV_PROXIMITY', 'MANUALLY_ENTERED'],
);

final result = await elavon.processSale(
  amount: 10000,
  currencyCode: 'USD',
  transactionOptions: transactionOptions,
);

// Listen to transaction events
elavon.transactionEvents.listen((event) {
  print('Transaction event: ${event.type}');
});

Troubleshooting #

Build Error: Could not find AAR files #

If you get errors like:

Could not find :commerce-android-6.8.0:.
Searched in the following locations:
  - file:/Users/.../android/libs/commerce-android-6.8.0.aar

Important: If you're using the plugin from pub.dev, you should ONLY need files in your app's directory. If you're being asked to add files to the plugin's directory, something is wrong.

Solution:

  1. Check file location: Make sure all AAR and JAR files are in the correct directory:

    • If using dirs 'libs' in repositories → files should be in android/app/libs/
    • If using dirs '../libs' → files should be in android/libs/
  2. Verify file names: Ensure the AAR file names match exactly (case-sensitive):

    • commerce-android-6.8.0.aar (not Commerce-Android-6.8.0.aar)
    • Check for exact matches including the .aar extension
  3. Check repositories block: Make sure the repositories block is in the correct location:

    // In android/app/build.gradle
    repositories {
        flatDir {
            dirs 'libs'  // Relative to android/app/
        }
    }
    
  4. Sync Gradle: After making changes:

    cd android
    ./gradlew clean
    cd ..
    flutter clean
    flutter pub get
    
  5. Verify files exist: Check that files are actually in the directory:

    ls -la android/app/libs/*.aar
    
  6. If you get "package com.elavon.commerce does not exist" error:

    • This means the plugin can't find the AAR files during compilation
    • Quick Fix: Use Option 1 - add files to plugin directory (one-time setup):
      # Find your plugin version
      flutter pub deps | grep flutter_elavon
           
      # Copy files to plugin directory (replace 1.0.5 with your version)
      cp -r your_project/android/app/libs/* ~/.pub-cache/hosted/pub.dev/flutter_elavon-1.0.5/android/libs/
      
    • Alternative: If using Option 2, make sure you've set the Gradle property:
      • Create/edit your_project/android/gradle.properties
      • Add: flutterElavonAppLibsPath=app/libs
      • Run flutter clean and rebuild
  7. If you're asked to add files to the plugin's directory: This shouldn't happen when using the published package. Try:

    • Run flutter clean and flutter pub get again
    • Check that you're using the plugin from pub.dev, not a local path:
      dependencies:
        flutter_elavon: ^1.0.4  # ✅ Correct - from pub.dev
        # flutter_elavon:
        #   path: ../flutter_elavon  # ❌ Wrong - this requires files in plugin directory
      
    • If using a local path dependency, you'll need files in both places (plugin's libs for compilation, app's libs for runtime)

PlatformException: Unable to establish connection on channel path_provider #

If you encounter this error:

PlatformException(channel-error, Unable to establish connection on channel: "dev.flutter.pigeon.path_provider_android.PathProviderApi.getApplicationDocumentsPath"., null, null)

Root Cause: This error occurs when path_provider (or any plugin) is used before it's fully registered. Even if you call WidgetsFlutterBinding.ensureInitialized() first, there can be a race condition where plugin registration happens asynchronously. Common causes:

  • Calling getApplicationDocumentsDirectory() in main() before ensureInitialized()
  • Initializing databases in main() before ensureInitialized()
  • Using any Flutter plugins before ensureInitialized()
  • Race condition: Even with ensureInitialized() called first, plugins may not be fully registered yet when the SDK tries to access them

Solution:

  1. Move WidgetsFlutterBinding.ensureInitialized() to the very first line of your main() function:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized(); // MUST be first line!
         
      // Now safe to use plugins, databases, path_provider, etc.
      final db = await DBHelper.openDb(); // ✅ Now safe
      runApp(MyApp());
    }
    
  2. Ensure path_provider: ^2.1.0 is explicitly added to your app's pubspec.yaml dependencies

  3. Run a clean rebuild:

    flutter clean
    flutter pub get
    flutter run
    
  4. If you're still getting the error even after calling ensureInitialized() first, try adding a small delay:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
         
      // Small delay to ensure plugins are fully registered (handles race condition)
      await Future.delayed(Duration(milliseconds: 200));
         
      // Now safe to use plugins, databases, path_provider, etc.
      final db = await DBHelper.openDb();
      runApp(MyApp());
    }
    
  5. Check your code for any plugin usage before ensureInitialized():

    • Search for getApplicationDocumentsDirectory() calls
    • Search for database initialization
    • Search for any plugin method calls in main()
    • Move all of these after WidgetsFlutterBinding.ensureInitialized()

License #

See LICENSE file for details.