Android Native
Overview
The EdfaPay SoftPos SDK is a comprehensive Android SDK that enables payment processing functionality in your Android application. It provides a complete solution for accepting card payments through NFC (Near Field Communication) technology, transforming any Android device into a point-of-sale terminal.
Key Features
- Card Payment Processing: Accept payments via NFC-enabled Android devices
- Purchase Transactions: Process purchase transactions with full card verification
- Transaction Reversal: Reverse the last transaction when needed
- Reconciliation: Perform reconciliation and retrieve reconciliation history
- Transaction Management: Get transaction details and manage transaction history
- Customizable UI: Theme customization with colors, fonts, and branding
- Multiple Authentication Methods: Support for email/password or auth token authentication
Requirements
- Minimum SDK Version: 28 (Android 9.0)
- Target SDK Version: 36 (recommended)
- Kotlin: Required
- Java Version: 11 or higher
- NFC Support: Device must support NFC for card reading
- Location Permission: Required for payment processing
Use Cases
- Retail point-of-sale systems
- Mobile payment acceptance
- In-store payment processing
- Transaction management and reconciliation
- Multi-terminal payment solutions
Installation
[!IMPORTANT]
Configure RepositoryIt is important to add the
gradlePluginPortalandmaven repository with authorizationrepositories to your project. It allows the gradle to download edfapay plugin from gradlePluginPortal and the native dependency from the edfapay-mobile repository.If your project build was configured to prefer settings repositories, Place the below maven block to project
./settings.gradleor./settings.gradle.ktspluginManagement { repositories { ... mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() mavenCentral() maven { url = uri("https://build.edfapay.com/nexus/content/repositories/edfapay-mobile/") credentials { username = "USERNAME" // USERNAME provided by edfapay password = "PASSWORD" // PASSWORD provided by edfapay } } } }pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode = RepositoriesMode.PREFER_SETTINGS repositories { google() mavenCentral() maven { url "https://build.edfapay.com/nexus/content/repositories/edfapay-mobile/" credentials { username "USERNAME" // USERNAME provided by edfapay password "PASSWORD" // PASSWORD provided by edfapay } } } }
If your project build was configured to prefer traditional build.gradle repositories, Place the below maven block to project
./build.gradleor./build.gradle.ktsallprojects { repositories { google() mavenCentral() gradlePluginPortal() maven { url "https://build.edfapay.com/nexus/content/repositories/edfapay-mobile/" credentials { username "USERNAME" // USERNAME provided by edfapay password "PASSWORD" // PASSWORD provided by edfapay } } } }allprojects { repositories { google() mavenCentral() gradlePluginPortal() maven { url = uri("https://build.edfapay.com/nexus/content/repositories/edfapay-mobile/") credentials { username = "USERNAME" // USERNAME provided by edfapay password = "PASSWORD" // PASSWORD provided by edfapay } } } }
Adding dependencyIt is important to add dependency to your project module
build.gradleorbuild.gradle.ktsRequirements:
- Minimum SDK Version: 28 (Android 9.0)
- Target SDK Version: 36 (recommended)
- Kotlin: Required
- Java Version: 11 or higher
android { ... ... ... //This is optional block, if you are getting compile time crash, then add whatever you need from below exclude packages. packaging { resources { excludes += setOf( "META-INF/DEPENDENCIES", "META-INF/LICENSE", "META-INF/LICENSE.txt", "META-INF/NOTICE", "META-INF/NOTICE.txt" ) } } } //REQUIRED DEPENDENCY dependencies { implementation("com.edfapay:sa-edfapay-revamp:1.0.1") }android { ... ... ... //This is optional block, if you are getting compile time crash, then add whatever you need from below exclude packages. packaging { resources { exclude "META-INF/DEPENDENCIES" exclude "META-INF/LICENSE" exclude "META-INF/LICENSE.txt" exclude "META-INF/NOTICE" exclude "META-INF/NOTICE.txt" } } } //REQUIRED DEPENDENCY dependencies { implementation "com.edfapay:sa-edfapay-revamp:1.0.1" }
Configure AndroidManifest.xmlAdd the following permissions to your
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>Important: Set
allowBackuptofalsein your application tag:<application android:allowBackup="false"> ... ... </application>
Usage
This section guides you through the essential steps to integrate and utilize the EdfaPay SoftPos SDK in your Android application.
Importing the SDK
import com.edfapay.paymentcard.EdfaPayPlugin
import com.edfapay.paymentcard.model.EdfaPayCredentials
import com.edfapay.paymentcard.model.TransactionType
import com.edfapay.paymentcard.model.TxnParams
import com.edfapay.paymentcard.model.enums.Env
import com.edfapay.paymentcard.model.enums.FlowType
import com.edfapay.paymentcard.model.responses.Transactionimport com.edfapay.paymentcard.EdfaPayPlugin;
import com.edfapay.paymentcard.model.EdfaPayCredentials;
import com.edfapay.paymentcard.model.TransactionType;
import com.edfapay.paymentcard.model.TxnParams;
import com.edfapay.paymentcard.model.enums.Env;
import com.edfapay.paymentcard.model.enums.FlowType;
import com.edfapay.paymentcard.model.responses.Transaction;Authenticating with EdfaPay
// 1. Direct auto-fill email/password
val credentials = EdfaPayCredentials(
environment = Env.REVAMP, // For production use Env.PRODUCTION
email = "[email protected]",
password = "yourPassword123"
)
// 2. Enable email/password (without providing credentials immediately)
val credentials = EdfaPayCredentials(
environment = Env.REVAMP // For production use Env.PRODUCTION
)
// 3. Using Token (Auth Code) from the Dashboard / Backend
val credentials = EdfaPayCredentials(
environment = Env.REVAMP, // For production use Env.PRODUCTION
authCode = "AUTH-CODE-FROM-PORTAL"
)// 1. Direct auto-fill email/password
EdfaPayCredentials credentials1 = new EdfaPayCredentials(
Env.REVAMP, // For production use Env.PRODUCTION
"[email protected]",
"yourPassword123"
);
// 2. Enable email/password (without providing credentials immediately)
EdfaPayCredentials credentials2 = new EdfaPayCredentials(
Env.REVAMP // For production use Env.PRODUCTION
);
// 3. Using Token (Auth Code) from the Dashboard / Backend
EdfaPayCredentials credentials3 = new EdfaPayCredentials(
Env.REVAMP, // For production use Env.PRODUCTION
"AUTH-CODE-FROM-BACKEND"
);Initializing the Plugin
[!IMPORTANT]
Before initializing the SDK:
- Request location permission (mandatory)
// 1. Configure theme (OPTIONAL)
EdfaPayPlugin.theme(this)
.setPrimaryColor("#000000") // Primary color (hex format)
.setSecondaryColor("#d3d3d3") // Secondary color (hex format)
.setFontScale(1.5f) // Font scale factor
// 2. Request location permission (MANDATORY), you can use your own requestLocation flow.
EdfaPayPlugin.Utils.requestLocationPermission(this) { granted ->
if (granted) {
Log.d("EdfaPay", "Location permission granted")
} else {
Log.d("EdfaPay", "Location permission not granted")
}
}
// 3. Once location request granted you can call initiate plugin
val credentials = EdfaPayCredentials(
environment = Env.PRODUCTION,
email = "[email protected]",
password = "yourPassword123"
)
EdfaPayPlugin.initiate( // this will initialize the SDK
context = this,
credentials = credentials,
onSuccess = { plugin, sessionId ->
// check for initilization status
},
onError = {/* Check if there's any error */}
)
// 1. Configure theme (REQUIRED - must be done before initialization)
EdfaPayPlugin.INSTANCE.getTheme()
.setPrimaryColor("#000000")
.setSecondaryColor("#d3d3d3")
.setFontScale(1.5f);
// 2. Request location permission (MANDATORY)
EdfaPayPlugin.Utils.INSTANCE.requestLocationPermission(this, new Function1<Boolean, Unit>() {
@Override
public Unit invoke(Boolean granted) {
if (granted) {
// 3. Initialize SDK
EdfaPayCredentials credentials = new EdfaPayCredentials(
Env.REVAMP, // For production use Env.PRODUCTION
"[email protected]",
"yourPassword123"
);
EdfaPayPlugin.INSTANCE.initiate(
MainActivity.this,
credentials,
new EdfaPayPlugin.OnSuccessCallback() {
@Override
public void onSuccess(EdfaPayPlugin plugin, String sessionId) {
Toast.makeText(
getApplicationContext(),
"SDK Initialized Successfully",
Toast.LENGTH_SHORT
).show();
Log.d("EdfaPay", "Initialized with session: " + sessionId);
}
},
new EdfaPayPlugin.OnErrorCallBack() {
@Override
public void onError(Throwable err) {
err.printStackTrace();
Toast.makeText(
getApplicationContext(),
"Error Initializing: " + err.getMessage(),
Toast.LENGTH_SHORT
).show();
}
}
);
} else {
Log.d("EdfaPay", "Location permission not granted");
}
return Unit.INSTANCE;
}
});
// 4. Enable logs (optional)
EdfaPayPlugin.INSTANCE.setEnableLogs(true);Enable logs (optional)
EdfaPayPlugin.enableLogs = true // If true, you will see SDK logs
Transaction Operations
Performing a Purchase Transaction
val params = TxnParams(
amount = amount, // Transaction amount as string
orderId = "INV-1234", // Unique order ID
transactionType = TransactionType.PURCHASE
)
EdfaPayPlugin.purchase(
requireActivity(),
flowType = FlowType.DETAIL,
txnParams = params,
onRequestTimerEnd = {},
onCardScanTimerEnd = {
//card scan timeout
},
onPaymentProcessComplete = { status, code, txn, isComplete ->
//utilize which param you need
},
onCancelByUser = {},
onError = {}
)TxnParams params = new TxnParams(
amount, // String
"INV-1234", // Optional orderId
TransactionType.PURCHASE
);
EdfaPayPlugin.purchase(
requireActivity(),
FlowType.DETAIL,
params,
new EdfaPayPlugin.TimeOutCallBack() {
@Override
public void onTimeout() {
Toast.makeText(requireContext(), "Server Request Timeout", Toast.LENGTH_SHORT).show();
}
},
new EdfaPayPlugin.TimeOutCallBack() {
@Override
public void onTimeout() {
Toast.makeText(requireContext(), "Card Scan Timeout", Toast.LENGTH_SHORT).show();
}
},
new EdfaPayPlugin.ProcessCompleteCallback() {
@Override
public void onComplete(boolean status, String code, Transaction transaction, boolean isProcessComplete) {
if (transaction != null) {
// Save transaction
// TransactionStorage.addTransaction(transaction);
String rrn = transaction.getRrn() != null ? transaction.getRrn() : "Unknown";
String txnAmount = transaction.getAmount() != null ? transaction.getAmount() : "0";
Toast.makeText(
requireContext(),
"Transaction saved. RRN: " + rrn + ", Amount: " + txnAmount,
Toast.LENGTH_SHORT
).show();
}
Toast.makeText(
requireContext(),
status ? "Success" : "Failure",
Toast.LENGTH_SHORT
).show();
}
},
new EdfaPayPlugin.CancelByUserCallBack() {
@Override
public void onCancel() {
Toast.makeText(requireContext(), "Cancelled by User", Toast.LENGTH_SHORT).show();
}
},
new EdfaPayPlugin.OnErrorCallBack() {
@Override
public void onError(Throwable e) {
Toast.makeText(requireContext(), "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
);Reversing Last Transaction
EdfaPayPlugin.reverseLastTransaction(
this,
onSuccess = {},
onError = {}
)EdfaPayPlugin.reverseLastTransaction(
this,
new EdfaPayPlugin.OnSuccessCallback() {
@Override
public void onSuccess(EdfaPayPlugin plugin, String sessionId) {
Toast.makeText(
MainActivity.this,
"Transaction reversed successfully",
Toast.LENGTH_SHORT
).show();
}
},
new EdfaPayPlugin.OnErrorCallBack() {
@Override
public void onError(Throwable error) {
Toast.makeText(
MainActivity.this,
"Transaction reverse failed: " + error.getMessage(),
Toast.LENGTH_SHORT
).show();
}
}
);[!NOTE] The reverse feature must be enabled from the backend. The reverse button will not appear in the transaction status dialog if the feature is not enabled.
Getting Transaction Details
EdfaPayPlugin.txnDetail(
txnId = "TRANSACTION_DETAILS", // Transaction ID
onSuccess = {
// Handle transaction details
},
onError = {}
)EdfaPayPlugin.txnDetail(
"61adb013-4905-49d8-a4e6-e2fd28a53ec7", // Transaction ID
new EdfaPayPlugin.TransactionDetailCallback() {
@Override
public void onSuccess(Transaction transaction) {
Toast.makeText(
getApplicationContext(),
"Transaction details fetched successfully",
Toast.LENGTH_SHORT
).show();
Log.d("EdfaPay", "Transaction: " + transaction);
}
@Override
public void onError(Throwable error) {
Toast.makeText(
getApplicationContext(),
"Transaction details fetch failed: " + error.getMessage(),
Toast.LENGTH_SHORT
).show();
}
}
);Reconciling Transactions
EdfaPayPlugin.reconcile(
onSuccess = {},
onError = {}
)EdfaPayPlugin.INSTANCE.reconcile(
new Function1<com.edfapay.paymentcard.model.responses.revamp.Reconcile, Unit>() { // onSuccess
@Override
public Unit invoke(com.edfapay.paymentcard.model.responses.revamp.Reconcile model) {
Log.d(TAG, "onSuccessReconcile: " + model);
return Unit.INSTANCE;
}
},
new Function1<Throwable, Unit>() { // onError
@Override
public Unit invoke(Throwable exception) {
Log.d(TAG, "onErrorReconcile: " + exception);
return Unit.INSTANCE;
}
}
);[!NOTE] Reconciliation may not work id not enabled from admin.
Reconcile History
EdfaPayPlugin.reconciliationHistory(
onSuccess = { historyList: List<com.edfapay.paymentcard.model.responses.revamp.ReconciliationHistory> ->
// You can fetch all reconcliation history here
},
onError = {}
)EdfaPayPlugin.reconciliationHistory(
new EdfaPayPlugin.ReconciliationHistoryCallback() {
@Override
public void onSuccess(List<ReconciliationHistory> historyList) {
Log.d("EdfaPay", "Reconciliation History:");
for (ReconciliationHistory history : historyList) {
Log.d("EdfaPay", "ID: " + history.getId() +
", Date: " + history.getDate() +
", Amount: " + history.getAmount());
}
Toast.makeText(
requireContext(),
"Fetched " + historyList.size() + " reconciliation records",
Toast.LENGTH_SHORT
).show();
}
@Override
public void onError(Throwable error) {
Log.e("EdfaPay", "Failed to fetch reconciliation history: " + error.getMessage(), error);
Toast.makeText(
requireContext(),
"Failed: " + error.getMessage(),
Toast.LENGTH_SHORT
).show();
}
}
);Reconcile Detail
EdfaPayPlugin.reconciliationDetail(
id = "RECONCLIATION_ID",
onSuccess = {},
onError = {}
)EdfaPayPlugin.reconciliationDetail(
reconciliationId,
new EdfaPayPlugin.ReconciliationDetailCallback() {
@Override
public void onSuccess(ReconciliationDetail detail) {
Log.d("EdfaPay", "Reconciliation Detail for " + reconciliationId + ":");
Log.d("EdfaPay", "Total Amount: " + detail.getTotalAmount());
Log.d("EdfaPay", "Transactions: " + detail.getTransactions());
Toast.makeText(
requireContext(),
"Reconciliation detail fetched",
Toast.LENGTH_SHORT
).show();
}
@Override
public void onError(Throwable error) {
Log.e("EdfaPay", "Failed to get reconciliation detail: " + error.getMessage(), error);
Toast.makeText(
requireContext(),
"Error: " + error.getMessage(),
Toast.LENGTH_SHORT
).show();
}
}
);[!TIP]
Enabling and Disabling Logs
The developer can enable or disable logging at the SDK
EdfaPayPlugin.enableLogs = trueEdfaPayPlugin.INSTANCE.setEnableLogs(true);Setting Animation Speed
The developer can set the speed for animations for status and card scheme. It will control the process speed.
EdfaPayPlugin.animationSpeedX = 2.0fEdfaPayPlugin.INSTANCE.setAnimationSpeedX(2.0f);Customizing the Theme
EdfaPayPlugin.theme(this)
.setPrimaryColor("#000000")
.setSecondaryColor("#d3d3d3")
.setFontScale(1.5f)
.setButtonBackgroundColor("#06E59F")
.setButtonTextColor("#000000")
.setHeaderImage(this, R.drawable.logo)
.setPoweredByImage(this, R.drawable.logo)EdfaPayPlugin.INSTANCE.getTheme()
.setPrimaryColor("#000000")
.setSecondaryColor("#d3d3d3")
.setFontScale(1.5f)
.setButtonBackgroundColor("#06E59F")
.setButtonTextColor("#000000")
.setHeaderImage(this, R.drawable.logo)
.setPoweredByImage(this, R.drawable.logo);[!IMPORTANT] Theme configuration is required before SDK initialization. The app may crash if theme is not configured.
Important Notes
-
Theme Configuration: Theme can be configured before SDK initialization.
-
Location Permission: Location permission is mandatory and must be requested before initialization using
EdfaPayPlugin.Utils.requestLocationPermission(). -
Manifest Configuration: Set
android:allowBackup="false"in your application tag to prevent backup issues. -
Reverse Transaction: Reverse feature must be enabled from the backend. The reverse button will not appear if the feature is disabled.
-
Fragment Lifecycle: Be aware of fragment lifecycle when handling callbacks to avoid crashes related to detached fragments.
License
MIT
Updated 29 days ago