easymerchantsdk 1.4.0 copy "easymerchantsdk: ^1.4.0" to clipboard
easymerchantsdk: ^1.4.0 copied to clipboard

Lyfecycle Payments SDK for Flutter — native mobile checkout (card, ACH, 3DS). Pub package easymerchantsdk.

Lyfecycle Payments SDK for Flutter #

The Lyfecycle Payments SDK (Flutter) provides a Flutter interface for Lyfecycle native mobile checkout on Android and iOS.

  • Card and ACH payments
  • 3D Secure, recurring payments, saved cards/accounts
  • makePayment — API key + secret key
  • makePaymentV2 — client token from your backend

Pub package name: easymerchantsdk — use this in pubspec.yaml and import 'package:easymerchantsdk/easymerchantsdk.dart';. The product name is Lyfecycle Payments SDK.

Pub.dev: pub.flutter-io.cn/packages/easymerchantsdk
Sample app: em-MobileCheckoutSDK-Flutter / local flutter-sdk-demo-app


Requirements #

Platform Minimum
Flutter 3.3+
Dart 3.5+ (sdk: ">=3.5.0 <4.0.0")
Android minSdk 24+
iOS 16.0+, Xcode 14+, CocoaPods

You need Lyfecycle credentials (sandbox / staging / production) from your account team.


1. Add the Lyfecycle Payments SDK #

In your app pubspec.yaml (package id easymerchantsdk):

dependencies:
  easymerchantsdk: ^1.4.0
flutter pub get

For local development against this repo:

dependencies:
  easymerchantsdk:
    path: ../em-MobileCheckoutSDK-Flutter

2. Android setup #

The plugin depends on the native Android SDK com.app:paysdk hosted on GitHub Packages. Your app must expose Maven credentials at build time.

android/build.gradle or android/build.gradle.kts #

Add the GitHub Maven repository (example Kotlin DSL):

// android/build.gradle.kts
val githubMavenUrl = System.getenv("GITHUB_MAVEN_URL")
    ?: "https://maven.pkg.github.com/EasyMerchant/em-MobileCheckoutSDK-Android"
val githubReadActor = System.getenv("GITHUB_READ_ACTOR") ?: ""
val githubReadToken = System.getenv("GITHUB_READ_TOKEN") ?: ""

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
        maven {
            url = uri(githubMavenUrl)
            credentials {
                username = githubReadActor
                password = githubReadToken
            }
        }
    }
}

Groovy build.gradle equivalent:

def githubMavenUrl = System.getenv("GITHUB_MAVEN_URL") ?: "https://maven.pkg.github.com/EasyMerchant/em-MobileCheckoutSDK-Android"
def githubReadActor = System.getenv("GITHUB_READ_ACTOR") ?: ""
def githubReadToken = System.getenv("GITHUB_READ_TOKEN") ?: ""

allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
        maven {
            url = uri(githubMavenUrl)
            credentials {
                username = githubReadActor
                password = githubReadToken
            }
        }
    }
}

Environment variables (required for CI and local builds) #

export GITHUB_READ_ACTOR="your-github-username-or-bot"
export GITHUB_READ_TOKEN="ghp_xxxxxxxx"   # PAT with read:packages

Optional override:

export GITHUB_MAVEN_URL="https://maven.pkg.github.com/EasyMerchant/em-MobileCheckoutSDK-Android"

AndroidManifest #

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

3. iOS setup #

Native UI sources are bundled in the plugin (no separate XCFramework download for Flutter).

cd ios
pod install
cd ..

Open ios/Runner.xcworkspace in Xcode (not .xcodeproj).

Info.plist (network) #

If you need cleartext HTTP in dev:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Forward custom URL schemes to the plugin from ios/Runner/AppDelegate.swift:

import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func application(
    _ app: UIApplication,
    open url: URL,
    options: [UIApplication.OpenURLOptionsKey: Any] = [:]
  ) -> Bool {
    if EasymerchantSdkPlugin.handleDeepLink(url: url) {
      return true
    }
    return super.application(app, open: url, options: options)
  }
}

Register your URL schemes in Info.plist (CFBundleURLTypes) as required by GrailPay / your bank flow.


4. Basic usage #

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:easymerchantsdk/easymerchantsdk.dart';

// Lyfecycle Payments SDK entry point (class name matches pub package)
final lyfecyclePaymentsSdk = Easymerchantsdk();

The native SDK also pushes events on a broadcast channel. Set this up once (e.g. in initState):

lyfecyclePaymentsSdk.setupEventListeners(
  onPaymentSuccess: (jsonString) {
    final data = jsonDecode(jsonString);
    debugPrint('Success: $data');
  },
  onPaymentStatusError: (jsonString) {
    final data = jsonDecode(jsonString);
    debugPrint('Error/cancel: $data');
  },
  onPaymentPending: (jsonString) {
    // iOS only: initial hosted form load (status pending in chargeData)
    debugPrint('Pending: $jsonString');
  },
);

Flow A — makePayment (API key + secret) #

Step 1 — Configure environment (once per session):

await lyfecyclePaymentsSdk.configureEnvironment(
  'sandbox',           // 'sandbox' | 'staging' | 'production'
  'your-api-key',
  'your-secret-key',
);

Step 2 — Build config JSON and pay:

