React-native 0.6版本集成支付寶-Alipay爬坑

前言

項目裏須要作支付, 在github看到的插件多多少少都遇到了坑, 實在是爬不出來。參考了支付寶官方文檔 還有別的一些大佬的文章,作個記錄java

安卓集成

1.在app目錄下新建libs目錄,將sdk 包放在應用工程的 libs 目錄下

image.png

2.在主項目的 build.gradle 中,添加下面的內容,將 libs 目錄做爲依賴倉庫:
allprojects {
    repositories {

        // 添加下面的內容
        flatDir {
            dirs 'libs'
        }

        // ... jcenter() 等其餘倉庫
    }
}

image.png

3.App Module 的 build.gradle中(項目的app 目錄下),添加下面的內容,將支付寶 SDK 做爲項目依賴:
//官方用的是compile,二者均可以 用implementation更好
 implementation (name: 'alipaySdk-15.6.5-20190718211159-noUtdid', ext: 'aar')

image.png

4.支付寶 SDK 須要使用下面這些權限,在AndroidManifest.xml下添加:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CAMERA"/>

image.png

以上sdk的配置基本完成 下面就須要和原生作橋接(下面代碼基本是copy另外一位大佬的,膜拜)react

5.android/app/src/main/java/com.xx下建立alipay,以下圖

image.png
6.建立AlipayModule.java,代碼以下:
(注意: 第一行的包名必定要寫對)android

package com.xxxx.alipay;

import com.alipay.sdk.app.PayTask;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import java.util.Map;

public class AlipayModule extends ReactContextBaseJavaModule {

    public AlipayModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

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

    @ReactMethod
    public void pay(final String orderInfo, final Promise promise) {
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                WritableMap map = Arguments.createMap();
                PayTask alipay = new PayTask(getCurrentActivity());
                Map<String, String> result = alipay.payV2(orderInfo,true);
                for (Map.Entry<String, String> entry: result.entrySet())
                    map.putString(entry.getKey(), entry.getValue());
                promise.resolve(map);
            }
        };
        // 必須異步調用
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }

}

7.建立AlipayPackage.java,代碼以下:(仍是要注意包名)ios

package com.xxxx.alipay;

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 AlipayPackage implements ReactPackage {

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

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new AlipayModule(reactContext));
        return modules;
    }

}

8.在com.xxxx下的MainApplication中註冊模塊:
(注意:這裏和原文有點區別 0.6版本的添加包與舊版本有些區別)git

@Override
    protected List<ReactPackage> getPackages() {
      @SuppressWarnings("UnnecessaryLocalVariable")
      List<ReactPackage> packages = new PackageList(this).getPackages();
      // Packages that cannot be autolinked yet can be added manually here, for example:
       packages.add(new AlipayPackage());
      return packages;
    }

image.png

ios集成

1.sdk安裝
(1).rn 0.6以上的版本
1.經過 CocoaPods 添加
  在項目路徑/ios/podfile 裏添加以下代碼
  pod 'AlipaySDK-iOS'
  添加完成後執行 pod install

image.png

(2)手動導入
由於我是用的新版本因此沒有手動導入,須要的老哥參考下文末連接或者支付寶開發文檔
2.設置URL Schemes
在Xcode中打開項目,設置項目屬性中的URL Schemes爲你支付寶開放平臺對此App設置的惟一標識。如圖標紅位置所示:

image.png

3.在項目目錄下建立Group Alipay,並建立RCTAlipay模塊,以下圖所示:

image.png

4.編寫RCTAlipay.h代碼以下:
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
#import <AlipaySDK/AlipaySDK.h>

@interface RCTAlipay : NSObject<RCTBridgeModule>

+(void) handleCallback:(NSURL *)url;

@end
5.編寫RCTAlipay.m代碼以下:
#import "RCTAlipay.h"

static RCTPromiseResolveBlock _resolve;
static RCTPromiseRejectBlock _reject;

@implementation RCTAlipay

RCT_EXPORT_MODULE();

RCT_REMAP_METHOD(pay, payInfo:(NSString *)payInfo resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
  NSArray *urls = [[NSBundle mainBundle] infoDictionary][@"CFBundleURLTypes"];
  NSMutableString *appScheme = [NSMutableString string];
  BOOL multiUrls = [urls count] > 1;
  for (NSDictionary *url in urls) {
    NSArray *schemes = url[@"CFBundleURLSchemes"];
    if (!multiUrls ||
        (multiUrls && [@"alipay" isEqualToString:url[@"CFBundleURLName"]])) {
      [appScheme appendString:schemes[0]];
      break;
    }
  }
  
  if ([appScheme isEqualToString:@""]) {
    NSString *error = @"scheme cannot be empty";
    reject(@"10000", error, [NSError errorWithDomain:error code:10000 userInfo:NULL]);
    return;
  }
  
  _resolve = resolve;
  _reject = reject;
  
  
  [[AlipaySDK defaultService] payOrder:payInfo fromScheme:appScheme callback:^(NSDictionary *resultDic) {
    [RCTAlipay handleResult:resultDic];
  }];
}

