4.2app.md 30 KB

预支付接口说明

预支付 根据account、type参数找到对应配置,并根据第三方支付平台进行相应的接口调用以及数据处理后,返回给app端直接可用数据。

微信接入

交互图

接入配置

param 说明 备注
appid 应用id 微信开放平台中获取
mch_id 商户号 微信商户平台中获取
key 支付key 微信商户平台中获取
API 调用文件 API 调用安全文件 用于退款,微信商户平台中获取

将以上信息以邮件提交到 liyi@cnlive.com ,以视讯云登录用户的邮箱发送。

支付宝接入

交互图

接入配置

param 说明 备注
partner_id 商户号
seller_email 支付宝用户邮箱
RAS_private RAS 私钥 使用支付宝官方工具生成
RAS_public RAS 公钥 支付宝后台获取

将以上信息以邮件提交到 liyi@cnlive.com ,以视讯云登录用户的邮箱发送。

demo IOS

1) 生成支付云预支付订单所需参数sign,将预支付订单的参数列表中必传参数(sign参数除外)和非必传参数(根据业务需求自行判断需传哪些参数)拼接成参数字典

NSDictionary *parameter = @{ @"account":account, //和支付云对接app支付对应的命名一致 如: @"testDemoAlipay"
                            @"type":type,//微信@”1” 支付宝@”3”
                             @"appId":AppId, //AppID
                            @"out_trade_no":outTradeNo, //唯一订单号
                            @"total_fee":totalFee, //订单总价 
@"notify_url":notifyUrl, //回调地址(用户付款通知业务系统接收地址)
                            @"body":body, //订单信息
@"user_id":userId, //用户id
                            @"attach.value":descript, //商品描述
                            @"attach.sid":userId, //用户id
                            @"attach.orderId":outTradeNo//唯一订单号
                        };
//将此参数字典parameter按照ASCII码值从小到大排序,并拼接AppKey如: d8da4312037a6aaff83dc8809c023fc9b06847a3f130e5得到string
//注意:所有参数的值均不能为空,若参数值为空则参数字典去除此键值对.

NSString *string = [NSString stringWithFormat:@"%@&key=%@", [self signvalue:parameter], AppKey];

- (NSString *)signvalue:(NSDictionary*)parameter
{
    //对所有传入参数按照字段名的 ASCII 码从小到大排序
    NSArray *keyArr=[parameter allKeys];
    NSArray *arr = [keyArr sortedArrayUsingSelector:@selector(compare:)];
    NSMutableString *string1 = [[NSMutableString alloc]init];
    for (int i=0; i<arr.count; i++) {  
        NSString *parameterString = parameter[[arr objectAtIndex:i]];
        if (parameterString.length > 0) {
            [string1 appendString:[NSString stringWithFormat:@"%@=%@&",[arr objectAtIndex:i],parameter[[arr objectAtIndex:i]]]];
        }
    }
    if (string1.length > 0) {
        [string1 deleteCharactersInRange:NSMakeRange(string1.length-1, 1)];
    }
    return string1;
}

2)将步骤1中得到的string进行SHA1加密并全部大写即得到sign签名字符串,需要导入文件

#import<CommonCrypto/CommonDigest.h>

NSString *signString = [[self sha1:string] uppercaseString];

- (NSString*)sha1:(NSString *)string
{
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t digest[CC_SHA1_DIGEST_LENGTH]; 
    CC_SHA1(data.bytes, (int)data.length, digest); 
    NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];
    while ([[output substringToIndex:1] isEqualToString:@"0"]) {
        output = [[NSMutableString alloc] initWithString:[output substringFromIndex:1]];
    }
    return output;
}

sign样例: 7656A9FEFB5D8A08AB41723A843FC3C0B3818A0A

3)请求支付云预支付订单接口 将预支付订单的参数列表中必传参数(包括生成的sign)和非必传参数(根据业务需求自行判断需传哪些参数)拼接成参数字典,请求预支付订单接口https://api.cnlive.com/open/api2/unifypay/prepay

  • 1 支付宝支付
    将支付云返回数据解析,需导入头文件#import <AlipaySDK/AlipaySDK.h>
  • 2 微信支付
    将支付云返回数据解析,需导入头文件#import "WXApi.h"
