
First integration
This guide will help you to make your first payment with ready-to-use payment forms.
Demo app
You are welcome to get started with our demo application. You can start making test transactions without any efforts including setting up a server, we provide a test integration server for you. Please note, that it is configured for demo purposes only.
The demo app is provided along with SDK since version 2.5.0.
NOTE: Before running the application, make sure SDK files are copied to the demo app folder. Find more details in the readme.txt file.
iOS
Requirements
- Xcode 11 and iOS 13 SDK
- iOS 10.0+ deployment target
Install the SDK
- Drag and drop
OPPWAMobile.framework
&OPPWAMobile-Resources.bundle
to the "Frameworks" folder of your project.
Make sure "Copy items if needed" is checked.
- Check "Build Phases" section of your Xcode project settings. Make sure:
.framework
file is in "Link Binaries with Libraries",.bundle
file is in "Copy Bundle Resources".- Confirm that these two Build Settings are both enabled:
Enable Modules (C and Objective-C)
Link Frameworks Automatically
-
[Optional] SDK extensions
You do not have to import additional frameworks to your project, unless you are going to use the following features:- Credit card scanning (
OPPWAMobile-CardIO.framework
) - Alipay native SDK (
OPPWAMobile-Alipay.framework
) - Iovation FraudForce SDK (
FraudForce.framework
)
- Credit card scanning (
You can now import the framework with:
#import <OPPWAMobile/OPPWAMobile.h>
#import <OPPWAMobile/OPPWAMobile.h>
NOTE: If you integrate SDK to the Swift app, please see the Apple guide Importing Objective-C into Swift to check how to import Objective-C headers correctly.
Set Up Your Server
To start working with our SDK, you should expose two APIs on your backend for your iOS app to communicate with:
- Endpoint 1: Creating a checkout ID,
- Endpoint 2: Getting result of payment.
See detailed instruction in our guide "Set Up Your Server".
Request Checkout ID
Your app should request a checkout ID from your server. This example uses our sample integration server; please adapt it to use your own backend API.
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB"]];
[[[NSURLSession sharedSession] dataTaskWithRequest:merchantServerRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// TODO: Handle errors
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.checkoutID = JSON[@"checkoutId"];
}] resume];
let merchantServerRequest = NSURLRequest(url: URL(string: "https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB")!)
URLSession.shared.dataTask(with: merchantServerRequest as URLRequest) { (data, response, error) in
// TODO: Handle errors
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let checkoutID = json?["checkoutId"] as? String
}
}.resume()
Android
Requirements
- Android Studio
- The Mobile SDK is designed to work with Android 4.4 (API Level 19) and up
Install the SDK
- Download the Mobile SDK for Android.
Add the following dependencies to your
build.gradle
:- Open your
AndroidManifest.xml
and declare the connect service within the application tag: - In addition, declare the "INTERNET" permission before the application tag:
-
[Optional] SDK extensions
You do not have to import additional frameworks to your project, unless you are going to use the following features:- Credit card scanning (
io.card:android-sdk
) - Alipay native SDK (
alipaySdk.aar
) - Iovation FraudForce SDK (
fraudforce-lib-release.aar
)
- Credit card scanning (
-
Import
oppwa.mobile.aar
into your project (File > New > New Module > Import .JAR/.AAR Package).
Then, reference it from your application (File > Project Structure > Dependencies > Add Module Dependency).
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:customtabs:28.0.0'
implementation 'com.google.android.gms:play-services-wallet:16.0.1'
<service
android:name="com.oppwa.mobile.connect.service.ConnectService"
android:exported="false"/>
If you want to use prebuilt checkout also declare the CheckoutActivity:
<activity
tools:replace="android:theme"
android:name="com.oppwa.mobile.connect.checkout.dialog.CheckoutActivity"
android:theme="@style/Theme.Checkout.Light"
android:windowSoftInputMode="adjustPan"
android:exported="false"
android:launchMode="singleTop"/>
NOTE: Don't set
screenOrientation
attribute for the CheckoutActivity
if your targetSdkVersion is 27 or higher.NOTE: Make sure you set the
tools:replace="android:theme"
attribute for the CheckoutActivity
. It belongs to the Android tools namespace, so you must first declare this namespace in the <manifest>
element: xmlns:tools="http://schemas.android.com/tools"
. Also if you use your custom style it must extend the Theme.Checkout style
.<uses-permission android:name="android.permission.INTERNET"/>
Set Up Your Server
To start working with our SDK, you should expose two APIs on your backend for your Android app to communicate with:
- Endpoint 1: Creating a checkout ID,
- Endpoint 2: Getting result of payment.
See detailed instruction in our guide "Set Up Your Server".
Request Checkout ID
Your app should request a checkout ID from your server. This example uses our sample integration server; please adapt it to use your own backend API.
public String requestCheckoutId() {
URL url;
String urlString;
HttpURLConnection connection = null;
String checkoutId = null;
urlString = YOUR_URL + "?amount=48.99¤cy=EUR&paymentType=DB";
try {
url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
JsonReader reader = new JsonReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"));
reader.beginObject();
while (reader.hasNext()) {
if (reader.nextName().equals("checkoutId")) {
checkoutId = reader.nextString();
break;
}
}
reader.endObject();
reader.close();
} catch (Exception e) {
/* error occurred */
} finally {
if (connection != null) {
connection.disconnect();
}
}
return checkoutId;
}
Present Checkout UI
1. Initialize Payment Provider with test mode
self.provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeTest];
let provider = OPPPaymentProvider(mode: OPPProviderMode.test)
2. Configure the Checkout Settings
Define the settings for the checkout screen. Initialize OPPCheckoutSettings
, it controls the information that is shown to the shopper.
For the first integration we recommend you to enable only synchronous payment methods, other payment brands need additional configuration.
OPPCheckoutSettings *checkoutSettings = [[OPPCheckoutSettings alloc] init];
// Set available payment brands for your shop
checkoutSettings.paymentBrands = @[@"VISA", @"DIRECTDEBIT_SEPA"];
// Set shopper result URL
checkoutSettings.shopperResultURL = @"com.companyname.appname.payments://result";
let checkoutSettings = OPPCheckoutSettings()
// Set available payment brands for your shop
checkoutSettings.paymentBrands = ["VISA", "DIRECTDEBIT_SEPA"]
// Set shopper result URL
checkoutSettings.shopperResultURL = "com.companyname.appname.payments://result"
NOTE: To learn more about shopper result url refer to Asynchronous Payments guide.
3. Present the Checkout Page
Initialize OPPCheckoutProvider
with the received checkout ID and created settings.
OPPCheckoutProvider *checkoutProvider = [OPPCheckoutProvider checkoutProviderWithPaymentProvider:provider
checkoutID:checkoutID
settings:checkoutSettings];
let checkoutProvider = OPPCheckoutProvider(paymentProvider: provider, checkoutID: checkoutID!, settings: checkoutSettings)
Then, open the payment page and implement the callbacks.
// Since version 2.13.0
[checkoutProvider presentCheckoutForSubmittingTransactionCompletionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
if (error) {
// Executed in case of failure of the transaction for any reason
} else if (transaction.type == OPPTransactionTypeSynchronous) {
// Send request to your server to obtain the status of the synchronous transaction
// You can use transaction.resourcePath or just checkout id to do it
} else {
// The SDK opens transaction.redirectUrl in a browser
// See 'Asynchronous Payments' guide for more details
}
} cancelHandler:^{
// Executed if the shopper closes the payment page prematurely
}];
// Since version 2.13.0
checkoutProvider?.presentCheckout(forSubmittingTransactionCompletionHandler: { (transaction, error) in
guard let transaction = transaction else {
// Handle invalid transaction, check error
return
}
if transaction.type == .synchronous {
// If a transaction is synchronous, just request the payment status
// You can use transaction.resourcePath or just checkout ID to do it
} else if transaction.type == .asynchronous {
// The SDK opens transaction.redirectUrl in a browser
// See 'Asynchronous Payments' guide for more details
} else {
// Executed in case of failure of the transaction for any reason
}
}, cancelHandler: {
// Executed if the shopper closes the payment page prematurely
})
For versions 2.12.0 and earlier use another method to open the checkout page.
Note there is an additional callback paymentBrandSelectedHandler
which allows you to create and pass to the SDK new checkout ID. In newer versions this callback is moved to OPPCheckoutProviderDelegate
. You may need this feature to send additional parameters at 1st step for specific payment brands. Otherwise set callback to nil
.
[checkoutProvider presentCheckoutForSubmittingTransactionCompletionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
// Handle transaction submitting result as shown in previous sample
} paymentBrandSelectedHandler:nil cancelHandler:^{
// Executed if the shopper closes the payment page prematurely
}];
checkoutProvider?.presentCheckout(forSubmittingTransactionCompletionHandler: { (transaction, error) in
// Handle transaction submitting result as shown in previous sample
}, paymentBrandSelectedHandler:nil, cancelHandler: {
// Executed if the shopper closes the payment page prematurely
})
NOTE: To ensure that the credit card data of the shopper is safe, close the payment pages when the app is sent to the background. Use the method
dismissCheckoutAnimated:completion:
of OPPCheckoutProvider
.[Optional] 4. Security. Disable third party keyboards.
A malicious third party keyboard may perform key-logging and transmit the logged information to an attacker’s server. It's recommended to disable the usage of third party keyboards entirely in your application. Note that this may degrade the user experience of your application.
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier {
if (extensionPointIdentifier == UIApplicationKeyboardExtensionPointIdentifier) {
return NO;
}
return YES;
}
func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplicationExtensionPointIdentifier) -> Bool {
if (extensionPointIdentifier == UIApplicationExtensionPointIdentifier.keyboard) {
return false
}
return true
}
Request Payment Status
Finally your app should request the payment status from your server (again, adapt this example to your own setup).
NSString *URL = [NSString stringWithFormat:@"https://YOUR_URL/paymentStatus?resourcePath=%@", [transaction.resourcePath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:URL]];
[[[NSURLSession sharedSession] dataTaskWithRequest:merchantServerRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// handle error
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
BOOL status = [result[@"paymentResult"] boolValue];
}] resume];
let url = String(format: "https://YOUR_URL/paymentStatus?resourcePath=%@", transaction.resourcePath!.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
let merchantServerRequest = NSURLRequest(url: URL(string: url)!)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let transactionStatus = json?["paymentResult"] as? Bool
}
}.resume()
NOTE: The transaction status may be not available immediately. To support all statuses please refer to the "Result Codes".
Testing
The sandbox environment only accepts test payment parameters.
You can find test values for credit cards and bank accounts in our Testing Guide.
Go to Production
1. Talk to your account manager to get the live credentials.
2. Adjust the server type to LIVE in your initialization of OPPPaymentProvider
.
self.provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeLive];
let provider = OPPPaymentProvider(mode: OPPProviderMode.live)
3. Change your backend to use the correct API endpoints and credentials.
Present Checkout UI
1. Configure the Checkout Settings
Define the settings for the checkout screen. Initialize CheckoutSettings
with received checkout ID, it controls the information that is shown to the shopper.
For the first integration we recommend you to enable only synchronous payment methods, other payment brands need additional configuration.
Set<String> paymentBrands = new LinkedHashSet<String>();
paymentBrands.add("VISA");
paymentBrands.add("MASTER");
paymentBrands.add("DIRECTDEBIT_SEPA");
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, paymentBrands, Connect.ProviderMode.TEST);
// Set shopper result URL
checkoutSettings.setShopperResultUrl("companyname://result");
NOTE: To learn more about shopper result url refer to Asynchronous Payments guide.
2. Present the Checkout Page
Set up the Intent
and start the checkout activity:
Intent intent = checkoutSettings.createCheckoutActivityIntent(this);
startActivityForResult(intent, CheckoutActivity.REQUEST_CODE_CHECKOUT);
Finally, override onActivityResult
to get notified when the checkout process is done.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) {
case CheckoutActivity.RESULT_OK:
/* transaction completed */
Transaction transaction = data.getParcelableExtra(CheckoutActivity.CHECKOUT_RESULT_TRANSACTION);
/* resource path if needed */
String resourcePath = data.getStringExtra(CheckoutActivity.CHECKOUT_RESULT_RESOURCE_PATH);
if (transaction.getTransactionType() == TransactionType.SYNC) {
/* check the result of synchronous transaction */
} else {
/* wait for the asynchronous transaction callback in the onNewIntent() */
}
break;
case CheckoutActivity.RESULT_CANCELED:
/* shopper canceled the checkout process */
break;
case CheckoutActivity.RESULT_ERROR:
/* error occurred */
PaymentError error = data.getParcelableExtra(CheckoutActivity.CHECKOUT_RESULT_ERROR);
}
}
NOTE: The getErrorInfo() method of the PaymentError can be used to get more details about the error.
Request Payment Status
Finally your app should request the payment status from your server (adapt this example to your own setup).
public String requestPaymentStatus() {
URL url;
String urlString;
HttpURLConnection connection = null;
String paymentStatus = null;
urlString = YOUR_URL + "/paymentStatus?resourcePath=" + URLEncoder.encode(RESOURCE_PATH, "UTF-8");
try {
url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
JsonReader jsonReader = new JsonReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"));
jsonReader.beginObject();
while (jsonReader.hasNext()) {
if (jsonReader.nextName().equals("paymentResult")) {
paymentStatus = jsonReader.nextString();
break;
}
}
jsonReader.endObject();
jsonReader.close();
} catch (Exception e) {
/* error occurred */
} finally {
if (connection != null) {
connection.disconnect();
}
}
return paymentStatus;
}
NOTE: The transaction status may be not available immediately. To support all statuses please refer to the "Result Codes".
Testing
The sandbox environment only accepts test payment parameters.
You can find test values for credit cards and bank accounts in our Testing Guide.
Go to Production
1. Talk to your account manager to get the live credentials.
2. Adjust the server type to LIVE in your initialization of PaymentProvider
.
binder.initializeProvider(Connect.ProviderMode.LIVE);