NAV

Mobile - App to App

Giới thiệu Demo Hướng dẫn tích hợp

Các bước tích hợp

  1. End-user chọn hình thức thanh toán bằng ZaloPay trên App của Merchant.
  2. Merchant gửi yêu cầu tạo đơn thanh toán (API Tạo đơn hàng) sang cho ZaloPay. ZaloPay trả thông tin đơn hàng về cho Merchant.
  3. App của Merchant gọi thanh toán bằng thông tin zp_trans_token trả về, SDK sẽ mở app ZaloPay/Zalo để End-user thực hiện bước thanh toán.
    Trường hợp device user không có app ZaloPay và Zalo, merchant sử dụng SDK để redirect đến App Store/Google Play của ZaloPay hoặc Zalo tương ứng.
  4. End-user thanh toán hoàn tất, app ZaloPay/Zalo sẽ mở lại App của Merchant để hiển thị kết quả giao dịch.
  5. Merchant Server  truy vấn trạng thái đơn hàng khi chưa nhận được Callback
  6. Merchant Server xử lý Callback từ ZaloPay khi End-user thanh toán thành công

Luồng xử lý chính

App to App Payment Flow

Trường hợp không có cài đặt ZaloPay

App to App Payment Flow

Tải về SDK AppToApp

Đối với iOS

Tích hợp SDK AppToApp

SDK AppToApp được phân phối dưới dạng thư viện, để sử dụng các API của ZPDK, cần tích hợp vào project theo các bước sau

  1. Thêm framework ZPDK.framework vào project
  2. Cấu hình cho phép khởi tạo ZaloPay từ app, bằng cách thêm  zalozalopay và zalopay.api.v2 vào key  LSApplicationQueriesSchemes
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>zalo</string>
    <string>zalopay</string>
    <string>zalopay.api.v2</string>
</array>

Khởi tạo ZPDK

Trong AppDelegate.m, thêm lời gọi tới ZPDK để xử lý việc trao đổi dữ liệu giữa ZaloPay và app

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [[ZaloPaySDK sharedInstance] initWithAppId:<appID> uriScheme:@"<uriScheme>" environment:<ZPZPIEnvironment>]; //Khởi tạo ZPDK
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
  return [[ZaloPaySDK sharedInstance] application:app openURL:url sourceApplication:@"vn.com.vng.zalopay" annotation:nil]; //gọi tới ZPDK để xử lý trao đổi dữ liệu giữa ZaloPay với app
}
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    ZaloPaySDK.sharedInstance()?.initWithAppId(<appid>, uriScheme: "<uriScheme>", environment: <ZPZPIEnvironment>)
    return true
  }

  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return ZaloPaySDK.sharedInstance().application(app, open: url, sourceApplication:"vn.com.vng.zalopay", annotation: nil)
  }

Lưu ý: Gọi hàm này vì ZPDK hiện đang check sourceApplication có đúng là của ZaloPay hay không.

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {}

Gọi hàm thanh toán

Gọi hàm để bắt đầu thanh toán

  [[ZaloPaySDK sharedInstance] initWithAppId:<appID> uriScheme:@"<uriScheme>" environment:<ZPZPIEnvironment>]; //Reinit ZPDK nếu muốn thanh toán bằng một AppID khác
  [ZaloPaySDK sharedInstance].paymentDelegate = self; //Depend on where you handle ZPPaymentDelegate.
  [[ZaloPaySDK sharedInstance] payOrder:zpTransToken];
  ZaloPaySDK.sharedInstance()?.initWithAppId(<appid>, uriScheme: "<uriScheme>", environment: <ZPZPIEnvironment>) //Reinit ZPDK nếu muốn thanh toán bằng một AppID khác
  ZaloPaySDK.sharedInstance()?.paymentDelegate = self  //Depend on where you handle ZPPaymentDelegate. 
  ZaloPaySDK.sharedInstance()?.payOrder(zpTransToken.text)

Xử lý kết quả trả về

  - (void)paymentDidSucceeded:(NSString *)transactionId zpTranstoken:(NSString *)zpTranstoken appTransId:(NSString *)appTransId {
    //Handle Success
  }
  - (void)paymentDidCanceled:(NSString *)zpTranstoken appTransId:(NSString *)appTransId {
    //Handle User Canceled
  }
  - (void)paymentDidError:(ZPPaymentErrorCode)errorCode zpTranstoken:(NSString *)zpTranstoken appTransId:(NSString *)appTransId {
    //Redirect to Zalo/ZaloPay Store when errorCode == ZPPaymentErrorCode.appNotInstall
    //Handle Error
  }
  func paymentDidSucceeded(_ transactionId: String!, zpTranstoken: String!, appTransId: String!) {
      //Handle Success
  }

  func paymentDidCanceled(_ zpTranstoken: String!, appTransId: String!) {
      //Handle User Canceled
  }

  func paymentDidError(_ errorCode: ZPPaymentErrorCode, zpTranstoken : String!, appTransId: String!) {
      //Redirect to Zalo/ZaloPay Store when errorCode == ZPPaymentErrorCode.appNotInstall
      //Handle Error
  }