NSDictionary *parameters = @{@"account":account, //和支付云对接app支付对应的命名一致 如: @"testDemoAlipay"
                             @"type":type,//微信@”1” 支付宝@”3”
                             @"appId":AppId, //AppID
                             @"out_trade_no":outTradeNo, //唯一订单号
                             @"total_fee":totalFee, //订单总价
                             @"notify_url":notifyUrl, //回调地址(用户付款通知业务系统接收地址)
                             @"body":body, //订单信息
@"user_id":userId, //用户id
                             @"attach.sid":userId, //用户id
@"attach.orderId":outTradeNo, //唯一订单号
@"attach.value":descript,//商品描述
                        @"sign":signString//RSA加密签名串
                         };

__block NSString *signedString = @"";
NSString *prepay = @"https://api.cnlive.com/open/api2/unifypay/prepay";
[[AFHTTPRequestOperationManager manager] POST:prepay parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    if ([[NSString stringWithFormat:@"%@", responseObject[@"errorCode"]] isEqualToString:@"0"])
{    
       if ([type isEqualToString:@"3"]) {//支付宝支付    
         signedString=responseObject[@"data"][@"alipay_app"];
         NSString *orderString = nil;
         NSString *appScheme = @"testDemo您的app包名";
         if (signedString != nil) {
            orderString = signedString;
         //支付宝支付结果回调
         [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
            NSString *resultStr = [resultDic objectForKey:@"resultStatus"];
         if ([resultStr isEqualToString:@"9000"]) {
           //PaySuccess支付成功
         }
         else if ([resultStr isEqualToString:@"6001"]) {
         //UserCancel用户取消
         }
         else {//PayFailure支付失败
         }
    }];
  }
}
if ([type isEqualToString:@"1"]) {//微信支付
    NSDictionary *wxMessage = responseObject[@"data"][@"wx_app"];
                        //调起微信支付
          PayReq* req             = [[PayReq alloc] init];
          req.partnerId           = [wxMessage objectForKey:@"partnerid"];
          req.prepayId            = [wxMessage objectForKey:@"prepayid"];
          req.nonceStr            = [wxMessage objectForKey:@"noncestr"];
          req.timeStamp           = [[wxMessage objectForKey:@"timestamp"] intValue];
          req.package             = [wxMessage objectForKey:@"package"];
          req.sign                = [wxMessage objectForKey:@"sign"];
    [WXApi sendReq:req];

}
    }
      } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];

4) AppDelegate.m中添加支付结果客户端回调判断

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
    if ([url.host isEqualToString:@"safepay"]) {//支付宝支付结果回调
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"result = %@",resultDic);
            NSString *resultStr = [resultDic objectForKey:@"resultStatus"];
if ([resultStr isEqualToString:@"9000"]) {
//PaySuccess
            }
else if ([resultStr isEqualToString:@"6001"])               
{//UserCancel
            }
else {
//PayFailure
            }
        }];
        return YES;
}
    else if ([url.host isEqualToString:@"pay"])//微信支付结果回调
    {
        [WXApi handleOpenURL:url delegate:[WXApiManager sharedManager]];
    }
    return YES;
}
注: 其中WXApiManager为自定义微信管理类,代码如下:
WXApiManager.h代码
#import <Foundation/Foundation.h>

@interface WXApiManager : NSObject<WXApiDelegate>

+ (instancetype)sharedManager;

@end
WXApiManager.m代码
#import "WXApiManager.h"

#define onlyCode @"testDemo您的app包名"
@implementation WXApiManager

#pragma mark - 单例

+(instancetype)sharedManager {
    static dispatch_once_t onceToken;
    static WXApiManager *instance;
    dispatch_once(&onceToken, ^{
        instance = [[WXApiManager alloc] init];
    });
    return instance;
}

#pragma mark - WXApiDelegate

- (void)onResp:(BaseResp *)resp
{
    if([resp isKindOfClass:[PayResp class]]){

        //支付返回结果,实际支付结果需要去微信服务器端查询
        NSString *strMsg;

        switch (resp.errCode) {
            case WXSuccess:
                strMsg = @"支付结果:成功!";
                NSLog(@"支付成功-PaySuccess,retcode = %d", resp.errCode);
                break;
            case WXErrCodeUserCancel:
            {
                strMsg = @"用户取消!";
                NSLog(@"用户取消-userCancel,retcode = %d", resp.errCode);
            }
                break;
            default:
                strMsg = [NSString stringWithFormat:@"支付结果:失败!retcode = %d, retstr = %@", resp.errCode,resp.errStr];
                NSLog(@"错误,retcode = %d, retstr = %@", resp.errCode,resp.errStr);
                break;
        }
    }
}

@end

demo Android

