Android Embed
Integrate PortOne Payment Gateway with your Android app using the PortOne Android SDK and start accepting payments.
You can use PortOne SDK to integrate the PortOne Payment Gateway with your Android Application.
Video Tutorial
Part-1
Part-2
Sample App
Check the sample app
Prerequisites
- Create an account on PortOne
- Enable Payment Channels and Methods of your choice
authKey
to access
authKey
authKey will be issued by the PortOne Team.
- Send an email to [email protected] to request the authKey.
Integration
Steps to integrate your Android application with PortOne Android SDK.
- Install PortOne Android SDK and authorise it.
- Initialise theÂ
PortOne
 Instance in the activity where the checkout is being processed. - Set the Intent Filters in the manifests of the Android App.
- Set Intent Receivers to receive the payment status
- Have a setup to get JWT token from the server.
- Generate a signature hash to be passed with the payload
1. Install PortOne Android SDK and authorise it
- To add PortOne SDK as a dependency, locate
build.gradle
(:app) in your Android app and add the following line
implementation 'com.github.iamport-intl:chaipay-android-native-sdk:V3.0.37'
- To access the PortOne SDK, you will require authorisation key to be added in your
gradle.properties
authKey= XXXXXXXXXXXXXXXXXXXXXX
- We must utilize the authkey in order to access the PortOne SDK. To
build.gradle
(:Project) orsettings.gradle
, add the following snippets.
repositories {
maven { url '<https://maven.google.com/>' }
maven{
url '<https://jitpack.io>'
credentials { username authKey }
}
}
- Include the following lines of code in build.gradle (:Project), mentioning the project dependency and the kotlin version.
buildscript {
ext.kotlin_version = "1.5.10"
dependencies {
classpath 'com.google.gms:google-services:3.0.0'
}
}
2. Initialise the PortOne
 Instance in the activity where the checkout is being processed.
PortOne
 Instance in the activity where the checkout is being processed.The PortOne object will be used to access checkout functions. You will additionally require to pass the environment, whether SANDBOX or LIVE.
