Andorid微信刷脸支付使用过程解析


本文着重是 开发前的准备工作和开发过程中遇到的一些坑,不涉及 优化 ,订单查询 ,退款和 具体商户后台server的开发。
开发环境: rk开发板 +华捷艾米A200 camera
最终实现 用自己的应用和商户信息成功进行了一笔刷脸支付过程的demo 并且不需要搭建自己的商户后台server。

1.创建移动应用

微信开放平台
在微信开放平台中创建 移动应用,填写 包名 和 签名信息 等。创建需要等审核完成,一般审核过程很快。

在这里插入图片描述
然后开通微信支付,未认证用户需要进行认证。认证过程也需要审核,这个比创建应用的时候要慢。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
认证过程需要填写一些企业资料 和收取一定费用 ,好像是 300/年 。

2.申请商户号, 开通APP支付和刷脸支付,关联APPID

微信商户号申请

在这里插入图片描述
点击APP支付 申请开通
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开通后 在APPID授权管理 标签页中 关联 步骤1 中所申请的 APPID (必须已经完成认证并且开通APP支付权限)。
在这里插入图片描述
如果APPID未认证 会提示
在这里插入图片描述
如果未开通APP支付权限
在这里插入图片描述
所以必须先要认证并且开通支付权限。

正常情况:
在这里插入图片描述
然后去微信开放平台 对应的APP设置中确认 关联。
在这里插入图片描述
在这里插入图片描述
至此绑定完成


3.开发指引 | 微信刷脸支付

微信刷脸支付 开发指引
微信刷脸支付SDK 目前应该也在快速迭代中,前几天还是1.30版本,现在就已经更新2.10版本了。
使用方式:

  1. 安装人脸App。WxPayFace 微信刷脸支付SDK
  2. 商户接入人脸SDK。项目中引入1中的aar包。商户APP demo
  3. 商户server .商户server demo 此server是在商户自己开发整套流程的参考demo ,如果只是跑通商户App demo 则不需要此server。


4.刷脸支付流程

名词解释

人脸授权 :通过人脸识别,返回微信用户信息(openid, face_code)。

face_code:人脸凭证。常用于人脸支付,作为订单的支付凭证。

时序图

商户APP微信人脸sdk商户server微信支付后台API1. 程序启动时初始化 initWxpayfacedoInitWxpayface(返回初始化结果)2. 获取数据 getWxpayfaceRawdatadoGetWxpayfaceRawdata(返回rawdata)3.获取SDK调用凭证3.get_wxpayface_authinfo(rawdata)返回authinfo返回authinfo4. 进行人脸识别 getWxpayfaceCode启动人脸识别activity进行人脸识别完成人脸识别回调返回人脸识别结果(face_code, openid)doWxPayfaceCodeCallback(返回人脸识别结果)进行支付5. 发起订单人脸支付发起订单支付facepay(face_code, orderinfo)返回支付结果返回支付结果查询支付结果查询订单状态queryorder返回订单状态loop[ 直到:返回确定的订单状态(成功/失败/订单不存在)/超过轮询时间 ]返回支付结果撤销交易,以避免用户扣款,而没有发货的情况(撤销可后台异步进行)3. 撤销交易reverseorder返回撤销结果loop[ 撤销交易直到成功 ]opt[ 轮询结束仍然没有支付成功 ]alt[ 支付成功/失败 ][ 支付结果未明(比如:支付中/网络超时) ]6. 更新支付结果updateWxpayfacePayResult(callback)用户确认支付结果关闭人脸应用界面doUpdatePayResultCallBack(界面关闭,触发回调)程序退出(...)6. 释放资源 releaseWxpayface商户APP微信人脸sdk商户server微信支付后台API

注:

  1. 初始化 initWxpayface, 只需要在程序启动时调用;
  2. 释放资源 releaseWxpayface,只需要在程序退出时调用;
    每个方法的具体参数可在文档内查看。接口文档

