Module tích hợp thanh toán ZaloPay vào ứng dụng React Native

 Module tích hợp thanh toán ZaloPay 
vào ứng dụng React Native


    Phần mới TíT xin nói về cách dùng ZaloPay cho thanh toán tiền(bài này nói về tích hợp ở chế độ sanbox nha mn). Docs thì m.n có thể đọc ở trang https://docs.zalopay.vn/v1/docs/apptoapp/overview.html

  • Luồng chính

            Thuật ngữ

            End-User: người mua hàng có sử dụng tài khoản ZaloPay.

            Merchant: người bán hàng, cá nhân hoặc đơn vị kinh doanh, cung ứng dịch vụ hoặc/và sản phẩm.

            ZaloPay: nền tảng thanh toán điện tử giúp Merchant tích hợp nhiều hình thức thanh toán để bán hàng cho End-User tiện hơn.

            - Sơ đồ 


            Bước 1: End-User chọn hình thức thanh toán bằng ZaloPay trên App của Merchant

            Bước 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.

            Bước 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 thanh toán. Trong trường hợp máy người dùng không có ZaloPay và Zalo, merchant sử dụng SDK để redirect đến App Store/Google Play Store của ZaloPay hay Zalo tương ứng.

            Bước 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.

  • Cách tích hợp trên Android và IOS
👉👉👉Về phần cài thì TíT hướng dẫn đối với AppToApp nha.

        💥Đầu tiên phải tải zalopaydk cho cả android và ios (https://docs.zalopay.vn/v1/docs/apptoapp/demo.html) 👇👇👇

💭Nếu không thể mở app zaloPay sanbox thì có thể do zdpk của zalopay k còn sử dụng ở v2 nữa nên mn hãy chuyển qua v5(ZPDK_v5.1.2.zip) nhé

    IOS

            - Để test được đầu tiên phải cài ZaloPay SanBox: https://stcstg.zalopay.com.vn/ps_res/ios/enterprise/sandboxmer/6.8.2/install.html 
đây là link(Phần mềm và hướng dẫn chạy được app), m.n làm theo là được nha.👏

            - Trong file Info.plist m.n thêm cho TíT đoạn code để cấu hình cho phép khởi tạo ZaloPay từ app👇👇(zp-redirect-1412 thì số 1412 có thể setup lại tuỳ nha không bắt buộc)

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wallet</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>zp-redirect-1412</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>zalo</string>
<string>zalopay</string>
<string>zalopay.guide.v2</string>
</array>
   

          - Tạo 2 file như này cho TíT đối với ios nha 👌👌

              💥    ZaloPayBridge.h

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

const NSInteger PAYMENTSUCCESS = 1;
const NSInteger PAYMENTFAILED = -1;
const NSInteger PAYMENTCANCELED = 4;

@interface ZaloPayBridge : RCTEventEmitter<RCTBridgeModule>

@end

              💥    ZaloPayBridge.m

#import "ZaloPayBridge.h"
#import <zpdk/zpdk.h>

@interface ZaloPayBridge () <ZPPaymentDelegate>

@end

@implementation ZaloPayBridge

- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}

RCT_EXPORT_MODULE(ZaloPayBridge);

- (NSArray<NSString *> *)supportedEvents
{
return @[@"EventPayZalo"];
}

RCT_EXPORT_METHOD(payOrder:
(NSString *)zpTransToken) {
[ZaloPaySDK sharedInstance].paymentDelegate = self;
[[ZaloPaySDK sharedInstance] payOrder:zpTransToken];
}

RCT_EXPORT_METHOD(installApp) {
[[ZaloPaySDK sharedInstance] navigateToZaloStore]; // Use for Production
//for the sandbox
// NSURL* url = [[NSURL alloc] initWithString:@"https://stcstg.zalopay.com.vn/ps_res/ios/enterprise/sandboxmer/4.22.0/install.html"];
// [[UIApplication sharedApplication] openURL: url];
}