Đối với Android

Tích hợp SDK AppToApp

Để tích hợp SDK AppToApp vào Android Studio bạn thực hiện các bước sau:

configurations.maybeCreate("default")
artifacts.add("default", file('zpdk-release.aar'))

Khởi tạo ZPDK

Thêm lời khởi tạo ZPDK trong hàm onCreate của Application

@Override
public void onCreate() {
  ...
  //Khởi tạo ZPDK
  ZaloPaySDK.init(<appID>, <Environment>);
}
    override fun onCreate(savedInstanceState: Bundle?) {
      ..
      ZaloPaySDK.init(<appID>, Environment);
    }

Gọi hàm thanh toán từ ZPDK và nhận callback

//Cần bắt sự kiện OnNewIntent vì ZaloPay App sẽ gọi deeplink về app của Merchant
@Override
public void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
  ZaloPaySDK.getInstance().onResult(intent);
}

//Reinit ZPDK nếu muốn thanh toán bằng một AppID khác
ZaloPaySDK.tearDown();
ZaloPaySDK.init(<appID>, <Environment>);

//Gọi hàm thanh toán
ZaloPaySDK.getInstance().payOrder(
  <Activity>, <Token>, <YourAppUriScheme>, new MyZaloPayListener()
);

//Implement interface PayOrderListener để nhận kết quả thanh toán 
private static class MyZaloPayListener implements PayOrderListener {
  @Override
  public void onPaymentSucceeded(final String transactionId, final String transToken, final String appTransID) {
    //Handle Success
  }

  @Override
  public void onPaymentCanceled(String zpTransToken, String appTransID) {
    //Handle User Canceled
  }
  @Override
  public void onPaymentError(ZaloPayError zaloPayError, String zpTransToken, String appTransID) {
    //Redirect to Zalo/ZaloPay Store when zaloPayError == ZaloPayError.PAYMENT_APP_NOT_FOUND
    //Handle Error
  }
}
  //Cần bắt sự kiện OnNewIntent vì ZaloPay App sẽ gọi deeplink về app của Merchant
  override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    ZaloPaySDK.getInstance().onResult(intent)
  }

  //Reinit ZPDK nếu muốn thanh toán bằng một AppID khác
  ZaloPaySDK.tearDown();
  ZaloPaySDK.init(<appID>, Environment);

  //Gọi hàm thanh toán
  ZaloPaySDK.getInstance().payOrder(<Activity>, <Token>!!, "<MerchantApp Deeplink>",object: PayOrderListener {
    override fun onPaymentCanceled(zpTransToken: String?, appTransID: String?) {
      //Handle User Canceled
    }
    override fun onPaymentError(zaloPayErrorCode: ZaloPayError?, zpTransToken: String?, appTransID: String?) {
      //Redirect to Zalo/ZaloPay Store when zaloPayError == ZaloPayError.PAYMENT_APP_NOT_FOUND
      //Handle Error
    }
    override fun onPaymentSucceeded(transactionId: String, transToken: String, appTransID: String?) {
      //Handle Success
    }
  })

Đối với React Native

Tích hợp và khởi tạo ZPDK

iOS

Android

  1. Mở project android bên trong project React Native đang làm việc bằng android studio
  2. Thực hiện các bước tiếp theo tương tự như phần Android ở trên
  3. Trong hàm getPackages(), thêm new PayZaloBridge() bên trong hàm Array.asList(...) như sau:
@Override
protected List<ReactPackage> getPackages() {
  return Array.asList(
    ...,
    new PayZaloBridge()
  );
}

Gọi hàm thanh toán

import {NativeModules, NativeEventEmitter} from 'react-native';
const { PayZaloBridge } = NativeModules;
const payZaloBridgeEmitter = new NativeEventEmitter(PayZaloBridge);

componentDidMount() {
  this.subscription = payZaloBridgeEmitter.addListener(
    'EventPayZalo',
    (data) => {
      if(data.returnCode == 1){
        alert('Giao dịch thành công!');
      } else{
        alert('Giao dịch thất bại!');
      }
    }
  );
}