5.接口调用踩坑

(1)初始化(initWxpayface)

这个一般放在自己定义的Application#onCreate()中调用就可以了。官方示例copy即可

//对人脸SDK进行初始化
WxPayFace.getInstance().initWxpayface(this, new IWxPayfaceCallback() {
			@Override
			public void response(Map info) throws RemoteException {
				if (info == null) {
					new RuntimeException("调用返回为空").printStackTrace();
					return ;
				}
				String code = (String) info.get("return_code");
				String msg = (String) info.get("return_msg");
				Log.d(TAG, "response info :: " + code + " | " + msg);
				if (code == null || !code.equals("SUCCESS")) {
					new RuntimeException("调用返回非成功信息: " + msg).printStackTrace();
					return ;
				}
				Log.d(TAG, "调用返回成功");
			}
		});

(2)获取数据 (getWxpayfaceRawdata)

此过程 一定要保证 两点:
1.设备能联网,应用要添加<uses-permission android:name="android.permission.INTERNET"/>权限,
官方demo中还添加以下权限:

   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   <uses-permission android:name="android.permission.READ_PHONE_STATE" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2.设备有SN号 。在android设备上,开机后进入setting->about devices->status->Serial number查看
当时使用的是 rk开发板,IMG没有写入SN号。当时在论坛上找的写入SN号工具只能写入 "ro.boot.serialno"的值,"ro.serialno"还是空的,所以最后只能修改源代码,重新编译烧录版本。

    /** 2. 人脸识别第二步 获取raw data*/
    private void getWxpayfaceRawdata() {
        WxPayFace.getInstance().getWxpayfaceRawdata(new IWxPayfaceCallback() {
            @Override
            public void response(Map info) throws RemoteException {
                if (info == null) {
                    new RuntimeException("调用返回为空").printStackTrace();
                    return;
                }
                String code = (String) info.get("return_code");
                String msg = (String) info.get("return_msg");
                rawdata = info.get("rawdata").toString();
                Log.d(TAG, "rawdata ==" + rawdata);
                if (code == null || rawdata == null || !code.equals("SUCCESS")) {
                    new RuntimeException("调用返回非成功信息,return_msg:" + msg + "   ").printStackTrace();
                    return ;
                }
       	        /**
       	         在这里处理您自己的业务逻辑
                 可以紧接着执行第三步 获取调用凭证getAuthInfo,
                 这应该是向 商户server 发起请求。
       	         */
       	        getAuthInfo(rawdata);
            }
        });
    }

(3)获取调用凭证(get_wxpayface_authinfo)

这是一个后端调用接口 采用xml格式
因为demo为了省事,省去商户后台server的开发,所以这一步也是在Android端直接调用。
获取凭证需要很多的 参数

