支付宝刷脸预授权

https://docs.open.alipay.com/20180402104715814204/intro

https://doc.open.alipay.com/docs/doc.htm?docType=1&articleId=109099

https://doc.open.alipay.com/docs/doc.htm?docType=1&articleId=108944

 

首先,你要参考文档拿到ftoaken,详见普通刷脸的文档https://docs.open.alipay.com/20180402104715814204/intro

联系支付宝要添加依赖

之后在App的build.gradle中添加依赖

implementation(name: 'Alipay_UniSDK', ext: 'aar')
implementation 'com.google.protobuf:protobuf-lite:3.0.0'

添加之后可能会遇到错误:The number of method references in a .dex file cannot exceed 64K.(详见https://mp.csdn.net/postedit/86241021)

然后添加

implementation 'com.android.support:multidex:1.0.1'

 

添加multiDexEnabled true

然后开始看文档https://doc.open.alipay.com/docs/doc.htm?docType=1&articleId=109099

刷脸+预授权

业务流程图:

扫脸当做预授权一种新的授权方式,等同于现在的付款码预授权一样。

解决方案技术实现:

1. 完成客户端人脸识别的接入,前往支付级刷脸服务 ,获取ftoken

注意:针对刷脸+当面资金授权场景,刷脸初始化接口(zoloz.authentication.customer.smilepay.initialize)中bizType=12并传入身份证信息。 示例:"extInfo":{"bizType":"12" ,"certName":"身份证姓名" ,"certNo":"身份证号" ,"certType":"IDCARD"}

2. 接入当面资金授权。前往当面资金授权技术文档

(1)其中alipay.fund.auth.order.freeze(资金授权冻结接口)接口的请求参数中auth_code参数值设置为扫脸sdk返回的FToken的值。

(2)alipay.fund.auth.order.freeze(资金授权冻结接口)接口的请求参数中auth_code_type=security_code

(3)alipay.fund.auth.order.freeze(资金授权冻结接口)接口的请求参数中传入terminal_params,即机具管控sdk加签参数,请参考5.2机具管控SDK开发对接 。其中交易加签,即通过机具管控SDK提供的签名接口,将签名信息(扫脸ftoken信息等)生成为机具专用业务签名,参考机具管控对接文档中2.4 交易加签 。示例:"terminal_params":"{\"terminalType\":\"IOT\",\"signature\":\"QIIAX8DqbFbNf2oe97FI1RSLAycC/tU4GVjer3bN8K4qLtAB\",\"apdidToken\":\"xPA3ptuArwYc3F6Va_pjVwv7Qx7Tg5TJdrA_Jb_moYte9AqGZgEAAA==\",\"hardToken\":\"\",\"time\":\"1539847253\",\"bizCode\":\"11000200040004000121\",\"bizTid\":\"010100F01i1XyacMgpOinHerfdBw1xA9dNDocctlnqhLD8lfODr1A7Q\",\"signedKeys\":\"authCode,totalAmount,apdidToken,hardToken,time,bizCode,bizTid\"}"

3. 预授权转支付交易里需要传入门店ID,以获得反佣

 

注意:

你要确保你得设备是已经接入了IoTSDK(我这边是商米的设备,已经集成好了,)

然后开始集成android这边的文档,集成文档参见https://doc.open.alipay.com/docs/doc.htm?docType=1&articleId=108944

android集成

先初始化接口 

FromImage

1.APIManager.getInstance().initialize(this, isvId);(这里应该捕获异常的)参数是下面的

2.获取public String getDeviceId();不为空(建议0.5~1s请求一次确保不为空null)

DeviceAPI api = APIManager.getInstance().getDeviceAPI();
Log.e("TAG", "public String getDeviceId();---------"+api.getDeviceId());

3.然后去加参(这里根据类型去调用,详见文档https://doc.open.alipay.com/docs/doc.htm?docType=1&articleId=108944)

PaymentAPI api = APIManager.getInstance().getPaymentAPI();
String terminal_params = api.signWithFaceToken(fToken, dataBinding.depositMoneyCount.getText().toString());

(到这里已经加参结束.log打印terminal_params 就是加参返回结果)

 

hardToken这个参数为空,有影响吗?

没影响,原样传给交易接口就好了

 

然后就是:

3、加签返回结果:

本接口返回的加签结果为以json结构表示的字符串,格式如下:

{"terminalType":"IOT","signature":"ERKDmm3fhGCvZZP0ob5gHUiTuTaFbB5gjjYBYxdOVwezN+sSJdV+uJy4kegYC6RQDzOLx/vbLYPoZTzxPXsVAFZgCg==","apdidToken":"iBfdgYKtgBObNOOybNHkaItG2EQkY3bovzvKDqtyWKVQ9tfvZAEAAA==","hardToken":"0601469C6568AEB7BA92FCC21DF8C766CC8A78A5BF874FC509A2D262B8B5FB9E35FF","time":"1533061133","bizCode":"11000100020002200020","bizTid":"01010020015XmMUS5BmWl39qqatmTLukjswaEaSYJADU2EQ2kb3AjcY","signedKeys":"authCode,totalAmount,apdidToken,hardToken,time,bizCode,bizTid"}

应用开发者获取加签结果后,最终向支付宝收单平台发起交易请求时,按交易报文协议在terminal_params字段中以字符串的形式带上此加签结果,从而完成交易扣款。

特别说明:由于交易报文协议为JSON格式,在构造terminal_params属性时,必须以字符串形式,因此,务必注意子json字符串的表示格式(需要转义)。

然后把terminal_params这个参数透传给服务端,

 

terminal_params这个参数是初始化人脸之后,在调用支付宝那边支付的时候,把这个参数传给服务端,由服务端调用支付宝接口(因为涉及敏感字段,所以由服务端调起)

详见下面部分代码(和普通刷脸逻辑相似)

private Zoloz zoloz;

public final static String isvId="一串数字"

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
      //初始化SDK
        try {
            APIManager.getInstance().initialize(this, isvId);
        } catch (APIManager.APIInitException e) {
            e.printStackTrace();
        }
        DeviceAPI api = APIManager.getInstance().getDeviceAPI();
        //初始化之后.,每个0.5S或者1s一次
        //循环不为空getDeviceId不为空
        Log.e("TAG", "public String getDeviceId();---------"+api.getDeviceId());
        扫脸用的,要是不行就放在首页开始初始化
        zoloz = com.alipay.zoloz.smile2pay.service.Zoloz.getInstance(getApplicationContext());        
         dataBinding.sweepAutFace.setOnClickListener(this);//刷脸预售权    
          
         if(SystemUtil.getSystemModel().contains("T2")) {
            dataBinding.sweepAutFace.setVisibility(View.VISIBLE);
          }
     
   }   
     
  
 
 

    @Override
    public void onClick(View v) {
        Intent intent;
        switch (v.getId()) {
            case R.id.sweep_aut_face:
                //刷脸预授权
                if (TextUtils.isEmpty(dataBinding.depositMoneyCount.getText().toString())) {

                    Snackbar.make(v, "请输入收款金额!", Snackbar.LENGTH_SHORT).show();
                    return;
                }
                if (TextUtils.isEmpty(dataBinding.depositNote.getText().toString())) {
                    Snackbar.make(v, "请输入备注信息!", Snackbar.LENGTH_SHORT).show();
                    return;
                }
                Log.e("TAG", "进入刷脸预售权");
//                Toast.makeText(DepositActivity.this, "进入刷脸预售权", Toast.LENGTH_SHORT).show();
                smileFacePay();
                break;
                   
        }

    }


    /**
     * 发起刷脸支付请求,先zolozGetMetaInfo获取本地app信息,然后调用服务端获取刷脸付协议.
     */
    // 值为"1000"调用成功
    // 值为"1003"用户选择退出
    // 值为"1004"超时
    // 值为"1005"用户选用其他支付方式
    static final String CODE_SUCCESS = "1000";
    static final String CODE_EXIT = "1003";
    static final String CODE_TIMEOUT = "1004";
    static final String CODE_OTHER_PAY = "1005";

    static final String TXT_EXIT = "已退出刷脸支付";
    static final String TXT_TIMEOUT = "操作超时";
    static final String TXT_OTHER_PAY = "已退出刷脸支付";
    static final String TXT_OTHER = "抱歉未支付成功,请重新支付";

    //刷脸支付相关
    static final String SMILEPAY_CODE_SUCCESS = "10000";
    static final String SMILEPAY_SUBCODE_LIMIT = "ACQ.PRODUCT_AMOUNT_LIMIT_ERROR";
    static final String SMILEPAY_SUBCODE_BALANCE_NOT_ENOUGH = "ACQ.BUYER_BALANCE_NOT_ENOUGH";
    static final String SMILEPAY_SUBCODE_BANKCARD_BALANCE_NOT_ENOUGH = "ACQ.BUYER_BANKCARD_BALANCE_NOT_ENOUGH";

    static final String SMILEPAY_TXT_LIMIT = "刷脸支付超出限额,请选用其他支付方式";
    static final String SMILEPAY_TXT_EBALANCE_NOT_ENOUGH = "账户余额不足,支付失败";
    static final String SMILEPAY_TXT_BANKCARD_BALANCE_NOT_ENOUGH = "账户余额不足,支付失败";
    static final String SMILEPAY_TXT_FAIL = "抱歉未支付成功,请重新支付";
    static final String SMILEPAY_TXT_SUCCESS = "刷脸支付成功";
    private ISharedPreference sharedPreference;
    private List<FacePayBean.DataBean> products;
    //使用AsyncHttpClient,实现联网的声明
    public AsyncHttpClient client = new AsyncHttpClient();





    private void smileFacePay() {
        zoloz.zolozGetMetaInfo(mockInfo(), new ZolozCallback() {
            // 解析zolozGetMetaInfo返回的结果,如果成功,则请求商户服务端调用人脸初始化接口
            @Override
            public void response(Map smileToPayResponse) {
                if (smileToPayResponse == null) {                
                    Toast.makeText(DepositActivity.this, "TXT_OTHER", Toast.LENGTH_SHORT).show();
                    return;
                }
                String code = (String)smileToPayResponse.get("code");
                String  metaInfo = (String)smileToPayResponse.get("metainfo");
                Log.e("TAG", "code----------------"+code);//1000值为"1000"调用成功
                //获取metainfo成功
                if (CODE_SUCCESS.equalsIgnoreCase(code) && metaInfo != null) {
//                    2. 刷脸初始化(建议服务端调起)
                    //这里用Rxjava 联网请求报线程错误
                    //然后找了两个个jar包android-async-http-master.jar和fastJson-1.1.45.jar
                    //android-async-http-master.jar请求数据用fastJson-1.1.45.jar解析                  
                    sharedPreference = ISharedPreference.getInstance(getApplication());//获取保存的token
                    //联网发送信息给服务器(自己的服务器)
                    String register = ApiService.baseUrl+"merchant/smilepayInit";//服务器地址
                    //这里是要传送的参数
                    RequestParams params = new RequestParams();
                    params.put("token",sharedPreference.getToken());
                    params.put("all",metaInfo);
                    //开始联网请求
                    client.post(register,params ,new AsyncHttpResponseHandler(){
                        //成功
                        @Override
                        public void onSuccess(String content) {
                            //这里去解析数据content
                            JSONObject jsonObject = JSON.parseObject(content);
                            String proInfo = jsonObject.getString("data");
                            products = JSON.parseArray(proInfo, FacePayBean.DataBean.class);                                  
                            //获取zimId和zimInitClientData调用人脸初始化
                            String zimId = products.get(0).getZimId();
                            String zimInitClientData = products.get(0).getZimInitClientData();
                            smile(zimId, zimInitClientData);//唤起人脸识别去支付
                            //这个我也不知道干嘛的,好像不能注释
                            UIUtils.getHandler().postDelayed(new Runnable() {
                                @Override
                                public void run() {
//                                    removeCurrentActivity();//销毁当前的activity
                                }
                            },2000);
                        }
                        @Override
                        public void onFailure(Throwable error, String content) {
                            Toast.makeText(DepositActivity.this, "网络异常,调用失败!", Toast.LENGTH_SHORT).show();

                        }
                    } );
                }
            }
        });
    }
    public static final String KEY_INIT_RESP_NAME = "zim.init.resp";
    /**
     * 发起刷脸支付请求.
     * @param zimId 刷脸付token,从服务端获取,不要mock传入
     * @param protocal 刷脸付协议,从服务端获取,不要mock传入
     */
    //. 唤起人脸识别
    private void smile(String zimId, String protocal) {
        Map params = new HashMap();
        params.put(KEY_INIT_RESP_NAME, protocal);
        /* start: 如果是预输入手机号方案,请加入以下代码,填入会员绑定的手机号,必须与支付宝帐号对应的手机号一致 */
//        这句代码就是扫脸之后会有一个用户输入手机号的页面,您要是写这一行,就不需要用户去手动输入,会直接把用户手机号显示在页面,
// 不写的话需要用户手动去输入
//        params.put("phone_number", "1381XXXXX");
        /* end: --------------------------------------------- */
        zoloz.zolozVerify(zimId, params, new ZolozCallback() {
            @Override
            public void response(final Map smileToPayResponse) {
                if (smileToPayResponse == null) {
                    Toast.makeText(DepositActivity.this, TXT_OTHER, Toast.LENGTH_SHORT).show();
                    return;
                }
                String code = (String)smileToPayResponse.get("code");
                String fToken = (String)smileToPayResponse.get("ftoken");
                String subCode = (String)smileToPayResponse.get("subCode");
                String msg = (String)smileToPayResponse.get("msg");
             

                //刷脸成功
                if (CODE_SUCCESS.equalsIgnoreCase(code) && fToken != null) {        
                    sharedPreference = ISharedPreference.getInstance(getApplication());//获取保存的token
                    //联网发送信息给服务器(自己的服务器)
                    String register = ApiService.baseUrl+"merchant/SmFundAuthTradePayCodeType";
                    //这里是要传送的参数
                    PaymentAPI api = APIManager.getInstance().getPaymentAPI();
                    String terminal_params = api.signWithFaceToken(fToken,dataBinding.depositMoneyCount.getText().toString());
                    RequestParams params = new RequestParams();
                    params.put("token",sharedPreference.getToken());
                    params.put("remarks",dataBinding.depositNote.getText().toString());//备注
                    params.put("code",fToken);//传ftonen
                    params.put("price",dataBinding.depositMoneyCount.getText().toString());//金额              
                    params.put("terminal_params",terminal_params);
                  
                    client.post(register, params, new AsyncHttpResponseHandler(){
                        @Override
                        public void onSuccess(String content) {
                           
                            ScanAutBean scanPayBean = JSON.parseObject(content, ScanAutBean.class);
                            if (scanPayBean != null) {

//                                print(scanPayBean.);//打印
//                                showPrintDialog(scanPayBean);//自己写
                            }
                        }

                        @Override
                        public void onFailure(Throwable error, String content) {
                            Toast.makeText(DepositActivity.this, "网络异常,未支付成功!", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }

        });
    }



 
    //将交易金额统一处理成12位,不足12位的在前面补0
    private String getAmount(String amount) {
        if (TextUtils.isEmpty(amount)) return null;
        while (amount.length() < 12) {
            amount = "0" + amount;
        }
        return amount;
    }
  
    //获取当前时间
    private String getCurrentTime() {
        SimpleDateFormat simpleDateFormat = (SimpleDateFormat) SimpleDateFormat.getDateInstance();
        simpleDateFormat.applyPattern("MM-dd HH:mm:SS");

        return simpleDateFormat.format(new Date());
    }

   
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值