zoukankan      html  css  js  c++  java
  • 集成支付宝支付

    集成支付宝支付

     ONE Goal ,ONE Passion!
    

    第一步:正式准备阶段.


    服务端.
    负责生成订单及签名,及接受支付异步通知。
    client
    负责使用服务端传来的订单信息调用支付宝支付接口。及依据SDK同步返回的支付结果展示结果页。

     注意:    私钥必须放在服务端,签名过程必须放在服务端。
    

    第二步,開始接入的准备工作.

    解压接口压缩文件(文件名称是WS_MOBILE_PAY_SDK_BASE.zip)。找到安卓的压缩文件(文件名称是支付宝钱包支付开发包标准版(Android).zip)。标准开发包以jar包方式提供给商户应用project集成。打开alipay-sdk-common文件夹获取alipaySDK-20150602.jar,后8位数字标识公布日期,商户可依据日期时间推断SDK版本号的新旧。

    1, 将alipaySDK-20150602.jar包放入商户应用project的libs文件夹下,例如以下图。

    这里写图片描写叙述

    2,进入商户应用project的Java Build Path,将libs文件夹下的alipaySDK-20150602.jar导入。例如以下图。

    这里写图片描写叙述

    3,选中Order and Export,勾选alipaySDK-20150602.jar。例如以下图。

    这里写图片描写叙述

    改动Manifest

    在商户应用project的AndroidManifest.xml文件中面加入声明:

    <activity
                android:name="你的支付界面(即PayDemoActivity )"
                android:configChanges="orientation|keyboardHidden|navigation"
                android:exported="false"
                android:screenOrientation="behind" >
     </activity>

    权限声明:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    第3步 :支付接口调用

    须要在新线程中调用支付接口。

    (可參考alipay_demo实现) 获取PayTask支付对象调用支付(支付或者授权的行为须要在独立的非ui线程中运行)

    alipay.pay(payInfo, true)方法中payInfo一些參数含义:

    參数 意义
    orderInfo 订单信息—getOrderInfo(“測试的商品”, “该測试商品的具体描写叙述”, “0.01”)返回的数据
    sign 后台给我们的签名(后台就是拿着订单信息进行签名)
    getSignType() “sign_type=”RSA”” (固定值)

    我们的支付activity

    public class PayDemoActivity extends FragmentActivity {
    
        // 商户PID
        public static final String PARTNER = "这些字段我们不写在代码中,而是由server处理";
        // 商户收款账号
        public static final String SELLER = "这些字段我们不写在代码中,而是由server处理";
        // 商户私钥。pkcs8格式
        public static final String RSA_PRIVATE = "这些字段我们不写在代码中,而是由server处理";
        // 支付宝公钥
        public static final String RSA_PUBLIC = "这些字段我们不写在代码中,而是由server处理";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout."你的布局");
        }
    
        /**
         * 点击--调用SDK支付
         *  sign是从后台获得的,由于签名过程涉及一些秘钥之类的,最好不要暴
         *  露在代码中,因此我们让后台对数据处理生成签名后直接给我们.
         */
        public void pay(View v) {
            try {
                /**
                 * 我们仅需对sign 做URL编码
                 */
                sign = URLEncoder.encode(sign, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    
        //完整的符合支付宝參数规范的订单信息
    
            final String payInfo = orderInfo + "&sign="" + sign + ""&" + getSignType();
    
            Runnable payRunnable = new Runnable() {
    
                @Override
                public void run() {
                    // 构造PayTask 对象
                    PayTask alipay = new PayTask(PayDemoActivity.this);
                    // 调用支付接口,获取支付结果
                    String result = alipay.pay(payInfo, true);
    
    //             result中已经有支付结果了,只是为了安全性.我们一般去查询自己公司server接口,从而得到支付结果.然后再做处理
    
                }
            };
    
            // 必须异步调用
            Thread payThread = new Thread(payRunnable);
            payThread.start();
        }
        /**
         * get the sign type we use. 获取签名方式
         * 
         */
        private String getSignType() {
            return "sign_type="RSA"";
        }
    
    }

    对订单信息进行签名——-后台操作

    /**
         * sign the order info. 对订单信息进行签名---后台操作
         * 
         * @param content
         *            待签名订单信息
         */
        private String sign(String content) {
            return SignUtils.sign(content, RSA_PRIVATE);
        }
    /**
     *      签名工具类---后台用,这里仅仅是让我们看看签名算法
     * @author fy
     *
     */
    public class SignUtils {
    
        private static final String ALGORITHM = "RSA";
    
        private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
    
        private static final String DEFAULT_CHARSET = "UTF-8";
    
        public static String sign(String content, String privateKey) {
            try {
                PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                        Base64.decode(privateKey));
                KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
                PrivateKey priKey = keyf.generatePrivate(priPKCS8);
    
                java.security.Signature signature = java.security.Signature
                        .getInstance(SIGN_ALGORITHMS);
    
                signature.initSign(priKey);
                signature.update(content.getBytes(DEFAULT_CHARSET));
    
                byte[] signed = signature.sign();
    
                return Base64.encode(signed);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
    }
    

    生成商户订单号,能够android端也能够server端确定.尽量让server端确定

    /**
         * get the out_trade_no for an order. 生成商户订单号參考方
         * 法,该值
         *  在商户端应保持唯一(可自己定义格式规范)
         */
        private String getOutTradeNo() {
            SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
            Date date = new Date();
            String key = format.format(date);
    
            Random r = new Random();
            key = key + r.nextInt();
            key = key.substring(0, 15);
            return key;//订单号
        }
    

    创建订单信息
    1,商品名称
    2,商品详情
    3,商品金额
    把这些数据传递给后台,后台生产订单信息给你.

    /**
         * create the order info. 创建订单信息
         *   由server生成
         */
        private String getOrderInfo(String subject, String body, String price) {
    
            // 签约合作者身份ID
            String orderInfo = "partner=" + """ + PARTNER + """;
    
            // 签约卖家支付宝账号
            orderInfo += "&seller_id=" + """ + SELLER + """;
    
            // 商户站点唯一订单号
            orderInfo += "&out_trade_no=" + """ + getOutTradeNo() + """;
    
            // 商品名称
            orderInfo += "&subject=" + """ + subject + """;
    
            // 商品详情
            orderInfo += "&body=" + """ + body + """;
    
            // 商品金额
            orderInfo += "&total_fee=" + """ + price + """;
    
            // server异步通知页面路径
            orderInfo += "&notify_url=" + """ + "http://notify.msp.hk/notify.htm" + """;
    
            // 服务接口名称, 固定值
            orderInfo += "&service="mobile.securitypay.pay"";
    
            // 支付类型。 固定值
            orderInfo += "&payment_type="1"";
    
            // 參数编码。 固定值
            orderInfo += "&_input_charset="utf-8"";
    
            // 设置未付款交易的超时时间
            // 默认30分钟。一旦超时,该笔交易就会自己主动被关闭。

    // 取值范围:1m~15d。 // m-分钟,h-小时,d-天,1c-当天(不管交易何时创建,都在0点关闭)。

    // 该參数数值不接受小数点,如1.5h,可转换为90m。 orderInfo += "&it_b_pay="30m""; // extern_token为经过快登授权获取到的alipay_open_id,带上此參数用户将使用授权的账户进行支付 // orderInfo += "&extern_token=" + """ + extern_token + """; // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空 orderInfo += "&return_url="m.alipay.com""; // 调用银行卡支付。需配置此參数。參与签名, 固定值 (须要签约《无线银行卡快捷支付》才干使用) // orderInfo += "&paymethod="expressGateway""; return orderInfo; }

    app支付已经完毕喽!


    假设你们公司已经做出了网页版的支付,并且想直接使用网页版支付那就直接调用webview.

        /**
         * 原生的H5(手机网页版支付切natvie支付) 【相应页面网页支付button】
         * 
         * @param v
         */
        public void h5Pay(View v) {
            Intent intent = new Intent(this, H5PayDemoActivity.class);
            Bundle extras = new Bundle();
            /**
             * url是測试的站点。在app内部打开页面是基于webview打开的,demo中的webview是H5PayDemoActivity,
             * demo中拦截url进行支付的逻辑是在H5PayDemoActivity中shouldOverrideUrlLoading方法实现,
             * 商户能够依据自己的需求来实现
             */
            String url = "http://m.meituan.com";
            // url能够是一号店或者美团等第三方的购物wap站点。在该站点的支付过程中,支付宝sdk完毕拦截支付
            extras.putString("url", url);
            intent.putExtras(extras);
            startActivity(intent);
    
        }
    

    这是调用显示webview的页面.能够依据支付宝提供的H5PayDemoActivity .假设须要的话自己改一下就好了

    @SuppressLint({ "SetJavaScriptEnabled", "InlinedApi" })
    public class H5PayDemoActivity extends Activity {
    
        private WebView mWebView;
    
        @SuppressWarnings("deprecation")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Bundle extras = null;
            try {
                extras = getIntent().getExtras();
            } catch (Exception e) {
                finish();
                return;
            }
            if (extras == null) {
                finish();
                return;
            }
            String url = null;
            try {
                url = extras.getString("url");
            } catch (Exception e) {
                finish();
                return;
            }
            if (TextUtils.isEmpty(url)) {
                // 測试H5支付。必须设置要打开的url站点
                new AlertDialog.Builder(H5PayDemoActivity.this).setTitle("警告")
                        .setMessage("必须配置须要打开的url 站点,请在PayDemoActivity类的h5Pay中配置")
                        .setPositiveButton("确定", new OnClickListener() {
    
                            @Override
                            public void onClick(DialogInterface arg0, int arg1) {
                                finish();
                            }
                        }).show();
    
            }
            super.requestWindowFeature(Window.FEATURE_NO_TITLE);
            LinearLayout layout = new LinearLayout(getApplicationContext());
            LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            layout.setOrientation(LinearLayout.VERTICAL);
            setContentView(layout, params);
    
            mWebView = new WebView(getApplicationContext());
            params.weight = 1;
            mWebView.setVisibility(View.VISIBLE);
            layout.addView(mWebView, params);
    
            WebSettings settings = mWebView.getSettings();
            settings.setUserAgentString(
                    "User-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50");
            settings.setRenderPriority(RenderPriority.HIGH);
            settings.setSupportMultipleWindows(true);
            settings.setJavaScriptEnabled(true);
            settings.setSavePassword(false);
            settings.setJavaScriptCanOpenWindowsAutomatically(true);
            settings.setMinimumFontSize(settings.getMinimumFontSize() + 8);
            settings.setAllowFileAccess(false);
            settings.setTextSize(WebSettings.TextSize.NORMAL);
            mWebView.setVerticalScrollbarOverlay(true);
            mWebView.setWebViewClient(new MyWebViewClient());
            mWebView.loadUrl(url);
        }
    
        @Override
        public void onBackPressed() {
            if (mWebView.canGoBack()) {
                mWebView.goBack();
            } else {
                finish();
            }
        }
    
        @Override
        public void finish() {
            super.finish();
        }
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
        }
    
        private class MyWebViewClient extends WebViewClient {
    
            @Override
            public boolean shouldOverrideUrlLoading(final WebView view, String url) {
                final PayTask task = new PayTask(H5PayDemoActivity.this);
                final String ex = task.fetchOrderInfoFromH5PayUrl(url);
                if (!TextUtils.isEmpty(ex)) {
                    new Thread(new Runnable() {
                        public void run() {
                            H5PayResultModel result = task.h5Pay(ex, true);
                            if (!TextUtils.isEmpty(result.getReturnUrl())) {
                                view.loadUrl(result.getReturnUrl());
                            }
                        }
                    }).start();
                } else {
                    view.loadUrl(url);
                }
                return true;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mWebView != null) {
                mWebView.removeAllViews();
                try {
                    mWebView.destroy();
                } catch (Throwable t) {
                }
                mWebView = null;
            }
        }
    }
    

    最后:支付结果获取和处理

    
                    String result = alipay.pay(payInfo, true);
    
    //             result中已经有支付结果了,只是为了安全性.我们一般去查询自己公司server接口(能够轮询),从而得到支付结果.然后再做处理.....

    另附:正确的请求參数,以及返回数据

    1,—–payInfo字符串格式。形式一般例如以下:

    partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測试"&body="測试測试"&total_fee="0.01"&notify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&sign="lBBK%2F0w5LOajrMrji7DUgEqNjIhQbidR13GovA5r3TgIbNqv231yC1NksLdw%2Ba3JnfHXoXuet6XNNHtn7VE%2BeCoRO1O%2BR1KugLrQEZMtG5jmJIe2pbjm%2F3kb%2FuGkpG%2BwYQYI51%2BhA3YBbvZHVQBYveBqK%2Bh8mUyb7GM1HxWs9k4%3D"&sign_type="RSA"

    2,—–返回值,字符串格式,形式一般例如以下
    当然我们不必參考这个返回值.我们仅仅关心自己后台返回值即可了.

    resultStatus={9000};memo={};result={partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="測试"&body="測试測试"&total_fee="0.01"&notify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&success="true"&sign_type="RSA"&sign="hkFZr+zE9499nuqDNLZEF7W75RFFPsly876QuRSeN8WMaUgcdR00IKy5ZyBJ4eldhoJ/2zghqrD4E2G2mNjs3aE+HCLiBXrPDNdLKCZgSOIqmv46TfPTEqopYfhs+o5fZzXxt34fwdrzN4mX6S13cr3UwmEV4L3Ffir/02RBVtU="}

    说明:

    返回结果须要通过resultStatus以及result字段的值来综合推断并确定支付结果。

    在resultStatus=9000,并且success=“true”以及sign=“xxx”校验通过的情况下,证明支付成功。其他情况归为失败。较低安全级别的场合。也能够仅仅通过检查resultStatus以及success=“true”来判定支付结果。

    Android平台和iOS平台的返回结果串唯一不同之处是resultStatus这个key,在iOS的返回结果串中原始的数据是ResultStatus(为了兼容历史版本号首字母大写),Android平台是resultStatus

    最终搞定了.其有用起来非常easy.就是怕有的童鞋不明确所以写了这么多.希望对正在写支付宝开发的童鞋有一点点帮助.
  • 相关阅读:
    sqlsever中生成GUID的方法
    部署项目到服务器
    读后感
    第二次作业
    课堂作业
    第一次作业 开发环境配置介绍
    第二次结对作业
    代码审查
    最大连续子数组和
    单元测试
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7294927.html
Copyright © 2011-2022 走看看