参数 必填 类型 说明
store_id string(32) 门店编号, 由商户定义, 各门店唯一。
store_name string(128) 门店名称,由商户定义。(可用于展示)
device_id string(32) 终端设备编号,由商户定义。
attach string 附加字段。字段格式使用Json
rawdata string(2048) 初始化数据。由微信人脸SDK的接口返回。
获取方式参见:
[获取数据 getWxpayfaceRawdata](#获取数据 getWxpayfaceRawdata)
[获取数据 getWxpayfaceRawdata](#获取数据 getWxpayfaceRawdata)
appid string(32) 商户号绑定的公众号/小程序 appid
mch_id string(32) 商户号
sub_appid string(32) 子商户绑定的公众号/小程序 appid(服务商模式)
sub_mch_id string(32) 子商户号(服务商模式)
now int 取当前时间,10位unix时间戳。 例如:1239878956
version string 版本号。固定为1
sign_type string 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
nonce_str string(32) 随机字符串,不长于32位
sign string 参数签名。详见微信支付签名算法
Sign参数获取

签名算法

签名生成的通用步骤如下:

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

参数名ASCII码从小到大排序(字典序)
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

◆ key设置路径:微信商户平台(pay.weixin.qq.com)–>账户设置–>API安全–>密钥设置
,获取方法:
在这里插入图片描述
安装插件 ,浏览器最好别用QQ浏览器。在这里插入图片描述
自家的插件不知道为什么唤不起来。重启N遍无用,推荐Chrome.
密钥是32位字符串 。
在上面第二步代码回调成功后紧接着 可以调用第三步。

    private void getAuthInfo(String rawdata){
        //now 参数 是unix 10位时间戳
        long  time = System.currentTimeMillis()/1000L;
        //为了对比起来方便 下面所有请求 都是用 字符串拼接的方式。
        //注意参数顺序 参数名ASCII码从小到大排序(字典序).
        String a ="appid=appid应用ID&device_id=DEV001&mch_id=mch_id商户号&nonce_str=V37ZHZVf2OrwsUV7kXTjTguP74c0byvE&now="+time+"&rawdata="+rawdata+"&sign_type=MD5&store_id=IMG001&store_name=门店名称&version=1";
        String stringSignTemp=a+"&key=32位的字符串";//注:key为商户平台设置的密钥key
        String sign= md5(stringSignTemp).toUpperCase(); //注:MD5签名方式
        Log.d(TAG, "sign : " +sign);
        String  finalStr = "<xml>\n" +
                "     <appid>appid应用ID</appid>\n" +
                "     <device_id>DEV001</device_id>\n" +
                "     <nonce_str>V37ZHZVf2OrwsUV7kXTjTguP74c0byvE</nonce_str>\n" +
                "     <now>"+time+"</now>\n" +
                "     <mch_id>mch_id商户号</mch_id>\n" +
                "     <rawdata>"+rawdata+"</rawdata>\n" +
                "     <store_id>IMG001</store_id>\n" +
                "     <store_name>门店名称</store_name>\n" +
                "     <sign_type>MD5</sign_type>\n" +
                "     <version>1</version>\n" +
                "     <sign>"+sign+"</sign>\n" +
                "</xml>";
       
        //SSL可以不用管
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient client = new OkHttpClient.Builder()
                    .sslSocketFactory(sslSocketFactory)
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            return true;
                        }
                    })
                    .build();
                    
            //请求格式xml ,请求方式post
            RequestBody body=RequestBody.create(MediaType.parse("application/xml"),finalStr);
            Request request = new Request.Builder()
                    .url("https://payapp.weixin.qq.com/face/get_wxpayface_authinfo")//后台接口地址,具体见后台开发文档
                    .post(body)
                    .build();

            client.newCall(request)
                    .enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
                            Log.d(TAG, "onFailure | getAuthInfo " + e.toString());
                        }

                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            try {
                                String bodyStr = response.body().string();
                                Log.d(TAG, "onResponse | getAuthInfo " + bodyStr);
                                //这里返回的不是标准的xml格式,缺少 开始标签 ,拼接后用XmlPullParser解析
                                String  xmlStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+bodyStr;
                                //ReturnXMLParser 类在官方的demo中
                                //最终获取到 AuthInfo信息。
                                mAuthInfo = ReturnXMLParser.parseGetAuthInfoXML( new ByteArrayInputStream(xmlStr.getBytes()));
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    });
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    

这里需要注意的很多 :

  1. now 参数 注意是 10位的 时间戳 。并且拼接字符串a 时用的now 和 最后请求Body中xml内容中的Now的值一定要相同,两个地方切勿直接用 System.currentTimeMillis()/1000L
  2. 获取sign值 拼接的字符串a 一定要按照参数名ASCII码从小到大排序。sign值可以用签名校验工具验证
  3. 请求接口 https://payapp.weixin.qq.com/face/get_wxpayface_authinfo
  4. 返回值不是标准的xml格式,不包括"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"部分,所以可以先拼接在解析。

就这样最终拿到了AuthInfo字符串 。