1)根据预支付 接口生成map 参数集合
2) 对所有传入参数(含系统参数和接口参数)按照字段名的 ASCII 码从小到大排序

/**
     * Map key 排序
     *
     * @param map
     * @return
     */
    private static Map<String, String> order(Map<String, String> map) {
        HashMap<String, String> tempMap = new LinkedHashMap<>();
        List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet());

        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });

        for (int i = 0; i < infoIds.size(); i++) {
            Map.Entry<String, String> item = infoIds.get(i);
            tempMap.put(item.getKey(), item.getValue());
        }
        return tempMap;
    }

3)参数的串联 使用 URL 键值 对的格式。 (即 key1=value1&key2=value2…)拼接成字符串 string1, 注意:值为空的参数不参与签名,所有请求参数值都需要进行URL编码

 private static String mapJoin(Map<String, String> map, boolean keyLower, boolean valueUrlencode) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String key : map.keySet()) {
            if (map.get(key) != null && !"".equals(map.get(key))) {
                try {
                    stringBuilder.append(key)
                            .append("=")
                            .append(valueUrlencode ? URLEncoder.encode(map.get(key), "utf-8").replace("+", "%20") : map.get(key))
                            .append("&");
                } catch (UnsupportedEncodingException e) {
                    LOGE("PAY:" + e.getMessage(), e);
                }
            }
        }
        if (stringBuilder.length() > 0) {
            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
        }
        LOGD("PAY:" + stringBuilder.toString());
        return stringBuilder.toString();
    }

4)拼接key=app_key,进行sha1运算 在 string1 最 后 拼 接 上 key=app_key得 到 stringSignTemp 字 符 串 , 并 对 stringSignTemp 进行 sha1 运算,再将得到的字符串所有字符转换为大写, 得到 sign 值 signValue


SHA1.SHA1Digest(mapJoin(map, true, false)
                .concat("&key=")
                .concat(sp_key))
                .toUpperCase(Locale.getDefault()); //备注(sha1运算代码不做详述附上下面代码)。

SHA1代码