private var environment = "sandbox" // For Sandbox
private var environment = "live" // For Live
private lateinit var portOne: PortOne
portone = PortOneImpl(this, "$environment")
3. Set the Intent Filters in the manifests of the Android App.
Add the following Intent Filter to the Activity to which you want the user to navigate after payment is completed. Default should be Checkout Activity.
To configure the intent filters, there are two parameters in the data
tag: host
and scheme
, whose values will be determined by the redirection URL.
if redirectionUrl= "**portone://checkout"**
then host = "**checkout"**
`scheme = "**portone"**`
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="checkout"
android:scheme="portone" />
</intent-filter>
4. Set Intent Receivers to receive the payment status
- If we have an app-to-app flow, our app will receive a deep link via intent after checkout, which we will provide to the SDK using the method below.
if (null != intent && null != intent.data) {
val paymentStatus = intent.data.toString()
portone.updatePaymentStatus(paymentStatus)
}
- The following method has to be added on the checkout activity where the checkout action has performed to receive the checkout status after checkout completion the HashMap format.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_CODE && data != null) {
when (requestCode) {
PAYOUT_REQUEST_CODE, PAYMENT_STATUS_REQUEST_CODE -> {
val paymentStatus: PaymentDto.PaymentStatus? =
(data.getSerializableExtra(PAYMENT_STATUS)
?: "Empty") as PaymentDto.PaymentStatus
}
}
}
}
5. Have a setup to get JWT token from the server
On the server side, a JWT token must be constructed that accepts portoneKey as input. Further information on JWT token generation is described in the link below.
6. Generate Signture Hash
Make a Signature Hash that will be included in the payload.
internal fun getSignatureHash(
amount: String,
currency: String,
failureUrl: String,
orderId: String,
clientKey: String,
successUrl: String
): String {
val hashMap: HashMap<String, String> = HashMap()
hashMap["amount"] = amount
hashMap["currency"] = currency
hashMap["failure_url"] = failureUrl
hashMap["merchant_order_id"] = orderId
hashMap["client_key"] = clientKey
hashMap["success_url"] = successUrl
val message = StringBuilder()
for ((key, value) in hashMap.toSortedMap().entries) {
val values = URLEncoder.encode(value, "UTF-8")
if (message.isNotEmpty()) {
message.append("&$key=$values")
} else {
message.append("$key=$values")
}
}
val sha256 = Hashing.hmacSha256(SECRET_KEY.toByteArray(StandardCharsets.UTF_8))
.hashString(message, StandardCharsets.UTF_8).asBytes()
val base64: String = Base64.encodeToString(sha256, Base64.DEFAULT)
Log.i(TAG_CHAI_PAY, "SignatureHash:base64-> $base64")
return base64.trim()
}
Checkout using Web (V3)
Our web checkout method involves processing of web-based payouts. To do this, we need to call a method, but first we need to prepare the method’s parameters, which include the following.
All the data types in the form of an object
Parameters | Data Type | |
---|---|---|
token | String | mandatory |
clientKey | String | mandatory |
request | CheckoutPaymentDto.CheckoutUsingWebRequest | mandatory |
CheckoutPaymentDto.CheckoutUsingWebRequest
CheckoutPaymentDto.CheckoutUsingWebRequest
All of the web checkout request's parameters are listed here, along with the appropriate data type.
Parameters | Data Type | |
---|---|---|
chaipayKey | String | mandatory |
merchantDetails | CheckoutPaymentDto.MerchantDetails | |
merchantOrderId | String | mandatory |
signatureHash | String | mandatory |
amount | Double | mandatory |
currency | String | mandatory |
countryCode | String | mandatory |
billingDetails | CheckoutPaymentDto.BillingDetails | Optional |
shippingDetails | CheckoutPaymentDto.ShippingDetails | Optional |
orderDetails | List<CheckoutPaymentDto.OrderDetail> | Optional |
successUrl | String | mandatory |
failureUrl | String | mandatory |
expiryHours | Int | mandatory |
source | String | mandatory |
description | String | Optional |
showShippingDetails | Boolean | Optional |
showBackButton | Boolean | Optional |
defaultGuestCheckout | Boolean | Optional |
isCheckoutEmbed | Boolean | Optional |
redirectUrl | String | mandatory |
environment | String | mandatory |
CheckoutPaymentDto.MerchantDetails
CheckoutPaymentDto.MerchantDetails
Parameters | Data Type | |
---|---|---|
name | String | Optional |
logo | String | Optional |
backUrl | String | Optional |
promoCode | String | Optional |
promoDiscount | Int | Optional |
shippingCharges | Double | Optional |
CheckoutPaymentDto.BillingDetails
CheckoutPaymentDto.BillingDetails
Parameters | Data Type | |
---|---|---|
shippingName | String | Optional |
shippingEmail | String | Optional |
shippingPhone | String | Optional |
shippingAddress | CheckoutPaymentDto.Address | Optional |
CheckoutPaymentDto.ShippingDetails
CheckoutPaymentDto.ShippingDetails
Parameters | Data Type | |
---|---|---|
billingName | String | Optional |
billingEmail | String | Optional |
billingPhone | String | Optional |
billingAddress | CheckoutPaymentDto.Address | Optional |
CheckoutPaymentDto.Address
CheckoutPaymentDto.Address
Parameters | Data Type | |
---|---|---|
city | String | Optional |
countryCode | String | Optional |
locale | String | Optional |
line_1 | String | Optional |
line_2 | String | Optional |
postal_code | String | Optional |
state | String | Optional |
CheckoutPaymentDto.OrderDetail
CheckoutPaymentDto.OrderDetail
Parameters | Data Type | |
---|---|---|
id | String | Optional |
price | Double | Optional |
name | String | Optional |
quantity | Int | Optional |
image | String (in the form of web url) | Optional |
Sample dumy Request:
fun getWebCheckoutRequest(): CheckoutPaymentDto.CheckoutUsingWebRequest {
val orderId = "merchant_order_id_001"
val signatureHash =
Utility.getSignatureHash(
"50010",
currency,
"https://dev-checkout.portone.io/failure.html",
orderId,
clientKey,
"https://dev-checkout.portone.io/success.html"
)
val orderDetail: CheckoutPaymentDto.OrderDetail = CheckoutPaymentDto.OrderDetail(
id = "knb",
name = "kim nguyen bao",
price = 50010.00,
quantity = 1,
image = "https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.amazon.in%2FWORLD-WEAR-FOOTWEAR-Red-1243-Comfortable%2Fdp%2FB07WRZW939&psig=AOvVaw3EEZHcjsC6i5FltZjpjYjB&ust=1709615063971000&source=images&cd=vfe&opi=89978449&ved=0CBMQjRxqFwoTCNCV_cfq2YQDFQAAAAAdAAAAABAD"
)
val orderList = ArrayList<CheckoutPaymentDto.OrderDetail>()
orderList.add(orderDetail)
val orderDetails = CheckoutPaymentDto.CheckoutUsingWebRequest()
orderDetails.chaipayKey = clientKey
orderDetails.merchantDetails = CheckoutPaymentDto.MerchantDetails(
name = "Gumnam",
logo = "https://www.google.com/imgres?imgurl=https%3A%2F%2Fcdn.dribbble.com%2Fuserupload%2F10790076%2Ffile%2Foriginal-ff791b20101e6551b2ade568108f5dba.png%3Fresize%3D400x300%26vertical%3Dcenter&tbnid=jYyQOvc0cqGZIM&vet=12ahUKEwjO08r-6tmEAxU9_DgGHdetAnEQMygMegUIARCIAQ..i&imgrefurl=https%3A%2F%2Fdribbble.com%2Fsearch%2Flogo&docid=95YyYbaoa7wZ4M&w=400&h=300&q=logo&ved=2ahUKEwjO08r-6tmEAxU9_DgGHdetAnEQMygMegUIARCIAQ",
backUrl = "https://demo.portone.io/checkout.html",
promoCode = "Gumnam420",
promoDiscount = 10000,
shippingCharges = 10000.00
)
orderDetails.merchantOrderId = orderId
orderDetails.signatureHash = signatureHash.trim()
orderDetails.amount = 50010.00
orderDetails.currency = currency
orderDetails.countryCode = "VN"
orderDetails.billingDetails = CheckoutPaymentDto.BillingDetails(
billingName = "Test mark",
billingEmail = "[email protected]",
billingPhone = phoneNo,
billingAddress = CheckoutPaymentDto.Address(
city = currency, countryCode = "VN", locale = "en",
line_1 = "address",
line_2 = "address_2",
postal_code = "400202",
state = "Mah"
)
)
orderDetails.shippingDetails = CheckoutPaymentDto.ShippingDetails(
shippingName = "Test mark",
shippingEmail = "[email protected]",
shippingPhone = phoneNo,
shippingAddress = CheckoutPaymentDto.Address(
city = currency, countryCode = "VN", locale = "en",
line_1 = "address",
line_2 = "address_2",
postal_code = "400202",
state = "Mah"
)
)
orderDetails.orderDetails = orderList
orderDetails.successUrl = "https://dev-checkout.portone.io/success.html"
orderDetails.failureUrl = "https://dev-checkout.portone.io/failure.html"
orderDetails.expiryHours = 1
orderDetails.source = "mobile"
orderDetails.description = "By Aagam"
orderDetails.showShippingDetails = true
orderDetails.showBackButton = true
orderDetails.defaultGuestCheckout = true
orderDetails.isCheckoutEmbed = false
orderDetails.env = devEnvironment
orderDetails.redirectUrl = "portone://checkout"
orderDetails.environment = environment
return orderDetails
}
This is the method that has been utilised to process the web checkout.
val checkoutDetails = CheckoutPaymentDto.CheckoutUsingWebRequest()
portone.checkoutUsingWeb(
token = getJwtToken(clientKey),
clientKey = clientKey,
request = checkoutDetails
)
After the payment completion the payment status will be received on onActivityResult we we have already added while integration.
Probable Errors:
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
INVALID_UNAUTHORIZED_JWT_TOKEN_ERROR
- Check whether PortOne Key and the Secret Key are of the same account
- Check whether the Secret Key is not modified
- Check whether
Bearer
keyword is added before the generated token with a white space.Bearer $jwtToken
- Verify if the expiration time should be greater than the current time
INVALID_UNAUTHORISED_TRANSACTION_SIGNATURE_ERROR
INVALID_UNAUTHORISED_TRANSACTION_SIGNATURE_ERROR
- Check whether all params match with the payload/request
- Check whether the portone key match with the payload and the account
INVALID_UNAUTHORISED_TRANSACTION_IAMPORTKEY_ERROR
INVALID_UNAUTHORISED_TRANSACTION_IAMPORTKEY_ERROR
- Check whether the portone key match with the payload and the account
INVALID_PAYMENT_CHANNEL
INVALID_PAYMENT_CHANNEL
- Make sure the payment channels and payment methods which are added in the payload are enable from the portone portal
INVALID_ENVIRONMENT
INVALID_ENVIRONMENT
- Make sure you have added environment either
sandbox
orlive
Summation of order value, tax, duties, shipping and discount is equal to amount
Summation of order value, tax, duties, shipping and discount is equal to amount
- If items are provided then please verify the values provided should match the total amount:Â
sum(items price * items quantity) + shipping charge - discount = amount
- Mandatory params in payload:
price
promo_discount (0 is also acceptable)
shipping_charges (0 is also acceptable)
Updated 12 days ago