(4)获取人脸支付凭证(getWxpayfaceCode)

启动人脸APP主界面入口,开启人脸识别,获取用户信息(openid)和支付凭证()。

参数 必填 类型 说明
appid string 商户号绑定的公众号/小程序 appid
mch_id string 商户号
sub_appid string(32) 子商户绑定的公众号/小程序 appid(可不填)
sub_mch_id string(32) 子商户号(非服务商模式不填)
store_id string 门店编号
telephone string 用户手机号。用于传递会员手机,此手机将作为默认值, 填写到手机输入栏。
out_trade_no string 商户订单号,须与调用支付接口时字段一致,该字段在在face_code_type为"1"时可不填,为"0"时必填
total_fee string 订单金额(数字), 单位分. 该字段在在face_code_type为"1"时可不填,为"0"时必填
face_authtype string 可选值:
FACEPAY: 人脸凭证,常用于人脸支付
FACEPAY_DELAY: 延迟支付(提供商户号信息联系微信支付开通权限)
authinfo string 调用凭证。获取方式参见: get_wxpayface_authinfo
ask_face_permit string 支付成功页是否需要展示人脸识别授权项。
展示:1
不展示:0
人脸识别授权项:
用户授权后用于1:N识别,可返回用户信息openid,建议商户有自己会员系统时,填1。
ask_ret_page string 是否展示微信支付成功页,可选值:“0”,不展示;“1”,展示
face_code_type string 目标face_code类型,可选值:“0”,人脸付款码:数字字母混合,通过「刷脸支付」接口完成支付;“1”,刷卡付款码:18位数字,通过「付款码支付/被扫支付」接口完成支付。如果不填写则默认为"0"
ignore_update_pay_result string 商户端是否对SDK返回支付结果,可选值:“0”,返回支付结果,商户需在确认⽀付结果后调⽤[updateWxpayfacePayResult]通知SDK;“1”,不返回支付结果。如果不填写则默认为"0"。
    private void getWXPayFaceCode(String mAuthInfo){
        if (mAuthInfo== null){
            Log.d(TAG, "mAuthInfo 为 null");
            return;
        }
        HashMap params = new HashMap();
        params.put(BaseUtils.FACE_AUTHTYPE, "FACEPAY");
        params.put(BaseUtils.APPID, "wxefawffetat56");
        params.put(BaseUtils.MCH_ID, "11534ef6121");
        params.put(BaseUtils.STORE_ID, "IMG001");
        //订单号 ,注意后后面支付pay中的订单号要一致
        out_trade_no = "" +(System.currentTimeMillis() / 100000); 
        params.put(BaseUtils.OUT_TRADE_NO, out_trade_no);
        //订单金额
        params.put(BaseUtils.TOTAL_FEE, "1");
        //第三步中获取的AuthInfo
        params.put(BaseUtils.AUTHINFO, mAuthInfo);

        WxPayFace.getInstance().getWxpayfaceCode(params, new IWxPayfaceCallback() {
            @Override
            public void response(final Map info) throws RemoteException {
//                if (!isSuccessInfo(info)) {
//                    return;
//                }
                Log.d(TAG, "response | getWxpayfaceCode" );

                final String code = (String)info.get(BaseUtils.RETURN_CODE);
                // open id  , face code
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //请求成功
                        if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SUCCESS)) {
                            //获取openid 和 face_code 
                            face_code = (String)info.get("face_code");
                            openID = (String)info.get("openid");
                            ip = "174.207.250.66";
                            try {
                                Thread.sleep(2000);
                                //第5步 支付
                                pay(openID,face_code,ip);
                            } catch (Exception e) {
                            }
                        } else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_USER_CANCEL)) {
                            Log.d(TAG, "run: 用户取消");
                        } else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SCAN_PAYMENT)) {
                            Log.d(TAG, "run: 扫码支付");
                        } else if (TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_ERROR)) {
                            Log.d(TAG, "run: 发生错误");
                        }
                    }
                });
            }
        });
    }