public class SHA1 {
    private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe,
            0x10325476, 0xc3d2e1f0};

    // 摘要数据存储数组
    private int[] digestInt = new int[5];

    // 计算过程中的临时数据存储数组
    private int[] tmpData = new int[80];

    /**
     * 将字节转换为十六进制字符串
     *
     * @param ib
     * @return
     */
    private static String byteToHexString(byte ib) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F'};
        char[] ob = new char[2];
        ob[0] = Digit[(ib >>> 4) & 0X0F];
        ob[1] = Digit[ib & 0X0F];
        String s = new String(ob);
        return s;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param bytearray
     * @return
     */
    private static String byteArrayToHexString(byte[] bytearray) {
        String strDigest = "";
        for (int i = 0; i < bytearray.length; i++) {
            strDigest += byteToHexString(bytearray[i]);
        }
        return strDigest;
    }

    /**
     * @param text
     * @return
     */
    public static String SHA1Digest(String text) {
        String pwd = "";
        try {
            MessageDigest md = MessageDigest.getInstance("SHA1");
            md.update(text.getBytes());
            pwd = new BigInteger(1, md.digest()).toString(16);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return pwd;
    }

    /**
     * 计算sha-1摘要
     *
     * @param bytedata
     * @return
     */
    private int process_input_bytes(byte[] bytedata) {
        // 初试化常量
        System.arraycopy(abcde, 0, digestInt, 0, abcde.length);
        // 格式化输入字节数组,补10及长度数据
        byte[] newbyte = byteArrayFormatData(bytedata);
        // 获取数据摘要计算的数据单元个数
        int MCount = newbyte.length / 64;
        // 循环对每个数据单元进行摘要计算
        for (int pos = 0; pos < MCount; pos++) {
            // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中
            for (int j = 0; j < 16; j++) {
                tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4));
            }
            // 摘要计算函数
            encrypt();
        }
        return 20;
    }

    /**
     * 格式化输入字节数组格式
     *
     * @param bytedata
     * @return
     */
    private byte[] byteArrayFormatData(byte[] bytedata) {
        // 补0数量
        int zeros = 0;
        // 补位后总位数
        int size = 0;
        // 原始数据长度
        int n = bytedata.length;
        // 模64后的剩余位数
        int m = n % 64;
        // 计算添加0的个数以及添加10后的总长度
        if (m < 56) {
            zeros = 55 - m;
            size = n - m + 64;
        } else if (m == 56) {
            zeros = 63;
            size = n + 8 + 64;
        } else {
            zeros = 63 - m + 56;
            size = (n + 64) - m + 64;
        }
        // 补位后生成的新数组内容
        byte[] newbyte = new byte[size];
        // 复制数组的前面部分
        System.arraycopy(bytedata, 0, newbyte, 0, n);
        // 获得数组Append数据元素的位置
        int l = n;
        // 补1操作
        newbyte[l++] = (byte) 0x80;
        // 补0操作
        for (int i = 0; i < zeros; i++) {
            newbyte[l++] = (byte) 0x00;
        }
        // 计算数据长度,补数据长度位共8字节,长整型
        long N = (long) n * 8;
        byte h8 = (byte) (N & 0xFF);
        byte h7 = (byte) ((N >> 8) & 0xFF);
        byte h6 = (byte) ((N >> 16) & 0xFF);
        byte h5 = (byte) ((N >> 24) & 0xFF);
        byte h4 = (byte) ((N >> 32) & 0xFF);
        byte h3 = (byte) ((N >> 40) & 0xFF);
        byte h2 = (byte) ((N >> 48) & 0xFF);
        byte h1 = (byte) (N >> 56);
        newbyte[l++] = h1;
        newbyte[l++] = h2;
        newbyte[l++] = h3;
        newbyte[l++] = h4;
        newbyte[l++] = h5;
        newbyte[l++] = h6;
        newbyte[l++] = h7;
        newbyte[l++] = h8;
        return newbyte;
    }

    private int f1(int x, int y, int z) {
        return (x & y) | (~x & z);
    }

    private int f2(int x, int y, int z) {
        return x ^ y ^ z;
    }

    private int f3(int x, int y, int z) {
        return (x & y) | (x & z) | (y & z);
    }

    //

    private int f4(int x, int y) {
        return (x << y) | x >>> (32 - y);
    }

    /**
     * 单元摘要计算函数
     */
    private void encrypt() {
        for (int i = 16; i <= 79; i++) {
            tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14]
                    ^ tmpData[i - 16], 1);
        }
        int[] tmpabcde = new int[5];
        for (int i1 = 0; i1 < tmpabcde.length; i1++) {
            tmpabcde[i1] = digestInt[i1];
        }
        for (int j = 0; j <= 19; j++) {
            int tmp = f4(tmpabcde[0], 5)
                    + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[j] + 0x5a827999;
            tmpabcde[4] = tmpabcde[3];
            tmpabcde[3] = tmpabcde[2];
            tmpabcde[2] = f4(tmpabcde[1], 30);
            tmpabcde[1] = tmpabcde[0];
            tmpabcde[0] = tmp;
        }
        for (int k = 20; k <= 39; k++) {
            int tmp = f4(tmpabcde[0], 5)
                    + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[k] + 0x6ed9eba1;
            tmpabcde[4] = tmpabcde[3];
            tmpabcde[3] = tmpabcde[2];
            tmpabcde[2] = f4(tmpabcde[1], 30);
            tmpabcde[1] = tmpabcde[0];
            tmpabcde[0] = tmp;
        }
        for (int l = 40; l <= 59; l++) {
            int tmp = f4(tmpabcde[0], 5)
                    + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[l] + 0x8f1bbcdc;
            tmpabcde[4] = tmpabcde[3];
            tmpabcde[3] = tmpabcde[2];
            tmpabcde[2] = f4(tmpabcde[1], 30);
            tmpabcde[1] = tmpabcde[0];
            tmpabcde[0] = tmp;
        }
        for (int m = 60; m <= 79; m++) {
            int tmp = f4(tmpabcde[0], 5)
                    + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4]
                    + tmpData[m] + 0xca62c1d6;
            tmpabcde[4] = tmpabcde[3];
            tmpabcde[3] = tmpabcde[2];
            tmpabcde[2] = f4(tmpabcde[1], 30);
            tmpabcde[1] = tmpabcde[0];
            tmpabcde[0] = tmp;
        }
        for (int i2 = 0; i2 < tmpabcde.length; i2++) {
            digestInt[i2] = digestInt[i2] + tmpabcde[i2];
        }
        for (int n = 0; n < tmpData.length; n++) {
            tmpData[n] = 0;
        }
    }

    /**
     * 4字节数组转换为整数
     *
     * @param bytedata
     * @param i
     * @return
     */
    private int byteArrayToInt(byte[] bytedata, int i) {
        return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16)
                | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff);
    }

    /**
     * 整数转换为4字节数组
     *
     * @param intValue
     * @param byteData
     * @param i
     */
    private void intToByteArray(int intValue, byte[] byteData, int i) {
        byteData[i] = (byte) (intValue >>> 24);
        byteData[i + 1] = (byte) (intValue >>> 16);
        byteData[i + 2] = (byte) (intValue >>> 8);
        byteData[i + 3] = (byte) intValue;
    }

    /**
     * 计算sha-1摘要,返回相应的字节数组
     *
     * @param byteData
     * @return
     */
    public byte[] getDigestOfBytes(byte[] byteData) {
        process_input_bytes(byteData);
        byte[] digest = new byte[20];
        for (int i = 0; i < digestInt.length; i++) {
            intToByteArray(digestInt[i], digest, i * 4);
        }
        return digest;
    }

    /**
     * 计算sha-1摘要,返回相应的十六进制字符串
     *
     * @param byteData
     * @return
     */
    public String getDigestOfString(byte[] byteData) {
        return byteArrayToHexString(getDigestOfBytes(byteData));
    }

    /**
     * @param data
     * @return
     */
    public String Digest(String data) {
        return this.getDigestOfString(data.getBytes());
    }

    /**
     * @param data
     * @return
     */
    public String Digest(String data, String encode) {
        try {
            return this.getDigestOfString(data.getBytes(encode));
        } catch (UnsupportedEncodingException e) {
            return this.Digest(data);
        }
    }
}

