【android仿系列进阶篇】android 支付宝手机网页支付

最近在做android~,恩,就说这么多吧

1,准备工作

支付宝相关文档下载地址:https://b.alipay.com/order/productDetail.htm?productId=2013080604609688&tabId=4#ps-tabinfo-hash

当然了,假设你已经有了pid(partner)和商户账户(seller),并且开通了手机网页支付功能。

下载的包里面,打开【手机网页即时到账接口】文件夹,看到里面的可以看看里面的pdf文档,【手机网页支付接入与使用规则.pdf】这个文档有教你怎么在支付宝开通相关的东西,这里我提一下,记得把公钥上传,然后私钥生成出来

这个包,对于android,虽然没有需要的lib,但是文档的相关参数说明也是必须的。

看文档,可以知道,网页支付需要两步,第一步是获取授权令牌,第二步根据这个令牌进行交易。

那么在第一步的时候,我们要根据文档提供的url获取令牌,这个时候我们要发起http请求,获得返回的内容,解析出来授权令牌,再去发请求,得到支付宝的支付网页,显示即可

我的做法是,第一步用http请求,第二步是webview加载链接

2,代码相关

假设你已经有了android工程,打开下载的包里面的demo【WS_WAP_PAYWAP-JAVA-UTF-8】在src目录下找到sign这个package然后把RSA.java拿出来,放到你的android工程里,因为我只用了RSA加密所以这里只拿了这一个,如果你需要其他加密方法,那就拿其他的……

还没完,再到util包里面打开AlipaySubmit.java类,找到:

/**
     * 解析远程模拟提交后返回的信息,获得token
     * @param text 要解析的字符串
     * @return 解析结果
     * @throws Exception
     */
    public static String getRequestToken(String text) throws Exception {
    	String request_token = "";
    	//以“&”字符切割字符串
    	String[] strSplitText = text.split("&");
    	//把切割后的字符串数组变成变量与数值组合的字典数组
    	Map<String, String> paraText = new HashMap<String, String>();
        for (int i = 0; i < strSplitText.length; i++) {

    		//获得第一个=字符的位置
        	int nPos = strSplitText[i].indexOf("=");
        	//获得字符串长度
    		int nLen = strSplitText[i].length();
    		//获得变量名
    		String strKey = strSplitText[i].substring(0, nPos);
    		//获得数值
    		String strValue = strSplitText[i].substring(nPos+1,nLen);
    		//放入MAP类中
    		paraText.put(strKey, strValue);
        }

    	if (paraText.get("res_data") != null) {
    		String res_data = paraText.get("res_data");
    		//解析加密部分字符串(RSA与MD5区别仅此一句)
    		if(AlipayConfig.sign_type.equals("0001")) {
    			res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
    		}

    		//token从res_data中解析出来(也就是说res_data中已经包含token的内容)
    		Document document = DocumentHelper.parseText(res_data);
    		request_token = document.selectSingleNode( "//direct_trade_create_res/request_token" ).getText();
    	}
    	return request_token;
    }

这个方法拿出来,也放到RSA里面去,其中:

res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);

这一句中,private_key是生成的私钥转换成PKCS8的内容(如果你不知道怎么生成,请打开demo里面的openssl工程,里面有一个生成命令文档,按照里面的命令即可),不是直接的RSA私钥,input_charset换成utf-8即可,

最后的:

Document document = DocumentHelper.parseText(res_data);
    		request_token = document.selectSingleNode( "//direct_trade_create_res/request_token" ).getText();

这两句,请换成成:

Log.d("res_data", res_data);
            request_token = res_data.substring(res_data.indexOf("<?"));
            int startIndex = request_token.indexOf("<request_token>");
            if (startIndex > -1) {
                int temp = "<request_token>".length();
                String start = request_token.substring(temp+startIndex, temp+startIndex+22);
                Log.d("start", start);
                int endIndex = request_token.indexOf("</request_token>");
                String end = request_token.substring(endIndex - 18, endIndex);
                Log.d("end", end);
                return start+end;
            }
            Log.d("request_token", request_token);
            return null;