这个过程没什么说的,就是用第三步的AuthInfo ,还有就是订单号 要和后面第五步支付过程的订单号要保持一致。

(5)支付 (pay),并更新支付结果(updateWxpayfacePayResult)

1. pay

支付 同样是一个后端server接口 后端server接口
接口地址 :https://api.mch.weixin.qq.com/pay/facepay
请求方式 POST、XML

参数 必填 类型 说明
appid string 商户号绑定的公众号/小程序 appid
mch_id string 商户号
sub_appid string(32) 子商户绑定的公众号/小程序 appid(可不填)
sub_mch_id string(32) 子商户号(非服务商模式不填)
device_info string(32) 终端设备号(商户自定义,如门店编号)。
out_trade_no string(32) 商户系统内部的订单号,32个字符内、可包含字母;更换授权码必须要换新的商户订单号 其他说明见商户订单号
total_fee string 订单金额(数字), 单位分. 该字段在在face_code_type为"1"时可不填,为"0"时必填
nonce_str string(32) 随机字符串,不长于32位。推荐随机数生成算法
sign string(32) 参数签名。详见微信支付签名算法
body String(128) 商品或支付单简要描述,格式要求:门店品牌名-城市分店名-实际商品名称
total_fee Int 订单总金额,单位为分,只能为整数,详见支付金额
spbill_create_ip String(16) 调用微信支付API的机器IP
openid String(128) 用户在商户appid 下的唯一标识
face_code String(128) 人脸凭证,用于刷脸支付

更多不必要参数可查看文档。
举例如下:

<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <attach>订单额外描述</attach>
   <body>刷卡支付测试</body>
   <device_info>1000</device_info>
   <goods_tag></goods_tag>
   <mch_id>10000100</mch_id>
   <nonce_str>8aaee146b1dee7cec9100add9b96cbe2</nonce_str>
   <out_trade_no>1415757673</out_trade_no>
   <spbill_create_ip>14.17.22.52</spbill_create_ip>
   <time_expire></time_expire>
   <total_fee>1</total_fee>
   <openid><![CDATA[oUpF8uN95-Ptaags6E_roPHg7AG0]]></openid>
   <face_code>Qpoqwhsdjhfausrhqieofnq90w=w8233wdwjdjiwq</face_code>
   <sign>C29DB7DB1FD4136B84AE35604756362C</sign>
</xml>

pay方法中Http请求 返回结果请查看文档
在这里插入图片描述

2. updateWxpayfacePayResult(final Map info, final IWxPayfaceCallback wxpayfaceCallBack)
接口参数
参数 必填 类型 说明
appid string 商户绑定的公众号/小程序 appid
mch_id string 商户号
store_id string 门店编号
authinfo string 调用凭证。获取方式参见: get_wxpayface_authinfo
payresult string 支付结果。可取值:
SUCCESS: 支付成功
ERROR: 支付失败
接口返回
参数 必填 类型 说明
return_code string 错误码。公共定义见 公共错误码
return_msg string(128) 对错误码的描述
实践指引
  private void updateWxpayfacePayResult() {
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("appid", "填您的公众号"); // 公众号,必填
        map.put("mch_id", "填您的商户号"); // 商户号,必填
        map.put("store_id", "填您的门店编号"); // 门店编号,必填
        map.put("authinfo", "填您的调用凭证"); // 调用凭证,必填
        map.put("payresult", "SUCCESS"); // 支付结果,SUCCESS:支付成功   ERROR:支付失败   必填
        WxPayFace.getInstance().updateWxpayfacePayResult(map, new IWxPayfaceCallback() {
            @Override
            public void response(Map info) throws RemoteException {
                if (info == null) {
                    new RuntimeException("调用返回为空").printStackTrace();
                    return;
                }
                String code = (String) info.get("return_code"); // 错误码
                String msg = (String) info.get("return_msg"); // 错误码描述
                if (code == null || !code.equals("SUCCESS")) {
                    new RuntimeException("调用返回非成功信息,return_msg:" + msg + "   ").printStackTrace();
                    return ;
                }
                /*
                在这里处理您自己的业务逻辑:
                执行到这里说明用户已经确认支付结果且成功了,此时刷脸支付界面关闭,您可以在这里选择跳转到其它界面
                 */
            }
        });
    }