5)将sign=signValue拼接到map 参数
将 sign=signValue拼接到string2后面得到最终的 参数 字符串 map.put("sign", getSign(map, TOKEN_KEY));

6)预支付调用

//订单生成:
public static String getOrderId(String frmId) {
        StringBuilder sb = new StringBuilder();
        String timestamp = String.valueOf(System.currentTimeMillis());
        sb.append(SPID).append(frmId)
                .append(android.text.format.DateFormat.format("yyyyMMdd", new Date()).toString())
                .append(timestamp.substring(timestamp.length() - 8))
                .append((int) (Math.random() * 999));
        LOGD("order id:" + sb.toString());
        return sb.toString();
    }
//Map生成
 public static Map<String, String> getPayVideoOnceToken(String account,
                                                           String sid,
                                                           String frmId,
                                                           ProductInfo info,
                                                           String type,
                                                           String version
                                                           ) {

        String out_trade_no = getOrderId(frmId);//上一步生成的订单
        Map<String, String> map = new LinkedHashMap<>();
        if (!TextUtils.isEmpty(account))
            map.put("account", account);

        map.put("attach.plat", "a");                            //附加字段
        map.put("attach.prdId", info.getPrdId());           //附加字段
        map.put("attach.version",version );           //附加字段
        map.put("attach.sid", String.valueOf(sid));             //附加字段
        map.put("attach.spId", USER_SPID);     //附加字段
        map.put("body", info.getTitle());                 //订单信息
        map.put("frmId", frmId);                                //渠道
        map.put("notify_url", "http://apps.pay.cnlive.com/upappnotify/notify/orderForVideo");    //回调通知URL
        map.put("out_trade_no", out_trade_no);                  //业务系统中的 订单号
        map.put("sp_id", SPID);
        if (BuildConfig.DEBUG){
            map.put("total_fee", "1");            //订单总价
        } else {
            map.put("total_fee", "" + info.getRmb());            //订单总价
        }
        map.put("type", type);            //渠道
        map.put("sign", getSign(map, TOKEN_KEY));//签名上面生成的sign

        return map;
}