componentWillUnmount() {
  this.subscription.remove();
}

let payZP = NativeModules.PayZaloBridge;
payZP.payOrder(zptranstoken);

Đối với Flutter

Tích hợp ZPDK

iOS

Tạo MethodChannel để gọi hàm thanh toán ZaloPay

  static const MethodChannel platform = MethodChannel('flutter.native/channelPayOrder'); //Example of creating MethodChannel

  final String result = await platform.invokeMethod('payOrder', {"zptoken": zpToken}); //Example of calling payOrder

Tạo EventChannel để nhận kết quả trả về từ ZaloPay

static const EventChannel eventChannel = EventChannel('flutter.native/eventPayOrder');
  @override
  void initState() {
    super.initState();
    if (Platform.isIOS) {
      eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); //Listening for event
    }
  }

Gửi kết quả đến EventChannel

  private var eventSink: FlutterEventSink?

  func paymentDidSucceeded(_ transactionId: String!, zpTranstoken: String!, appTransId: String!) {
    //Example of Handling Success
    guard let eventSink = eventSink else {
      return
    }
    eventSink(["errorCode": 1, "zpTranstoken": zpTranstoken, "transactionId": transactionId, "appTransId": appTransId])
  }
  func paymentDidCanceled(_ zpTranstoken: String!, appTransId: String!) {
    //Example of Handling User Canceled
    guard let eventSink = eventSink else {
      return
    }
    eventSink(["errorCode": 4, "zpTranstoken": zpTranstoken, "appTransId": appTransId])
  }
  func paymentDidError(_ errorCode: ZPPaymentErrorCode, zpTranstoken: String!, appTransId: String!) {
    //Example of Handling Error
    guard let eventSink = eventSink else {
      return
    }
    //Redirect to Zalo/ZaloPay Store when errorCode == ZPPaymentErrorCode.appNotInstall
    eventSink(["errorCode": errorCode, "zpTranstoken": zpTranstoken, "appTransId": appTransId])
  }

Android

Dùng Method Channel để gọi đến hàm thanh toán và trả kết quả về Flutter

MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channelPayOrder)
  .setMethodCallHandler { call, result ->
    if (call.method == "payOrder"){
        val token = call.argument<String>("zptoken")
        ZaloPaySDK.getInstance().payOrder(this@MainActivity, token !!, "<UriScheme>",object: PayOrderListener {
            override fun onPaymentCanceled(zpTransToken: String?, appTransID: String?) {
              result.success("User Canceled")
            }
            override fun onPaymentError(zaloPayErrorCode: ZaloPayError?, zpTransToken: String?, appTransID: String?) {
              //Redirect to Zalo/ZaloPay Store when zaloPayError == ZaloPayError.PAYMENT_APP_NOT_FOUND
              result.success("Payment failed")
            }
            override fun onPaymentSucceeded(transactionId: String, transToken: String, appTransID: String?) {
              result.success("Payment Success")
            }
        })
    }
  }

Dữ liệu trả về của ZPDK

Trường hợp Thanh toán thành công - Handle function paymentDidSucceeded()

Tham số Kiểu dữ liệu Ý nghĩa
transactionId string Mã zp_trans_id của giao dịch
zpTranstoken string Mã zp_trans_token của đơn hàng thanh toán
appTransId string Mã app_trans_id của giao dịch

Trường hợp User huỷ thanh toán - Handle function paymentDidCanceled()

Tham số Kiểu dữ liệu Ý nghĩa
zpTranstoken string Mã zp_trans_token của đơn hàng thanh toán
appTransId string Mã app_trans_id của giao dịch

Trường hợp thanh toán lỗi - Handle function paymentDidError()

Tham số Kiểu dữ liệu Ý nghĩa
errorCode number Thông tin mã lỗi
zpTranstoken string Mã zp_trans_token của đơn hàng thanh toán
appTransId string Mã app_trans_id của giao dịch

Ghi chú: Với trường hợp user chưa có app ZaloPay hoặc Zalo sẽ trả về mã lỗi: -1. Merchant cần thực hiện navigator tới App Store /Google Play để user thực hiện download app.
Example với trường hợp chưa có app

{
  if errorCode == ZPPaymentErrorCode.appNotInstall {

      ZaloPaySDK.sharedInstance()?.navigateToZaloStore();            // navigator to Zalo App

      // ZaloPaySDK.sharedInstance()?.navigateToZaloPayStore();   // navigator to ZaloPay App

      return;
  }
}
Không tìm thấy kết quả phù hợp