这里说明一下为什么,首先它的这两句无非就是xml的解析,我们没必要这么用,还要加上它的包,另外,我发现解析出来的授权令牌里面有乱码,不管我怎么设置编码都有,本想联系客服问个原因,但是一直都是繁忙中,无奈我只能截取一下,先用着,望有知道的同学告知一下……

看我们的付款layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:id="@+id/top_bar"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:layout_alignParentTop="true"
        android:background="@color/light_black"
        android:padding="4dp">

        <TextView
            android:id="@+id/back_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="4dp
            android:gravity="center"
            android:padding="6dp"
            android:text="@string/home_back"
            android:textColor="@drawable/top_bar_selector"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/main_app_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="支付宝网页版"
            android:textColor="@android:color/white"
            android:textSize="22sp" />

    </RelativeLayout>

    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/top_bar"
        android:scrollbars="none" />
</RelativeLayout>

其中的一些color,背景等大家自己调一下,这里面很简单就一个webview

在Activity里面初始化好相关内容,其中关于webview设置如下:

webView.getSettings().setJavaScriptEnabled(true);//允许webkit执行js代码;
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message,
                                     JsResult result) {
                return super.onJsAlert(view, url, message, result);
            }
        });
        webView.setWebChromeClient(new WebChromeClient() {
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
            }
        });

        webView.setWebViewClient(new WebViewClient() {
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return super.shouldOverrideUrlLoading(view, url);
            }

            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                if (progressDialog != null) {
                    progressDialog.dismiss();
                }
            }

            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }
        });

其中有一个关闭progressdialog的步骤,这里面如果你没有这个东西,直接注释掉吧。

至此,在我们的oncreate初始话之后呢,加上我们的令牌获取请求,再此之前我们先要初始化一些参数,首先在我们的RSA.java里面添加几个方法:

订单(其中的userid如果没有可以去掉,成功后的页面和通知页面这个你要有自己的处理,当然目前没有的话也可以向我一样写上百度的地址……):

public static String getAliPayWAPOrderBodyInfor(String subject, String price, String refNo, String SUCCESS_URL, String NOTIFY_URL, String userid) {
        String orderInfor = "<direct_trade_create_req><su" +
                "bject>" + subject +
                "</subject><out_trade_no>" + "1282889689801" + "</out_trade_no><total_fee>" + price + "</tot" +
                "al_fee><seller_account_name>" + AliPayUtil.SELLER + "</seller_account_name><call_" +
                "back_url>" + SUCCESS_URL + "</call_back_" +
                "url><notify_url>" + NOTIFY_URL + "</notify_url><out_user>" + userid + "</out_user><pay_expire>3600</pay_expire></direct_trade_create" +
                "_req>";
        return orderInfor;
    }

授权令牌参数:

public static Map<String, String> getAccessTokenParamsMap() {
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "alipay.wap.trade.create.direct");
        sParaTemp.put("partner", AliPayUtil.PARTNER);//这里换成你的pid
        sParaTemp.put("sec_id", "0001");//这是RSA加密
        sParaTemp.put("format", "xml");
        sParaTemp.put("v", "2.0");
        sParaTemp.put("req_id", UtilDate.getOrderNum());//这个方法可以把util包里面的这个UtilDate.java拿过来,当然了没必要的话直接把相关的方法拿过来
        return sParaTemp;
    }

交易参数:

public static Map<String, String> getBillParamsMap() {
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("service", "alipay.wap.auth.authAndExecute");
        sParaTemp.put("partner", AliPayUtil.PARTNER);//这里换成你的pid
        sParaTemp.put("sec_id", "0001");
        sParaTemp.put("format", "xml");
        sParaTemp.put("v", "2.0");
        return sParaTemp;
    }