- (void)paymentDidSucceeded:(NSString *)transactionId
zpTranstoken:(NSString *)zpTranstoken
appTransId:(NSString *)appTransId {
[self sendEventWithName:@"EventPayZalo" body:@{@"returnCode": [NSString stringWithFormat:@"%ld", (long)1], @"transactionId":transactionId ? transactionId : @"", @"zpTranstoken": zpTranstoken ? zpTranstoken : @"", @"appTransId": appTransId ? appTransId : @""}];
}

- (void)paymentDidCanceled:(NSString *)zpTranstoken
appTransId:(NSString *)appTransId {
[self sendEventWithName:@"EventPayZalo" body:@{@"returnCode": [NSString stringWithFormat:@"%ld", (long)-4], @"zpTranstoken":zpTranstoken ? zpTranstoken : @"", @"appTransId": appTransId ? appTransId : @""}];
}

- (void)paymentDidError:(ZPPaymentErrorCode)errorCode
zpTranstoken:(NSString *)zpTranstoken
appTransId:(NSString *)appTransId {
// Handle Error
if (errorCode == ZPPaymentErrorCode_AppNotInstall) {
[[ZaloPaySDK sharedInstance] navigateToZaloStore];
return;
}
[self sendEventWithName:@"EventPayZalo" body:@{@"returnCode": [NSString stringWithFormat:@"%ld", (long)errorCode], @"zpTranstoken":zpTranstoken ? zpTranstoken : @"", @"appTransId":appTransId ? appTransId : @""}];
}
@end

         - Sau đó ở khởi tạo zpdk và xử lý trao đổi dữ liệu với ZaloPay

#import <zpdk/zpdk.h>

//Khởi tạo ZPDK
[[ZaloPaySDK sharedInstance] initWithAppId:1412 uriScheme:@"wallet://app" environment: ZPZPIEnvironment_Production];
// =>> Bên dưới [self.window makeKeyAndVisible]


//gọi tới ZPDK để xử lý trao đổi dữ liệu giữa ZaloPay với app
- (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];
}

          - Sau đó thêm zpdk vào ios nha




    ✌ Android

            - Trong file zip zalopaydk mà mn đã tải ở trên, có folder android chứa file .aar

            - Đầu tiên m.n hãy tạo folder android/zpdk-release. Trong folder này chứa file .aar và 1 file nữa là build.gradle có nội dung như sau👇👇

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

            - Tiếp theo, cần include zpdk vào file android/settings

include ':zpdk-release'

                và file android/app/build.gradle ở phần dependencies

implementation project(':zpdk-release')

            - Tiếp theo tạo module zalopay (😈lưu ý đổi lại thông tin cho đúng với project của m.n nha😈). Trong folder java/com/tên-project tạo mới folder zalopaymodule, trong folder này chứa 2 file:

            💥 ZaloPayBridge.java

package com.walletmyapp.zalopaymodule; // <= sửa lại tên

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ZaloPayBridge implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();

modules.add(new ZPModule(reactContext));

return modules;
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

            💥 ZPModule.java

package com.walletmyapp.zalopaymodule; // <= sửa lại tên

import android.app.Activity;
import android.content.Intent;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import vn.zalopay.sdk.listeners.PayOrderListener;
import vn.zalopay.sdk.ZaloPayError;
import vn.zalopay.sdk.ZaloPaySDK;

