Skip to main content

Alipay App

Let customers pay from your Android or iOS app using the Alipay payment SDK. Your backend creates an alipay_app session. The API returns a signed order string; your app passes that string to the SDK and checks the payment through your backend afterward.

1. Prepare your app​

Complete the following setup before making a live payment. Follow the Android or iOS subsection for the app you are building; both use the same backend order-creation request in step 2.

1.1 Collect the configuration​

ValueWhere you use it
Platform application ID and enabled alipay_app entryYour server's create-session request.
Payment API key with payments:write, payments:read, and operations:readYour server's secret store.
Alipay provider AppID bound to your appSDK registration. It is not the platform app_id.
Android application ID and release certificate, or iOS bundle IDThe installed app must match the activated registration.
iOS URL Scheme and HTTPS Universal LinkReturn from Alipay to your app.
Your backend checkout and order-status routesApp-to-server requests in steps 2–4.

Obtain the activated configuration from NextAppMarket. Signing keys and provider order creation are handled by the platform. You do not implement Alipay's server SDK, construct biz_content, or add a provider private key to the app.

The versions below are published SDK versions checked for this guide, not a claim that your release build has passed device testing. Keep the pinned version in your build and validate upgrades before changing it.

1.2 Install on Android​

  1. In settings.gradle, make Maven Central available to application dependencies:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
  1. Add the dependency to app/build.gradle:
dependencies {
implementation 'com.alipay.sdk:alipaysdk-android:15.8.42'
}

This AAR declares Android API 21 as its minimum. Use an app minSdk of at least 21 for this version. Keep your app's supported compileSdk and targetSdk settings; do not copy the library's historical target setting into your app.

  1. Remove a separately bundled older Alipay AAR from the dependency graph if you are replacing it. Keep one SDK copy; a local AAR plus Maven dependency can cause duplicate classes.
  2. Confirm the following permissions in the merged Android manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

The published AAR supplies its activities, package visibility entries, and consumer shrinker rules. Inspect Android Studio → Merged Manifest to ensure your app's overrides have not removed them. Do not add a custom payment-result Activity that competes with the SDK's own result handling.

  1. Sync Gradle and build your app. On the checkout screen, register the provider AppID before payment:
import com.alipay.sdk.app.AlipayApi
import com.alipay.sdk.app.PayTask

AlipayApi.registerApp(this, configuredAlipayAppId)

this is your checkout Activity. configuredAlipayAppId is the provider ID from activation. Registration supports the SDK's security and launch optimizations; it does not create a payment. Checkpoint: the imports resolve and the signed app installs on your test device.

1.3 Install on iOS​

This walkthrough uses Alipay's official 15.8.40.1 XCFramework distribution, which includes device and Apple Silicon simulator slices.

  1. Download the official XCFramework package and unpack it. Use the standard distribution unless your project already has a conflicting UTDID component; in that case use the matching NoUtdid distribution.
  2. Add AlipaySDK.xcframework and AlipaySDK.bundle to the app target. Copy the bundle in Build Phases → Copy Bundle Resources. Link the static SDK without embedding its framework binary. Do not also install another Alipay pod or framework.
  3. Link the system dependencies required by the distribution: UIKit, Foundation, CFNetwork, SystemConfiguration, QuartzCore, CoreGraphics, CoreMotion, CoreTelephony, CoreText, WebKit, libc++.tbd, and libz.tbd. Preserve existing linker settings.
  4. Import the SDK in Objective-C:
#import <AlipaySDK/AlipaySDK.h>

For a Swift target, create YourApp-Bridging-Header.h, add this import and #import <UIKit/UIKit.h>, and set Build Settings → Objective-C Bridging Header to its project-relative path. The SDK boundary examples below use Objective-C; the rest of your app can remain Swift.

  1. Add an app-specific return scheme in Target → Info → URL Types, for example com.example.myapp.alipay. Use that same string in the payment call. In Info.plist, merge these query schemes if your app checks Alipay availability:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
