Android
Installation
Add this to your buildScript repositories declaration
repositories {
maven { url 'https://nexus.devops.geopagos.com/repository/android-geopagos_public/' }
google()
mavenCentral()
jcenter()
maven { url 'https://jitpack.io' }
}
And this to your module dependencies
dependencies {
implementation "com.geopagos.payments.sdk:payments-core:$paymentVersion"
}
And for each type of reader you want to support (you may choose to support one or more)
- QPOS
- MagicPOS
- Urovo SmartPOS
dependencies {
implementation "com.geopagos.payments.sdk:sdk-reader-qpos:$paymentVersion"
}
dependencies {
implementation "com.geopagos.payments.sdk:sdk-reader-magicpos:$paymentVersion"
}
dependencies {
implementation "com.geopagos.payments.sdk:sdk-reader-urovo:$paymentVersion"
}
Configure the SDK
This consists of initializing the Readers SDK, provide data acording to code documentation.
First of all, SDK intialization is required, there is a Builder SDKPaymentsConfiguration.Builderto configure the required data:
val sdkPaymentsConfiguration = SDKPaymentsConfiguration.Builder()
.setLogger(<LOGGER>)
.setSwipePinDecider(<SWIPE_PIN_DECIDER>)
.build(
<CONTEXT>,
"<ENDPOINT>",
setOf(<READER_INSTALLER_SET>,
setOf(<PLUGIN_INSTALLER_SET>)
)
SDKPayments.init(sdkPaymentsConfiguration)
Where:
- CONTEXT* is the ApplicationContext
- ENDPOINT is a String with the URL path of the processor URL. Geopagos will provide this URL
- READER_INSTALLER_SET is a set of reader installers. According to the dependencies you added
- PLUGIN_INSTALLER_SET is a set of optional plugins. According to the dependencies you added. Geopagos will provide the corresponding documentation according to the contracted plugins
- LOGGER is a custom logger you can provide to get additional information about what the sdk is doing (is useful for debugging purposes)
- SWIPE_PIN_DECIDER is an interface that allows you to decide if the SDK should ask pin on swipe transactions. This is optional. By default the SDK is loaded with an implementation that decides if a Swipe Card requires PIN based on the last ServiceCode Digit
About installers
Each reader has its own installer. Whether you've added the QPOS, Urovo SmartPOS and/or MAGICPOS dependencies (see above), you'll gain access to SDKQposReader, SDKUrovoReader and/or SDKMagicPosReader that allows you to install each reader as is shown below.
- QPOS
- MagicPOS
- Urovo SmartPOS
SDKQposReader.getInstaller()
SDKMagicPosReader.getInstaller()
SDKUrovoReader.getInstaller(
<READER_PROFILE>,
<SDK_FILE_WRAPPER>,
<PIN_KEYBOARD_CONFIGURATION>
)
Where:
- READER_PROFILE is the profile for your country.
- SDK_FILE_WRAPPER allows you to provide a configuration file to the getInstaller
- PIN_KEYBOARD_CONFIGURATION allows you to customize the buttons of the PIN keyboard. You can customize the texts and its sizes, the margins and the background colors.
Initialization Example (supporting only MagicPos)
val swipePinDecider = object : SDKSwipePinDecider{
override fun decide(card: SDKTransactionCard.Magnetic, decision: (pinRequire: Boolean) -> Unit) {
decision(true)
}
}
val sdkPaymentsConfiguration = SDKPaymentsConfiguration.Builder()
.setLogger(myCustomLogger)
.setSwipePinDecider(swipePinDecider)
.build(
applicationContext,
"https://example.net/",
setOf(SDKMagicPosReader.getInstaller()),
setOf(SDKBinCvmContactlessDeciderPlugin.getInstaller(sdkBinTable))
)
SDKPayments.init(sdkPaymentsConfiguration)
Scan devices
A device is required to make a transaction , at this point you can scan devices.
You will have to use the SDKDeviceScanService to scan for devices, and select any of the found devices. To create a SDKDeviceScanService, you can use the SDKDeviceScanServiceFactory.create() method to create one.
val readerService = SDKDeviceScanServiceFactory.create()
Then, simply use one of the two scan method (one for using it from an Activity and other from a Fragment) passing the corresponding arguments. To use this, you must first ask for those permissions related to bluetooth.
class MyActivity : AppCompatActivity(), SDKScannerResultListener {
fun startScanning() {
readerService.scan(this, 120000)
}
}
The most important parameter the scan method receives is the SDKScannerResultListener, this listener is used to handle the result the results of the scanning process.
override fun onDeviceListUpdated(list: List<SDKDevice>) {
// TODO: Implement the logic to handle the list of devices found by the scanner
showDevicesToSelectDialog(list)
}
override fun onScanFinish() {
// TODO: Implement the logic to handle the scanning process being stopped
}
override fun onError(type: SDKScannerResultListener.ErrorType, message: String?) {
// TODO: Implement the logic to handle the different errors that may happen when scanning
handleScannerError(type, message)
}
Create transaction intent
To start a transaction it is needed to create a TransactionIntent, specifying the type transaction (sale, cancel or refund).
To create a SDKTransactionIntent
, use the SDKTransactionIntentFactor.createTransactionIntent
, this method receives
transaction type (sale, refund, cancel) and the implementation of SDKTransactionListener
interface
In case there is an ongoing transaction, it is attempted to be aborted beforehand to prevent having more than one active transaction simultaneously.
var txData : SDKTransactionData = SDKTransactionData(SDKTransactionType.Sale)
SDKTransactionIntentFactory.createTransactionIntent(txData, object : SDKTransactionListener {
override fun onTransactionCreated(result: SDKTransactionIntentResult) {
when(result) {
is SDKTransactionIntentResult.Success -> {
currentTx = result.transactionIntent
}
is SDKTransactionIntentResult.Error -> {
appendInfo("Error creating a new transaction: ${result.message}")
}
}
}
override fun onTransactionStateChanged(state: SDKTransactionState) {
handleTxState(state)
}
override fun onReaderStateChanged(state: SDKReaderState) {
handleReaderState()
}
})
SDKTransactionIntentResult.Error is thrown when a previous transaction exists and for some reason it cannot be aborted. The transaction cannot be aborted during the reader connection or after the confirmation.
Provide a device
Provide a device which was previously scanned.
Call the method provideDevice
in SDKTransactionState.DeviceRequired
state
fun handleTxState(state: SDKTransactionState) {
when (state) {
is SDKTransactionState.DeviceRequired -> {
state.provideDevice(selectedDevice!!) // device previously found by the scanner
}
...
}
}
Provide reader configuration
Create a SDKReadConfig
object and call the method provideDevice
in ReadConfigRequired
state.
fun handleTxState(state: SDKTransactionState) {
val readConfig = SDKReadConfig(
60000,
setOf(SDKCardReadMode.Chip, SDKCardReadMode.Swipe, SDKCardReadMode.Nfc),
SDKCardInsertionStatus.NotInserted,
getSDKTransactionTotals()
)
when (state) {
is ReadConfigRequired -> {
state.provideReadConfig(readConfig)
}
...
}
}
Select EMV app
There are cards that have more than one EMV application internally in the chip. This is a way that allows the standard to have several logic cards in the same plastic (for example, a credit card and a debit card), In this state the Readers SDK provides the list of available applications and you must choose which one you want to use (if the card only has one emv application, this state is not called).
Call the method selectEmvApp
in SDKTransactionState.SelectEmvApp
state.
fun handleTxState(state: SDKTransactionState) {
when (state) {
is SelectEmvApp -> {
val availableEmvApps = state.availableEmvApps
customMethodForSelectEmvApp(availableEmvApps) { emvApp ->
state.selectEmvApp(emvApp)
}
}
}
}
Confirm transaction
When the card is read, this data is provided to the Readers SDK user who decides to confirm or reject the transaction, then online processing is performed. Finally, an approved or declined, or error response is obtained,the data necessary to confirm the transaction will be explained in using JSON for confirmation section.
There is a deprecated version of the confirm() function that accepts typed parameters through the SDKConfirmation class.
Confirm a sale.
fun handleTxState(state: SDKTransactionState) {
when (state) {
val confirmation: SDKConfirmationJson = getNewSaleConfirmationJson()
is SDKTransactionState.ConfirmTransaction.Sale -> {
state.confirm(confirmation)
}
...
}
}
Confirm a refund.
fun handleTxState(state: SDKTransactionState) {
when (state) {
val confirmation: SDKConfirmationJson = getNewRefundConfirmationJson()
is SDKTransactionState.ConfirmTransaction.Refund -> {
state.confirm(confirmation)
}
...
}
}
Confirm a cancel.
fun handleTxState(state: SDKTransactionState) {
when (state) {
val confirmation: SDKConfirmationJson = getNewCancelConfirmationJson()
is SDKTransactionState.ConfirmTransaction.Cancel -> {
state.confirm(confirmation)
}
...
}
}
Transaction approved
If the transactions is approved, the response is obtained in the following methods.
Check for SDKTransactionState.TransactionApproved
state.
fun handleTxState(state: SDKTransactionState) {
when (state) {
is SDKTransactionState.TransactionApproved -> {
if(state is SDKTransactionState.TransactionApproved.Sale) {
// Approved sale
} else {
// Approved refund or cancel
}
...
}
}
Transaction error
During a transaction, two kind of errors can occur: recoverable and not recoverable. In the recoverable, it’s possible to retry the transaction calling the associate callback, in the not recoverable errors, the transaction finished and ç it's necessary to create another one.
Check whether state is SDKTransactionState.RecoverableError
or SDKTransactionState.NonRecoverableError
.
fun handleTxState(state: SDKTransactionState) {
when (state) {
is SDKTransactionState.RecoverableError -> {
...
state.recover() //if you want try recover an error
}
is SDKTransactionState.NonRecoverableError -> {
//transaction is finished by an error
}
...
}
}