Build on Mobile
This page details how MobilePay app payments should be implemented in your Android/iOS app.
- Android
- iOS
Prerequisites and Assumptions
This guide assumes:
- You already have backend services integrated with MobilePay APIs.
- Your app uses minSdkVersion API 23 (Marshmallow, 6.0) or later.
- You are generally familiar with developing applications on Android.
Using app payments for digital sales might not be allowed by some mobile application distribution services (Google Play, App Store, etc.) and might result in your application being removed. Please review the terms of service for the respective mobile application distribution services you use to ensure that you are compliant with their guidelines.
Create Payment
First, you'll need to create payment. To do this you should call your backend service that is implemented as described here. This service call should return a response that contains a deep link needed to launch the MobilePay app.
Starting MobilePay
MobilePay supports navigation via native Activity Result APIs and deep linking.
- Result APIs
- Deep Links
Activity Result or startActivityForResult
APIs use standard Android functions and will launch MobilePay in your app process. This is the preferred way when integrating into a native Android app.
Let's open MobilePay with the deep link received from your backend.
- Kotlin using Activity Result APIs
- Kotlin using startActivityForResult
- Java
private val mobilePayContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
when (it.resultCode) {
SUCCESS_RESULT_CODE -> {}
REJECT_RESULT_CODE -> {}
FAILED_RESULT_CODE -> {}
UNKNOWN_RESULT_CODE -> {}
}
}
// Use the link received from your backend to launch MobilePay.
fun openMobilePay(deepLink: String) {
try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(deepLink)
}
mobilePayContract.launch(intent)
} catch (exception: ActivityNotFoundException) {
// Inform the user that MobilePay is not installed or use these links to redirect the user to Play Store:
// DK: https://play.google.com/store/apps/details?id=dk.danskebank.mobilepay
// FI: https://play.google.com/store/apps/details?id=fi.danskebank.mobilepay
}
}
companion object {
private const val SUCCESS_RESULT_CODE = Activity.RESULT_OK
private const val REJECT_RESULT_CODE = Activity.RESULT_CANCELED
private const val FAILED_RESULT_CODE = 1
private const val UNKNOWN_RESULT_CODE = 2
}
// Use the link received from your backend to launch MobilePay.
fun openMobilePay(deepLink: String) {
try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(deepLink)
}
startActivityForResult(intent, MOBILEPAY_PAYMENT_REQUEST_CODE)
} catch (exception: ActivityNotFoundException) {
// Inform the user that MobilePay is not installed or use these links to redirect the user to Play Store:
// DK: https://play.google.com/store/apps/details?id=dk.danskebank.mobilepay
// FI: https://play.google.com/store/apps/details?id=fi.danskebank.mobilepay
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == MOBILEPAY_PAYMENT_REQUEST_CODE) {
when (resultCode) {
SUCCESS_RESULT_CODE -> {}
REJECT_RESULT_CODE -> {}
FAILED_RESULT_CODE -> {}
UNKNOWN_RESULT_CODE -> {}
}
}
}
companion object {
const val MOBILEPAY_PAYMENT_REQUEST_CODE = 1337 // Any request code you choose
private const val SUCCESS_RESULT_CODE = Activity.RESULT_OK
private const val REJECT_RESULT_CODE = Activity.RESULT_CANCELED
private const val FAILED_RESULT_CODE = 1
private const val UNKNOWN_RESULT_CODE = 2
}
private static final int MOBILEPAY_PAYMENT_REQUEST_CODE = 1337; // Any request code you choose
private static final int SUCCESS_RESULT_CODE = Activity.RESULT_OK;
private static final int REJECT_RESULT_CODE = Activity.RESULT_CANCELED;
private static final int FAILED_RESULT_CODE = 1;
private static final int UNKNOWN_RESULT_CODE = 2;
// Use the link received from your backend to launch MobilePay.
void openMobilePay(String deepLink) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(deepLink));
startActivityForResult(intent, MOBILEPAY_PAYMENT_REQUEST_CODE);
} catch (android.content.ActivityNotFoundException exception) {
// Inform the user that MobilePay is not installed or use these links to redirect the user to Play Store:
// DK: https://apps.apple.com/us/app/mobilepay/id624499138
// FI: https://apps.apple.com/us/app/mobilepay/id768172577
} catch (NullPointerException exception) {
// Null deepLink was passed in.
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MOBILEPAY_PAYMENT_REQUEST_CODE) {
if (resultCode == SUCCESS_RESULT_CODE) {
} else if (resultCode == REJECT_RESULT_CODE) {
} else if (resultCode == FAILED_RESULT_CODE) {
} else if (resultCode == UNKNOWN_RESULT_CODE) {
}
}
}
Handling the Result
MobilePay can return these result codes:
- SUCCESS_RESULT_CODE (Activity.RESULT_OK) - payment was successful and it is in reserved state.
- REJECT_RESULT_CODE (Activity.RESULT_CANCELED) - user rejected the payment.
- FAILED_RESULT_CODE (1) - user could not complete the payment due to invalid state of payment or the user's MobilePay account.
- UNKNOWN_RESULT_CODE (2) - user attempted to do a payment, but because of network issues we could not determine if it was successful. (E.g., the user tries to do a payment, but it does not succeed due to network issues. Then the user decides to reject the payment and again receives a network error. At this point we cannot leave the user blocked in the MobilePay app, so we finish with this result code.) You should try to capture or at least check the state of these payments as they can be successful.
Deep link approach is used when the MobilePay app is launched with the startActivity
function. When using this navigation method, the MobilePay app will run in a separate process and invoke your app with a deep link after the payment flow is finished.
Let's open MobilePay with the deep link received from your backend.
- Kotlin
- Java
fun openMobilePay(deepLink: String) {
try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(deepLink)
}
startActivity(intent)
// At this point we know that MobilePay will be launched.
// Consider navigating to a new screen here.
} catch (exception: ActivityNotFoundException) {
// Inform the user that MobilePay is not installed or use these links to redirect the user to Play Store:
// DK: market://details?id=dk.danskebank.mobilepay
// FI: market://details?id=fi.danskebank.mobilepay
}
}
void openMobilePay(String deepLink) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(deepLink));
startActivity(intent);
// At this point we know that MobilePay will be launched.
// Consider navigating to a new screen here.
} catch (android.content.ActivityNotFoundException exception) {
// Inform the user that MobilePay is not installed or use these links to redirect the user to Play Store:
// DK: market://details?id=dk.danskebank.mobilepay
// FI: market://details?id=fi.danskebank.mobilepay
} catch (NullPointerException exception) {
// Null deepLink was passed in.
}
}
After this, the MobilePay app will be launched and the user will be able to proceed with the payment flow.
Returning to Your App
There are multiple ways a user can return to your app:
- User approves the payment and is redirected back to your app.
- User cancels the payment and is redirected back to your app.
- User fails to complete the payment due to some kind of error and is redirected back to your app.
- User closes the app before/after reservation using the native app switcher.
- User presses back in the MobilePay Login screen.
All these can be grouped into:
- App switching.
- Redirect.
The following section addresses how each one should be handled.
App Switching
At any point the user can close the MobilePay app and just return to your app. This can happen even if the payment is already reserved! Since it is unknown if your app was opened after a completed payment, you'll need to check the payment state each time your app returns to the foreground. For this, you should use your backend service that provides the current state of a payment (more details here).
Redirect from MobilePay
The other scenario is that the MobilePay app tries to automatically navigate back to your app. For this to work you'll need:
- Valid deep link to a place that knows how to proceed with the flow (official deep linking guide).
- Provide this deep link during payment creation.
In the general case, this deep link should open the app screen which handles the "App switching" scenario described above, and just treat it the same way as if the user manually navigated to your app.
When redirecting back to your app, MobilePay appends a query parameter status
to the end of a deep link. It can contain these values:
- successful
- failed
- rejected
Consider checking this parameter and triggering a capture without checking the payment's state in your backend (capture can only succeed if status
returned value is successful
).
P.S. It's not required for a successful app payments integration.
Prerequisites and Assumptions
This guide assumes:
- You already have backend services integrated with MobilePay APIs.
- Your app handles a custom URL scheme. See Apple documentation for more details.
- You are generally familiar with developing applications on iOS.
Using app payments for digital sales might not be allowed by some mobile application distribution services (Google Play, App Store, etc.) and might result in your application being removed. Please review the terms of service for the respective mobile application distribution services you use to ensure that you are compliant with their guidelines.
Create Payment
First, you'll need to create payment. To do this you should call your backend service that is implemented as described here. This service call should return a response that contains a deep link needed to launch the MobilePay app.
Redirect to MobilePay
Now that we have the deep link let's open MobilePay app.
UIApplication.shared.open(redirectUrl, options: [:], completionHandler: { success in
if success {
// Handle success.
} else {
// Handle failure. Most likely MobilePay app is not present on the user's device. You can redirect to App Store using these links:
// DK: itms-apps://itunes.apple.com/app/id624499138
// FI: itms-apps://itunes.apple.com/app/id768172577
}
})
After this, the MobilePay app will be launched and the user will be able to proceed with the payment flow.
Returning to Your App
There are multiple ways a user can return to your app:
- User approves the payment and is redirected back to your app.
- User cancels the payment and is redirected back to your app.
- User fails to complete the payment due to some kind of error and is redirected back to your app.
- User closes the app before/after reservation using the native app switcher.
- User presses back in the MobilePay Login screen.
All these can be grouped into:
- App switching.
- Redirect.
The following section addresses how each one should be handled.
App Switching
At any point a user can close MobilePay app and just return to your app. This can happen even if payment is already reserved! Since it is unknown if your app was opened after completed payment, you'll need to check payment state each time your app returns to the foreground. For this, you should use your backend service that provides current state of payment (more details here).
Example how to handle case when user manually switches to your app:
let observer = NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil, using: { _ in
// Check payment status - poll if needed.
})
Don't forget to unregister from notification when it's not needed:
NotificationCenter.default.removeObserver(observer)
Redirect from MobilePay
Example how to handle automatic redirect from the MobilePay app:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Validate that url is from MobilePay and check payment status - poll if needed.
return true
}
}
When redirecting back to your app, MobilePay appends a query parameter status
to the end of a deep link. It can contain these values:
- successful
- failed
- rejected
P.S. It's not required for a successful app payments integration. You must rely on webhooks and status polling to know whether a payment is succesful or not.
All done
Now everything should be ready for testing! Sandbox testing guide is here.
MobilePay supports multiple countries, but cross-country payments are not enabled.
Having troubles with this guide? Be sure to contact us .