<string>alipays</string>
</array>
  1. Configure an HTTPS Universal Link such as https://links.example.com/alipay/. Add Signing & Capabilities → Associated Domains → applinks:links.example.com. On that domain, serve /.well-known/apple-app-site-association over HTTPS, without a redirect, using your real Team ID and bundle ID:
{
"applinks": {
"apps": [],
"details": [{"appID": "ABCDE12345.com.example.myapp", "paths": ["/alipay/*"]}]
}
}

The wildcard permits the path Alipay appends to your configured link. Do not put a query string in the association path. Merge with existing associations instead of overwriting another app's entries.

  1. Before payment, register your provider identity:
[[AlipaySDK defaultService] registerApp:configuredAlipayAppId
universalLink:@"https://links.example.com/alipay/"];

Checkpoint: the app builds, the resource bundle is included, and tapping a matching Universal Link from another app can open your installed app. Test both the link and scheme callbacks in step 3. An association update may require a fresh install and time for Apple's cache to update.

Installation basis: Alipay Android integration, iOS integration, SDK distributions, and Universal Link setup. The steps needed for this integration are included above; these links are source references.

2. Create the order on your backend​

Authenticate the customer, calculate the price, and save the business order and payment attempt as described in Build your payment backend. Save the following body as payment.json, replacing the application and external order IDs:

{
"app_id": "app_demo",
"payment_entry": "alipay_app",
"amount_minor": 1000,
"currency": "CNY",
"external_order_id": "shop_order_1042",
"description": "100 app credits"
}
curl --fail-with-body --request POST \
'https://pay.appconnect.cn/payment/v1/payment-sessions' \
--header "Authorization: Bearer $PAYMENT_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: create-shop-order-1042-v1' \
--data-binary @payment.json

Use the key and exact body persisted for this attempt. Save data.order.id before returning the business order ID and data.invocation to the client. The Payment API key stays on your server.

If the invocation is null, keep the same order and retrieve its payment session. Do not create another order while the first result is unresolved.

Connect your Pay button​

Implement your authenticated POST /api/checkout endpoint, then copy the Android or iOS HTTP helper from Connect your app to checkout. That page defines beginCheckout, refreshPendingOrder, persistence, and the app-facing response used below.

Call beginCheckout with your cart ID and alipay_app. Save businessOrderId before launching the SDK. Your backend returns the platform invocation inside your app's checkout response. Check its kind, required fields, and expires_at; if the instructions are expired, query the existing order instead of opening the SDK. Do not hard-code the example order string or signed fields into a real payment.

Checkpoint: one tap produces one saved business order, one platform order ID, and the expected invocation. Repeat the request for the same unresolved attempt and verify that it does not create a second charge.

3. Open Alipay in your app​

Expect invocation.kind === "sdk_string". Check expires_at, persist the business order ID, and pass invocation.sdk_string unchanged. Do not URL-encode, decode, split, or re-sign the string.

Android​

This Kotlin function runs inside your checkout Activity. Add import com.alipay.sdk.app.PayTask. The refreshOrder callback is your application's authenticated status request, described in Confirm payment.

fun launchAlipay(
activity: android.app.Activity,
signedOrder: String,
refreshOrder: () -> Unit
) {
Thread {
try {
val result = PayTask(activity).payV2(signedOrder, true)
// result["resultStatus"] may inform the UI; it cannot grant goods.
activity.runOnUiThread { refreshOrder() }
} catch (error: Exception) {
// The outcome is unresolved even if the SDK call throws.
activity.runOnUiThread { refreshOrder() }
}
}.start()
}

Connect it to the shared checkout function from your Activity:

beginCheckout(cartId, "alipay_app") { invocation ->
requireUsableInvocation(invocation, "sdk_string")
val signedOrder = invocation.getString("sdk_string")
require(signedOrder.isNotEmpty())
launchAlipay(this, signedOrder, ::refreshPendingOrder)
}

Call this after checking the invocation, with its exact signed string. Disable repeated Pay taps while this invocation is active. Manage the worker with your app's lifecycle; if the Activity is destroyed, recover the stored business order from your order screen on the next launch.

iOS​