预支付:
网络请求代码如下:(各团队网络请求封装不一样这里只显示最简单网络请求相应的第三方库如下: (compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2')


 RestAdapter restAdapter = new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setEndpoint("http://unifypay.cnlive.com")
                .setClient(new OkClient(new OkHttpClient()))
                .build();
        restAdapter.create(VipPayService.class).newWay2PayVideo(map, new Callback<UnifyPayMessage>() {
            @Override
            public void success(UnifyPayMessage unifyPayMessage, Response response) {
                Logger.e(response.getUrl());
                Logger.e(unifyPayMessage.toString());
                if (unifyPayMessage != null && unifyPayMessage.getStatus().equals("0")) {
                    LOGD("=====================aplipay =====================");

                    startPay(unifyPayMessage);
                } else {
                    LOGE("支付错误:" + unifyPayMessage.getMsg() + ", url:" + response.getUrl());
                }
            }

            @Override
            public void failure(RetrofitError error) {
                LOGE("支付错误:" + error.getUrl() + ", msg:" + error.getMessage());

            }
        });

辅助类如下

接口类:

public interface VipPayService {
  @GET("/prepay")
    void newWay2PayVideo(@QueryMap Map<String, String> options,
                         Callback<UnifyPayMessage> callback);

}

bean类:

public class UnifyPayMessage {

    private String status;
    private String msg;
    private String notify_url;
    private String order_id;
    private String alipay_app;
    private WXPrepayInfo wx_app;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getNotify_url() {
        return notify_url;
    }

    public void setNotify_url(String notify_url) {
        this.notify_url = notify_url;
    }

    public String getOrder_id() {
        return order_id;
    }

    public void setOrder_id(String order_id) {
        this.order_id = order_id;
    }

    public WXPrepayInfo getWx_app() {
        return wx_app;
    }

    public void setWx_app(WXPrepayInfo wx_app) {
        this.wx_app = wx_app;
    }

    public String getAlipay_app() {
        return alipay_app;
    }

    public void setAlipay_app(String alipay_app) {
        this.alipay_app = alipay_app;
    }

    @Override
    public String toString() {
        return "UnifyPayMessage{" +
                "status='" + status + '\'' +
                ", msg='" + msg + '\'' +
                ", notify_url='" + notify_url + '\'' +
                ", order_id='" + order_id + '\'' +
                ", alipay_app='" + alipay_app + '\'' +
                ", wx_app=" + wx_app +
                '}';
    }
}

7)支付以及结果判断
支付宝支付: 第一步为异步支付,第二步异步支付结果判断是否成功 支付:


  private void startPay(final UnifyPayMessage unifyPayMessage) {
        if(unifyPayMessage == null || unifyPayMessage.getAlipay_app() == null)return;
        try {
            //签名拼接支付信息操作交由后台
            LOGD("ExternalPartner start pay");
            // start the pay.
            Runnable payRunnable = new Runnable() {
                @Override
                public void run() {
                    PayTask alipay = new PayTask(mActivity);
                    String result = alipay.pay(unifyPayMessage.getAlipay_app());

                    Message msg = new Message();
                    msg.what = SDK_PAY_FLAG;
                    msg.obj = result;
                    alipayHandler.sendMessage(msg);
                }
            };

            Thread payThread = new Thread(payRunnable);
            payThread.start();

        } catch (Exception ex) {
            LOGE("alipay error".concat(ex.getMessage()), ex);
            ToastUtil.show(mActivity, 
mActivity.getString(R.string.remote_call_failed));
        }
}

结果判断:


 private Handler alipayHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SDK_PAY_FLAG:
                    closeProgress();
                    if (mActivity != null) {
                        Result resultObj = new Result((String) msg.obj);
                        String resultStatus = resultObj.resultStatus;

                        // 判断resultStatus 为“9000”则代表支付成功,具
体状态码代表含义可参考接口文档
                        if (resultStatus.equals("9000")) {
                            ToastUtil.show(mActivity, "支付成功");
                            EventBus.getDefault().post(new 
EventPayment(PayUtil.PAY_TYPE_ALIPAY, PayUtil.PAY_RESULT_STATUS_SUCCESS));
                        } else {
                            // 判断resultStatus 为非“9000”则代表可能支付失败
                            // “8000” 代表支付结果因为支付渠道原因或
者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准
(小概率状态)
                            if (resultStatus.equals("8000")) {
                                ToastUtil.show(mActivity, "支付结果确认中");
                            } else {
                                ToastUtil.show(mActivity, "支付失败");
                                EventBus.getDefault().post(new 
EventPayment(PayUtil.PAY_TYPE_ALIPAY, PayUtil.PAY_RESULT_STATUS_FAIL));
                            }
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    };

微信支付:


//预支付订单生成之后调用支付订单
private void genPayReq(UnifyPayMessage unifyPayMessage) {
        PayReq req = new PayReq();
        req.appId = unifyPayMessage.getWx_app().getAppid();
        req.partnerId = unifyPayMessage.getWx_app().getPartnerid();
        req.prepayId = unifyPayMessage.getWx_app().getPrepayid();
        req.packageValue = "Sign=WXPay";
        req.nonceStr = unifyPayMessage.getWx_app().getNoncestr();
        req.timeStamp = unifyPayMessage.getWx_app().getTimestamp();
        req.sign = unifyPayMessage.getWx_app().getSign();

        // 发起支付请求
        msgApi.registerApp(Constants.APP_ID);
        msgApi.sendReq(req);
    }