+(void) handleResult:(NSDictionary *)resultDic
{
  NSString *status = resultDic[@"resultStatus"];
  if ([status integerValue] >= 8000) {
    _resolve(@[resultDic]);
  } else {
    _reject(status, resultDic[@"memo"], [NSError errorWithDomain:resultDic[@"memo"] code:[status integerValue] userInfo:NULL]);
  }
}

+(void) handleCallback:(NSURL *)url
{
  //若是極簡開發包不可用,會跳轉支付寶錢包進行支付,須要將支付寶錢包的支付結果回傳給開發包
  if ([url.host isEqualToString:@"safepay"]) {
    [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
      //【因爲在跳轉支付寶客戶端支付的過程當中,商戶app在後臺極可能被系統kill了,因此pay接口的callback就會失效,請商戶對standbyCallback返回的回調結果進行處理,就是在這個方法裏面處理跟callback同樣的邏輯】
      [self handleResult:resultDic];
    }];
  }
  if ([url.host isEqualToString:@"platformapi"]){//支付寶錢包快登受權返回authCode
    
    [[AlipaySDK defaultService] processAuthResult:url standbyCallback:^(NSDictionary *resultDic) {
      //【因爲在跳轉支付寶客戶端支付的過程當中,商戶app在後臺極可能被系統kill了,因此pay接口的callback就會失效,請商戶對standbyCallback返回的回調結果進行處理,就是在這個方法裏面處理跟callback同樣的邏輯】
      [self handleResult:resultDic];
    }];
  }
}

@end

注意:
這裏是經過配置文件來獲取scheme,若是獲取到appScheme的值爲空的話,就寫死在代碼裏,簡單粗暴
image.pnggithub

6 網頁支付返回APP
【重要】此時iOS的調起支付寶網頁支付(即未安裝支付寶App)在RN中能夠實現支付完成返回App進行相關操做,可是調起支付寶App支付完成後會發現相關支付完成的操做失效,因此要在`Appdelegate.m`中導入`RCTAlipay.h`進行相關回調:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary*)options {
  //若是極簡開發包不可用,會跳轉支付寶錢包進行支付,須要將支付寶錢包的支付結果回傳給開發包
  if ([url.host isEqualToString:@"safepay"]) {
    [RCTAlipay handleCallback:url];
    return YES;
  }
  //此處是微信支付 XXXXXX:微信urlsheme
  if ([url.scheme isEqualToString:@"XXXXXX"])
  {
    return  [WXApi handleOpenURL:url delegate:(id<WXApiDelegate>)self];
  }
  
  return  YES;
}

注意:微信支付完成也是要使用改方法, 得在裏面判斷一下react-native

react-native調用

1.編寫Alipay.js工具類
import { NativeModules } from 'react-native';
export default NativeModules.Alipay;
2.在支付頁面調用Alipay發起支付寶支付:
import Alipay from './Alipay'
 async aliPayAction(payStr){
       //payStr爲從後臺獲取的支付字符串
        Alipay.pay(payStr).then((data) =>{
           let resultDic = {};
/*筆者iOS端和安卓端返回的支付回調結果數據不一致,可能和支付寶sdk版本有關,
讀者可自行根據返回數據進行相關處理,iOS(RCTAlipay.m)和安卓(AlipayModule)
可自行選擇須要resolve回調判斷處理的數據,如只返回resultStatus*/
            if (Platform.OS === 'ios'){
                resultDic = data[0];
            } else {
                resultDic = data;
            }
            if (resultDic.resultStatus == '9000'){
                //支付成功
            }else {
                //支付失敗
            }
        }).catch((err) => {
            console.log('err='+err);
            this.refs.toast.show('支付失敗');
        });
    }

到這裏支付寶就集成完了,剛開始一頭霧水,看了下rn的官方文檔,支付寶的官方文檔,還有其餘大佬的文章。終於拼湊完成了。作個記錄
Happy Hackingapi

參考1:支付寶集成官方文檔
參考2:react-native集成支付寶支付)promise

相關文章
相關標籤/搜索