After saving the business order and validating sdk_string and expires_at, call the SDK on your checkout UI thread. Use the same scheme and Universal Link configured in step 1:

if (![self isUsableInvocation:invocation kind:@"sdk_string"] ||
![invocation[@"sdk_string"] isKindOfClass:[NSString class]] ||
[invocation[@"sdk_string"] length] == 0) {
[self refreshPendingOrder];
return;
}
[[AlipaySDK defaultService]
payOrder:invocation[@"sdk_string"]
fromScheme:@"com.example.myapp.alipay"
fromUniversalLink:@"https://links.example.com/alipay/"
callback:^(NSDictionary *result) {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]
postNotificationName:@"PaymentNeedsRefresh" object:nil];
});
}];

The completion block also covers the SDK's browser payment path. Do not require the Alipay app to be installed before allowing this SDK flow; test both installed and absent cases.

iOS callback wiring, including cold starts​

Add these methods to your existing AppDelegate or a long-lived payment router. They handle both return mechanisms:

- (void)paymentNeedsRefresh {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]
postNotificationName:@"PaymentNeedsRefresh" object:nil];
});
}

- (BOOL)routeAlipayURL:(NSURL *)url {
if (![url.scheme isEqualToString:@"com.example.myapp.alipay"] ||
![url.host isEqualToString:@"safepay"]) return NO;
[[AlipaySDK defaultService] processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *result) { [self paymentNeedsRefresh]; }];
return YES;
}

- (BOOL)routeAlipayActivity:(NSUserActivity *)activity {
NSURL *url = activity.webpageURL;
if (![activity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb] ||
![url.host isEqualToString:@"links.example.com"] ||
![url.path hasPrefix:@"/alipay/"]) return NO;
[[AlipaySDK defaultService] handleOpenUniversalLink:activity
standbyCallback:^(NSDictionary *result) { [self paymentNeedsRefresh]; }];
return YES;
}

In an AppDelegate-based app, forward application:openURL:options: to routeAlipayURL: and application:continueUserActivity:restorationHandler: to routeAlipayActivity:. If you have other providers or deep links, continue to their routers when an Alipay router returns NO.

For an app without scenes, these are the two AppDelegate entry points. Merge them with any existing provider/deep-link routing:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
return [self routeAlipayURL:url];
}

- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *))restorationHandler {
return [self routeAlipayActivity:userActivity];
}

For a scene-based app, add these methods to your existing SceneDelegate:

- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)contexts {
AppDelegate *app = (AppDelegate *)UIApplication.sharedApplication.delegate;
for (UIOpenURLContext *context in contexts) [app routeAlipayURL:context.URL];
}

- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)activity {
AppDelegate *app = (AppDelegate *)UIApplication.sharedApplication.delegate;
[app routeAlipayActivity:activity];
}

After initializing your checkout coordinator in scene:willConnectToSession:options:, pass connectionOptions.URLContexts and connectionOptions.userActivities to the same routers. Declare the router methods in your AppDelegate header so SceneDelegate can call them. Refresh persisted orders from sceneDidBecomeActive: even when no callback is received.

Add this at the end of your existing scene:willConnectToSession:options: implementation, after creating the UI and payment coordinator (retain your existing window setup):

AppDelegate *app = (AppDelegate *)UIApplication.sharedApplication.delegate;
for (UIOpenURLContext *context in connectionOptions.URLContexts) {
[app routeAlipayURL:context.URL];
}
for (NSUserActivity *activity in connectionOptions.userActivities) {
[app routeAlipayActivity:activity];
}

Your coordinator observes PaymentNeedsRefresh and calls the concrete status request in Connect your app to checkout. Keep the observer alive while the app can receive payment returns; remove it when the coordinator is disposed.

Interpret the SDK result​

resultStatusWhat your UI can sayWhat your backend must do
9000Checking payment.Retrieve and validate the platform order before delivery.
8000 or 6004Confirming payment.Reconcile the existing order; no automatic replacement.
6001Payment cancelled in the app.Check whether the order remains unpaid; cancellation does not close it.
6002Connection interrupted.Query the original order.
4000Payment could not be completed.Query and inspect the saved attempt before offering another payment.
5000A payment request is already active.Stop duplicate launch calls; resume the original order.
Other or missing valueUnable to confirm yet.Preserve the order and query it.