public class ZPModule extends ReactContextBaseJavaModule {
private ReactApplicationContext mReactContext;
final String PAYMENTSUCCESS = "1";
final String PAYMENTFAILED = "-1";
final String PAYMENTCANCELED = "4";

PayOrderListener listener = new PayOrderListener() {
@Override
public void onPaymentSucceeded(String transactionId, String transToken, String appTransID) {
// Handle Success
WritableMap params = Arguments.createMap();
params.putString("transactionId", transactionId);
params.putString("transToken", transToken);
params.putString("appTransID", appTransID);
params.putString("returnCode", PAYMENTSUCCESS);
sendEvent(mReactContext, "EventPayZalo", params);
}

@Override
public void onPaymentCanceled(String transToken, String appTransID) {
// Handle Cancel
WritableMap params = Arguments.createMap();
params.putString("returnCode", PAYMENTCANCELED);
params.putString("zpTranstoken", transToken);
params.putString("appTransID", appTransID);
sendEvent(mReactContext, "EventPayZalo", params);
}

@Override
public void onPaymentError(ZaloPayError zaloPayError, String transToken, String appTransID) {
// Handle Error
WritableMap params = Arguments.createMap();
params.putString("returnCode", PAYMENTFAILED);
params.putString("zpTranstoken", transToken);
params.putString("appTransID", appTransID);
sendEvent(mReactContext, "EventPayZalo", params);
}
};

BaseActivityEventListener activityEventListener = new BaseActivityEventListener(){
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
};

public ZPModule(ReactApplicationContext reactContext) {
super(reactContext);
mReactContext = reactContext;
reactContext.addActivityEventListener(activityEventListener);
}

@Override
public String getName() {
return "ZaloPayBridge";
}

@ReactMethod
public void payOrder(String zpTransToken) {
System.out.println(zpTransToken);
Activity currentActivity = getCurrentActivity();
ZaloPaySDK.getInstance().payOrder(currentActivity, zpTransToken, "wallet://app", listener);
}

@ReactMethod
public void installApp() {
ZaloPaySDK.getInstance().navigateToZaloOnStore(mReactContext);
}
private void sendEvent(ReactContext reactContext, String eventName, WritableMap params) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}

            - Tiếp theo là import module vừa tạo vào MainApplication.java

import com.walletmyapp.zalopaymodule.ZaloPayBridge; // import bridge zalopay

import vn.zalopay.sdk.Environment;
import vn.zalopay.sdk.ZaloPaySDK;

                Thêm packages vào hàm getPackages

packages.add(new ZaloPayBridge()); // package zalopay

                Khởi tạo môi trường ở chế độ sanbox (trong hàm onCreate nha)

ZaloPaySDK.init(1412, Environment.SANDBOX);

            - Tạo intent ở file MainActivity.java

import android.content.Intent;
import vn.zalopay.sdk.ZaloPaySDK;

                Tạo NewIntent
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
ZaloPaySDK.getInstance().onResult(intent);
}

  • Sử dụng 

const { ZaloPayBridge } = NativeModules;
    
const payZaloBridgeEmitter = new NativeEventEmitter(ZaloPayBridge);

const payOrder = (token) => { // token từ BE trả về nha
const payZP = NativeModules.ZaloPayBridge;
payZP.payOrder(token);
};
useEffect(() => {
const subscription = payZaloBridgeEmitter.addListener(
'EventPayZalo',
(data) => {
if (data.returnCode == 1) {
// handle action
} else if (data.returnCode == -1) {
ZaloPayBridge.installApp();
Alert.alert('Pay errror! ' + data.returnCode);
}
},
);
return () => subscription?.remove();
}, []);
           
            - Đối với ioss thì có thể dùng luôn ZaloPayBridge, còn android thì m.n hãy tạo 1 cái event emitter để dùng nha (có thể log ZaloPayBridge để xem các hàm)

            - Để thanh toán thì m.n xem 2 hàm ở phần "Gọi hàm thanh toán" ở phần docs của https://docs.zalopay.vn/v1/docs/apptoapp/api.html

    Vậy là TíT đã nói xong về phần tích hợp thanh toán zalopay ở chế độ sanbox, nếu có gì thắc mắc hay chưa làm được thì mn liên hệ vơi Face của TíT nha. Bài hơi dài cảm ơn m,n đã đọc và ủng hộ 💜💜💜

Đăng nhận xét

Mới hơn Cũ hơn