参数拼接方法(在util包的AlipayCore.java中)

/**
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        String prestr = "";

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);

            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }

        return prestr;
    }

生成sign签名的方法 :

public static String buildRequestMysign(Map<String, String> sPara) {
        String prestr = AlipayCore.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        mysign = sign(prestr, private_key, "utf-8");
        return mysign;
    }

然后再你的activity里面这样调用:

<pre name="code" class="html">Map<String, String> sParaTemp = AliPayUtil.getAccessTokenParamsMap();
sParaTemp.put("req_data", RSA.getAliPayWAPOrderBodyInfor(SUBJECT, price, "1282889689801", SUCCESS_URL, NOTIFY_URL, userid));
        //生成签名结果
        String mysign = RSA.buildRequestMysign(sParaTemp);
        //签名结果与签名方式加入请求提交参数组中
        sParaTemp.put("sign", mysign);

这样我们的参数map就做好了,当然了 一般我们是用post请求所以好要把它转化一下,像这样:

private List<NameValuePair> generatNameValuePair(Map<String, String> properties) {
        List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>(properties.size());
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            nameValuePair.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        return nameValuePair;
    }

这样你就可以以post形式发了,post的url是http://wappaygw.alipay.com/service/rest.htm,参数是上面的list

因为我这边用了一些框架所以对于异步的请求,很好处理,但如果你没有用呢,无非就是handler,message机制,总之,假设你得到了正确的响应结果(不正确的话,看一下code值,和文档中比较一下,j看看是什么错误),然后对结果处理:

				String dec = "";
                    try {
                        dec = URLDecoder.decode(result, "utf-8");//请将result换成你的请求结果
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        return;
                    }
                    String ret;
                    try {
                        ret = RSA.getRequestToken(dec);
                        Log.d("ret", ret);
                        if (ret!=null) {
                            wapPay(ret);
                        } else {
                           //message
                            return;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        return;
                    }

先做一次urldecode,然后再解析数据:

其中的wapPay方法:

private void wapPay(String token) {
        Map<String, String> sParaTemp = RSA.getBillParamsMap();
        String req_data = "<auth_and_execute_req><request_token>" + token + "</request_token></auth_and_execute_req>";
        sParaTemp.put("req_data", req_data);
        String mysign = RSA.buildRequestMysign(sParaTemp);
        sParaTemp.put("sign", mysign);
        List<NameValuePair> paramspost = generatNameValuePair(sParaTemp);
        String url = "http://wappaygw.alipay.com/service/rest.htm?" + URLEncodedUtils.format(paramspost, "UTF-8");
        webView.loadUrl(url);
    }

好的至此,我们可以看到页面了:

后面的步骤大家就直接看着来把。

时间: 2024-11-29 07:11:21

【android仿系列进阶篇】android 支付宝手机网页支付的相关文章

支付宝手机网页支付

本节主要描写叙述支付宝手机站点支付,开发网址:productId=2013080604609688" target="_blank">https://b.alipay.com/order/productDetail.htm?productId=2013080604609688,光找这个找了半天,呵呵 在网页中部有四个标签页,选择"技术集成",下载集成开发包,里面有相关的技术文档和三种语言的代码演示样例.代码演示样例中差点儿集成了全部的代码逻辑.cli

支付宝手机网页支付即时到账接口

mycncart的前后台均为移动设备方便访问,支付宝方面单独针对移动设备访问网站设立了支付接口,普通的支付宝即时到账接口无法在手机网页上正常支付 本支付插件是支付宝手机网页即时到账接口. 本插件需要解决生成商家公钥和私钥等,以及与支付宝方面的技术接洽,请与我联系获取此免费技术支持. 主要功能: 1. 针对有资格申请支付宝手机网页即时到账的中国国内公司商家设计使用: 2. 可设置最低启用金额; 3. 可设置适用的国家和地区用户; 4. 设定相关订单状态: 5. 当支付款项成功时,支付宝将相关操作异

用MVC做支付宝手机网页支付问题

支付宝支付接口手机网页支付 从官网扒下来的demo阿里做得还是相当不错的,只要参数改正确了基本上都是能跑通,WebForm的没什么大问题,这次要讲的主要是几个要注意的问题,因为是用MVC来做. 1.要确宝手机网页支付开通已经申请通过,具体官网都有介绍. 2.支付宝的同步请求是正常接收到了的,但支付宝支付接口异步通知 AliPaynotify却没有接收到任何返回的信息,这里 支付宝的异步通知其实被 asp.net 的安全机制给拦截了,返回给支付宝的500错误信息是 A potentially da

Android应用开发进阶篇-场景文字识别

由于研究生毕业项目需要完成一个基于移动终端的场景文字识别系统,虽然离毕业尚早,但出于兴趣的缘故,近一段抽时间完成了这样一套系统.基本的架构如下: 客户端:Android应用实现拍摄场景图片,大致划出感兴趣文字区域,通过socket通信上传服务器端识别; 服务器端:Python server进行socket通信监听,连通后调用文字识别引擎(exe可执行程序),将识别结果返回; 下面是系统运行示例图: 1. 客户端 包含两个Activity,: MainActivity主界面如上图左1,选择拍摄后调

快速Android开发系列网络篇之Android-Async-Http

快速Android开发系列网络篇之Android-Async-Http 转:http://www.cnblogs.com/angeldevil/p/3729808.html 先来看一下最基本的用法 AsyncHttpClient client = new AsyncHttpClient(); client.get("http://www.google.com", new AsyncHttpResponseHandler() { @Override public void onSucce

快速Android开发系列网络篇之Retrofit

Retrofit是一个不错的网络请求库,用官方自己的介绍就是: A type-safe REST client for Android and Java 看官网的介绍用起来很省事,不过如果不了解它是怎么实现的也不太敢用,不然出问题了就不知道怎么办了.这几天比较闲就下下来看了一下,了解一下大概实现方法,细节就不追究了.先来看一个官网的例子,详细说明去网官看 简单示例 首先定义请求接口,即程序中都需要什么请求操作 public interface GitHubService { @GET("/use

快速Android开发系列网络篇之Volley

Volley是Google推出的一个网络请求库,已经被放到了Android源码中,地址在这里,先看使用方法 RequestQueue mRequestQueue = Volley.newRequestQueue(context); JsonObjectRequest req = new JsonObjectRequest(URL, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONO

SQL Server调优系列进阶篇(深入剖析统计信息)

前言 经过前几篇的分析,其实大体已经初窥到SQL Server统计信息的重要性了,所以本篇就要祭出这个神器了. 该篇内容会很长,坐好板凳,瓜子零食之类... 不废话,进正题 技术准备 数据库版本为SQL Server2008R2,利用微软的以前的案例库(Northwind)进行分析,部分内容也会应用微软的另一个案例库AdventureWorks 相信了解SQL Server的朋友,对这两个库都不会太陌生. 概念理解 关于SQL Server中的统计信息,在联机丛书中是这样解释的 查询优化的统计信

SQL Server调优系列进阶篇(如何索引调优)

前言 上一篇我们分析了数据库中的统计信息的作用,我们已经了解了数据库如何通过统计信息来掌控数据库中各个表的内容分布.不清楚的童鞋可以点击参考. 作为调优系列的文章,数据库的索引肯定是不能少的了,所以本篇我们就开始分析这块内容,关于索引的基础知识就不打算深入分析了,网上一搜一片片的,本篇更侧重的是一些实战项内容展示,希望通过本篇文章各位看官能在真正的场景中找到合适的解决方法足以. 对于索引的使用,我希望的是遇到问题找到合适的解决方法就可以,切勿乱用!!! 本篇在分析出索引的优越性的同时也将负面影响