Use memo only for sanitized diagnostics. Do not log the full signed order string or SDK result. Server status controls customer access even when the client reports 9000.

4. Confirm payment and deliver the purchase​

When the customer returns, ask your backend for the business order's status. Your backend checks ownership and retrieves the saved platform order:

curl --fail-with-body \
'https://pay.appconnect.cn/payment/v1/orders/ord_demo_001' \
--header "Authorization: Bearer $PAYMENT_API_KEY"

Validate the returned identity, currency, and amount. Fulfill only after the authoritative status is paid, using a unique fulfillment record. A callback or a return to your page is a reason to check this order, not a reason to grant the purchase.

Implement webhooks and order reconciliation so confirmation works even when the customer closes the app or browser. Show a pending state for unresolved results and offer Check payment instead of immediately starting another charge.

5. Refund or close the order​

For a paid order, follow Refund a payment to submit a full or partial refund and track it to completion. Use the saved platform order ID; your client does not refund through the provider SDK.

For an abandoned unpaid order, use the close-order flow. Removing the payment UI does not close the order. Run the integration checklist before release.

6. Verify the complete flow​

Make an approved verification purchase with your signed app. Confirm these checkpoints in sequence: create-session returns an order ID → the SDK opens → the customer completes or cancels payment → your callback or foreground handler queries your backend → confirmed payment delivers once → a refund can be submitted and tracked from the same order.

Repeat with Alipay absent, an app cold start, a lost backend response, and a duplicate Pay tap. Test both URL Scheme and Universal Link return on iOS. Keep the order recoverable if your foreground page disappears.

7. Common problems and how to fix them​

SymptomCheck and fix
Gradle cannot resolve the SDKEnsure mavenCentral() is in dependency repositories, the pinned version is spelled correctly, and your build's repository policy permits it. Sync again.
Duplicate classes or duplicate symbolsCheck dependency output for both a local SDK and Maven/pod/framework copy. Keep one matching distribution. For iOS UTDID conflicts, use Alipay's matching NoUtdid package.
iOS cannot import the frameworkCheck app-target membership, framework search paths, and the bridging-header path for Swift. Build the selected app target with the SDK linked.
Apple Silicon simulator architecture errorUse the XCFramework distribution in this guide; do not mix it with a device-only framework. Payment verification still requires a physical device.
Pay button freezes the Android UIMove payV2 to the worker thread shown above; only render the result on the main thread.
SDK opens and immediately reports a parameter/signature failureCompare the original SDK string's byte length and SHA-256 digest across server and client. Remove extra URL encoding, trimming, or reconstruction. Check entry alipay_app, expiry, and provider AppID binding. If unchanged, send the platform request ID to support.
iOS never returns to your appCheck the scheme string matches exactly, AASA Team ID/bundle/path are correct, Associated Domains is in the installed entitlement, and both scheme and Universal Link handlers are wired. Test a cold start.
App returns but UI never updatesCheck that the callback emits the refresh trigger, your observer/coordinator is alive, the saved business order exists, and the status endpoint uses the signed-in customer's session.
Alipay is not installedAllow the SDK's supported browser flow; do not hard-fail only because the package is absent. Test its callback and return behavior separately.
9000 but the platform is still processingKeep a confirmation screen. Query with backoff and let the verified webhook/background worker reconcile. Do not grant goods or ask the customer to pay again.
Debug works, release failsCompare the installed package, signing identity, bundle ID, entitlements, and merged SDK configuration with activation. Test the actual distribution-signed build.
Customer paid but received no productInspect the platform order, saved business mapping, verified webhook inbox, and fulfillment/outbox record in that order. Recover delivery idempotently rather than creating a charge.

For API authentication, timeout, refund, and webhook issues, use the shared troubleshooting steps. When escalating, send platform request ID, platform/business order IDs, SDK version, OS, timestamp with time zone, and a sanitized status code. Never send keys or a complete signed order string.