【干货】Android实现支付宝当面付

        前段时间,公司有个项目,要用Android平板做一个智能点餐系统。与我们常用的APP不同,此项目仅部署在商家的终端(即Android的平板设备),而且由于时间等原因,领导不打算部署服务器。也就是说,要完全使用Android来实现。顾客点餐后,系统发起支付宝当面付请求,生成当面付二维码,顾客支付完成后,订单下发。具体的一些业务不展开细说。

        调研当面付在Android平台的使用时,先看了开放平台文档中心的一些文档(地址https://docs.open.alipay.com/194)。下图是截取的扫码支付的接入指引。我们可以看到,其实是有“商家后台”这么个模块。也就是说,我们需要从Android设备将预下单请求发送给服务端,再由服务端发送给支付宝后台。当然,这是最安全最完美的方式。通过看下图,可能很多人会问:我们能不能绕过服务端,直接由Android设备向支付宝发起预下单请求呢?答案是可以的。这也是这篇文章的重点。

  

        既然你点进了我这篇博客,那么我相信你肯定有如下的需求:没有服务端,仅仅想通过写个Android程序来实现当面付。而且,我相信你可能已经遇到了如下问题:

        1.我把java的demo下载下来,在eclipse上不能正常跑。

        那么你需要了解下当面付签约、公钥、私钥这些问题。

        2.我把java的demo导入eclipse中,可以跑,不可以生成二维码。

        那么你需要修改写代码中生成二维码部分的文件路径。

        3.我在eclipse中可以跑,但是几乎一样的代码,在Androidstudio开发的app上面不能正常使用。

        我相信大多数人是遇到了这个问题,恭喜你,你来对地方了。

        看了官方论坛的一些博客,也参考了蚂蚁金服java当面付的demo(下载地址https://docs.open.alipay.com/54/104506/)。起初,自己下载下来,导入eclipse使用,可以跑通正常的流程。但是,几乎一样的Java代码,在Android中就是不行。这个问题困扰了我三天,我也尝试去网上寻找答案,但是始终没有一篇文章能解答我的疑惑。

        看一下遇到的问题:当我们向支付宝发起预支付请求,以为自己会收到支付宝的二维码信息时,我们懵逼了,没有任何二维码生成,提示“系统异常,预下单状态未知!!!”。预支付请求代码如下(几乎跟java的demo一样):

    // 测试当面付2.0生成支付二维码
    public void test_trade_precreate() {

        String outTradeNo = "tradeprecreate" + System.currentTimeMillis() + (long) (Math.random() * 10000000L);
        String subject = "xxx品牌xxx门店当面付扫码消费";
        String totalAmount = "0.01";
        String storeId = "test_store_id";
        String timeoutExpress = "5m";

        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject)
                .setTotalAmount(totalAmount)
                .setOutTradeNo(outTradeNo)
                .setStoreId(storeId)
                .setTimeoutExpress(timeoutExpress);

        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                Log.d("TTTT", "支付宝预下单成功: )");

                AlipayTradePrecreateResponse response = result.getResponse();
                try {
                    mBitmap =  QrUtils.qrToBitmap(response.getQrCode(), 256);
                } catch (WriterException e) {
                    e.printStackTrace();
                }
                break;

            case FAILED:
                Log.d("TTTT", "支付宝预下单失败: )");
                break;

            case UNKNOWN:
                Log.d("TTTT", "系统异常,预下单状态未知!!!");
                break;

            default:
                Log.d("TTTT", "不支持的交易状态,交易返回异常!!!");
                break;
        }
    }

        看到这个问题,相信大家都是懵逼的,为什么一模一样的java代码,在eclipse中以java程序运行可以,在Android studio中就不行了呢?我们把Androidstudio下logcat切换为error,发现如下log:

        其中有个链接,打开这个链接,会告诉你验签出错之类的提示:

        于是,我开始一次又一次的验证自己的私钥公钥是否输入错误。最后,我坚信自己绝对没有配置错误。那到底为何报这个问题?于是,我开始以error中的log为关键字百度,在开发者社区查了查,大体知道问题原因了。(地址https://openclub.alipay.com/read.php?tid=2546&fid=55&ant_source=zsearch)。简单来讲,出于安全考虑,https需要验证证书,但是Android端不能验证证书。也就是说,我们要是在Android客户端实现,必须要绕过安全认证。

        由于项目时间紧,我也没有采用自己写网络请求的方法。因为我感觉不是那么靠谱。接下来,我开始去研究支付宝sdk的源码(其实我也不知道这是不是源码,反正是java的demo中的jar包。对了,我直接把java项目中所有的jar包全放进了Android项目中)。

    源码看了大半天,也可能是一两天,最后找到了问题点。文件名是WebUtils.java。部分源码如下。于是,我试着把return false改为了return true。编译一下,发起请求,成功了。。惊不惊喜?意不意外?困扰了我们很久的问题,其实只需要修改一个地方。。。

static {

        try {
            ctx = SSLContext.getInstance("TLS");
            ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() },
                new SecureRandom());

            ctx.getClientSessionContext().setSessionTimeout(15);
            ctx.getClientSessionContext().setSessionCacheSize(1000);

            socketFactory = ctx.getSocketFactory();
        } catch (Exception e) {

        }

        verifier = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return false;//默认认证不通过,进行证书校验。
            }
        };

    }

在这里注意下,我没有研究过如何把java代码打包成jar包。我们不使用alipay-sdk-java-3.3.0,直接把对应的source文件夹中的源码拷贝出来,放在我们自己的项目src中,删除原有的sdk的jar包。我相信你们比我强,知道我在说什么吧,哈哈,这应该是比较简单的操作,不展开细说。这是我项目的部分结构,以辅助说明我上面的一些话:

(1)libs:保留了alipay-sdk-java-3.3.0以为的jar包

同时,gradle中也注释掉:

(2)src:把sdk中的com.alipay.api单独拿出来放在项目中

原创博客,如转载,请注明出处!谢谢!

猜你喜欢

转载自blog.csdn.net/qq_21154101/article/details/87994955