final config = {
  'environment': 'sandbox',
  'amount': '10.00',
  'currency': 'usd',
  'paymentMethods': ['card', 'ach'],
  'saveCard': true,
  'saveAccount': true,
  'secureAuthentication': true,
  'authenticatedACH': false,
  'showReceipt': true,
  'showTotal': true,
  'showSubmitButton': true,
  'submitButtonText': 'Pay now',
  'email': 'user@example.com',
  'name': 'Jane Doe',
  'fields': {
    'visibility': {'billing': true, 'additional': true},
    'billing': [
      {'name': 'address', 'required': true, 'value': '123 Main St'},
      {'name': 'country', 'required': true, 'value': 'United States'},
      {'name': 'state', 'required': true, 'value': 'California'},
      {'name': 'city', 'required': false, 'value': 'San Francisco'},
      {'name': 'postal_code', 'required': false, 'value': '94105'},
    ],
    'additional': [
      {'name': 'phone_number', 'required': false, 'value': '+1-555-123-4567'},
      {'name': 'description', 'required': false, 'value': 'Order #123'},
    ],
  },
  'appearanceSettings': {
    'theme': 'light',
    'bodyBackgroundColor': '#FFFFFF',
    'primaryButtonBackgroundColor': '#2563EB',
  },
};

final result = await lyfecyclePaymentsSdk.makePayment(jsonEncode(config));
if (result != null) {
  final response = jsonDecode(result);
  // Handle response (see format below)
}

apiKey / secretKey may be included in the JSON for makePayment on some setups; configuring via configureEnvironment is required for the native layer.

Flow B — makePaymentV2 (client token) #

Obtain a client_token from your backend (Payment Intent / hosted checkout API), then:

final config = {
  'environment': 'sandbox',
  'amount': '25.00',
  'currency': 'usd',
  'clientToken': clientTokenFromYourBackend,
  'paymentMethods': ['card', 'ach'],
  'saveCard': false,
  'saveAccount': false,
  'secureAuthentication': true,
  'fields': { /* same shape as makePayment */ },
};

final result = await lyfecyclePaymentsSdk.makePaymentV2(jsonEncode(config));

You do not need configureEnvironment for V2 if the token already encodes the session (demo app still sets keys for token generation on the server side).

Payment reference (3DS / follow-up) #

After 3DS or certain flows you may receive a referenceToken in the response. Resume payment with:

final result = await lyfecyclePaymentsSdk.paymentReference(referenceToken);

5. Payment result format #

Aligned with the React Native SDK (iOS native bridge). Parse the JSON string returned by makePayment / makePaymentV2 / events.

Success #

{
  "status": "success",
  "chargeData": { },
  "billingInfo": { },
  "additionalInfo": { },
  "referenceToken": "optional-from-3ds"
}

Error #

{
  "status": "error",
  "message": "Human-readable error"
}

Cancelled #

{
  "status": "cancelled",
  "message": "Payment cancelled"
}

Android may still return legacy shapes in some paths ("status": true boolean). Prefer checking both during migration:

bool isSuccess(dynamic status) =>
  status == 'success' || status == true;

6. Configuration reference (common keys) #

Key Type Description
environment String sandbox, staging, production
amount String Decimal amount as string, e.g. "10.00"
currency String e.g. usd
paymentMethods List<String> card, ach
clientToken String Required for makePaymentV2
tokenOnly bool Tokenize without charge
saveCard / saveAccount bool Save payment methods
secureAuthentication bool 3DS when supported
authenticatedACH bool GrailPay / verified ACH
showReceipt / showTotal / showSubmitButton bool UI toggles
fields Object Billing & additional field visibility/values
appearanceSettings Object Theme colors, fonts, radius
grailPayParams Object role, timeout (min 11), brandingName, etc.
is_recurring bool Recurring payment
recurringIntervals List<String> daily, weekly, monthly, …
metadata Object Custom metadata

See the demo app buildPaymentConfiguration() in MainPaymentView.dart / ClientPaymentView.dart for a full working example.


7. API summary #

Method Description
configureEnvironment(env, apiKey, secretKey) Set native API environment (for makePayment)
makePayment(configJson) Hosted checkout with API credentials
makePaymentV2(configJson) Hosted checkout with clientToken
paymentReference(referenceToken) Continue after 3DS / reference flow
setViewController() iOS: bind root VC (usually optional)
getPlatformVersion() Debug helper
setupEventListeners(...) Subscribe to PaymentSuccess / PaymentStatusError / PaymentPending

8. Troubleshooting #

Issue What to check
Android: failed to resolve com.app:paysdk GITHUB_READ_ACTOR / GITHUB_READ_TOKEN on app android/build.gradle
iOS: pod errors cd ios && pod install, use .xcworkspace
iOS: presentation errors Call payment from a visible screen; avoid presenting from a modal host
Empty / parse errors Pass JSON string via jsonEncode(map), not a raw Map
Gradle Kotlin mismatch Plugin uses Kotlin 2.0.21 and paysdk 2.0.9 (aligned with RN SDK)

9. Version & support #

For credential and backend Payment Intent setup, contact Lyfecycle Payments support.

0
likes
110
points
102
downloads

Documentation

API reference

Publisher

verified publisherlyfecycletech.com

Weekly Downloads

Lyfecycle Payments SDK for Flutter — native mobile checkout (card, ACH, 3DS). Pub package easymerchantsdk.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, http, plugin_platform_interface

More

Packages that depend on easymerchantsdk

Packages that implement easymerchantsdk