最后第五步整体过程代码:

    private void pay(String openID,String faceCode,String ipAddress){
        Log.d(TAG, "-------------start pay-----------");
        String a ="appid=APPID&body=刷脸支付测试&device_info=DEV001&face_code="+faceCode+"&mch_id=MCH_ID&nonce_str=V37ZHZVf2OrwsUV7kXTjTguP74c0byvE&openid="+openID+"&out_trade_no="+out_trade_no+"&spbill_create_ip="+ipAddress+"&total_fee=1";
        String stringSignTemp=a+"&key=32KEY";//注:key为商户平台设置的密钥key
        String sign= md5(stringSignTemp).toUpperCase();
        String  finalStr = "<xml>\n" +
                "     <appid>APPID</appid>\n" +
                "     <body>刷脸支付测试</body>\n" +
                "     <device_info>DEV001</device_info>\n"+
                "     <face_code>"+faceCode+"</face_code>\n"+
                "     <mch_id>MCHID</mch_id>\n" +
                "     <nonce_str>V37ZHZVf2OrwsUV7kXTjTguP74c0byvE</nonce_str>\n" +
                "     <openid>"+openID+"</openid>\n"+
                "     <out_trade_no>"+out_trade_no+"</out_trade_no>\n"+
                "     <spbill_create_ip>"+ipAddress+"</spbill_create_ip>\n" +
                "     <total_fee>1</total_fee>\n"+
                "     <sign>"+sign+"</sign>\n" +
                "</xml>";

        OkHttpClient client = new OkHttpClient.Builder()
                .hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                })
                .build();

        RequestBody body=RequestBody.create(MediaType.parse("application/xml"),finalStr);
        Request request = new Request.Builder()
                .url("https://api.mch.weixin.qq.com/pay/facepay")
                .post(body)
                .build();

        client.newCall(request)
                .enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        Log.d(TAG, "onFailure | getAuthInfo " + e.toString());
                    }
                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        try {
                            String bodyStr = response.body().string();
                            Log.d(TAG, "支付结果  ====\n" + bodyStr);
                            String  xmlStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+bodyStr;
//                            String retrunCode = ReturnXMLParser.parseCodeXML( new ByteArrayInputStream(xmlStr.getBytes()),"return_code");
                            String result_code = ReturnXMLParser.parseCodeXML( new ByteArrayInputStream(xmlStr.getBytes()),"result_code");
                            Map map =new HashMap();
                            map.put("appid","APPID应用ID");
                            map.put("mch_id",商户号);
                            map.put("store_id","IMG001");
                            map.put("authinfo",mAuthInfo);
                            boolean resultStatus = TextUtils.equals(result_code, WxfacePayCommonCode.VAL_RSP_PARAMS_SUCCESS);
                            if (result_code!=null && resultStatus ){
                                map.put("payresult","SUCCESS");
                            }else {
                                map.put("payresult","ERROR");
                            }
							//更新支付状态 
                            WxPayFace.getInstance().updateWxpayfacePayResult(map, new IWxPayfaceCallback() {
                                @Override
                                public void response(Map info) throws RemoteException {
                                    Log.d(TAG, "-------------更新支付状态 -----------"+info.get("return_code"));
                                }
                            });
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
    }

请求成功后一定要 调用更新支付结果的方法(不然一直卡在 支付等待界面),调用后会根据结果提示支付成功或者失败。 至此整个支付流程就完事了。

最后可以去商户平台 查看订单信息:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章