用戶使用移動的終端完成對所購買商品或者服務的支付功能;分爲近場支付(藍牙支付,刷卡,滴卡),和遠程支付(網上支付,短信支付)java
都是比較安全.都是大公司的產品.並且這個和金錢以前掛鉤;android
支付不難.由於是第三方平臺的東西.程序員
在客戶端使用第三方平臺的api調用插件完成支付-->調用第三方平臺jar包裏面的方法(集成過程),這一步纔用到支付寶sdkweb
支付方法須要的支付參數算法
MainActivityexpress
public class MainActivity extends Activity { private Button btn_zfb; /** * 支付寶經過hanlder機制發送支付結果出來,這個過程咱們理解爲"同步返回".由於只要支付寶支付成功.客戶端就能夠經過handler收到消息 */ private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) {/* Result result = new Result((String) msg.obj); switch (msg.what) { case RQF_PAY: case RQF_LOGIN: { Toast.makeText(ExternalPartner.this, result.getResult(), Toast.LENGTH_SHORT).show(); } break; default: break; } */ }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initListener(); } private void initView() { btn_zfb = (Button) findViewById(R.id.btn1); } private void initListener() { /** * 支付寶支付 */ btn_zfb.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //1. 選擇商品,把**支付數據**post到後臺server-->發送一個請求 final String goodInfoJsonString = "{\"goodInfos\":[{\"goodCounts\":\"1\",\"goodExtInfo\":{},\"goodIDs\":\"965\",\"goodType\":\"1\"}],\"loginFlag\":\"0\",\"mobile\":\"18682036558\",\"orderId\":\"0\",\"otherInfo\":{\"agentID\":\"0-maizuo\",\"channelID\":\"31\",\"clientID\":\"31\"},\"payDatas\":{\"discountInfo\":{\"activeID\":\"0\",\"discountID\":\"0\",\"discountPrice\":\"\"},\"payInfo\":[{\"bankType\":\"7\",\"payCount\":\"3800\",\"payTicketCount\":\"1\",\"payType\":\"1\"}],\"payPass\":\"\",\"returnUrl\":\"\",\"totalPrice\":\"3800\"},\"processPath\":\"1\",\"sessionKey\":\"chfrlczgtomqsiurzzyo\",\"userID\":\"200394160\"}"; //2.把支付數據post到後臺server-->發送一個請求 new Thread(new Runnable() { @Override public void run() { // TODO try { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost post = new HttpPost( "http://mobileif.maizuo.com/version3/orderform/order?version=2"); post.addHeader("Content-Type", "application/json"); post.setEntity(new StringEntity(goodInfoJsonString)); HttpResponse response = httpClient.execute(post); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity); System.out.println(result);//-->bean-->getAlipayVerifyKey(); //3.在客戶端使用第三方平臺的api調用插件完成支付 //獲取Alipay對象,構造參數爲當前Activity和Handler實例對象 //mHandler就是一會處理咱們支付結果的hanlder AliPay alipay = new AliPay(MainActivity.this, handler); //調用pay方法,將訂單信息傳入 String orderInfo = "_input_charset=\"UTF-8\"&body=\"賣座網電子影票\"&it_b_pay=\"1h\"¬ify_url=\"http%3A%2F%2Fpay.maizuo.com%2FmobileBack.htm\"&out_trade_no=\"201503283783092428\"&partner=\"2088411628331920\"&payment_type=\"1\"&seller_id=\"2088411628331920\"&service=\"mobile.securitypay.pay\"&subject=\"海岸影城(2D通兌票1張)\"&total_fee=\"38.00\"&sign=\"KDhXG0I8T1VZCgg3tfmYbnhF91I6marCQ0yWgmIe1ZGJ9z6MHFwwV7O156%2FkTecKikrIwRnrPNOI%0Ac8h6bUPRX9DIoHF3Yamj1NCi%2B5j0e16uRy5VtyhLFPx608stqjLlaepBsRZYPblyikuts67W9IJ%2B%0AyNrrG8cZ6ltgulZTFH4%3D\"&sign_type=\"RSA\"";//支付串碼 String payResult = alipay.pay(orderInfo); } } catch (Exception e) { e.printStackTrace(); } } }).start(); } }); } // 「00」 – 銀聯正式環境 // 「01」 – 銀聯測試環境,該環境中不發生真實交易 String serverMode = "00"; /** * 銀聯支付 */ public void uupay(View v) { //經過支付請求.拿到支付串碼 String tn = "201503281059506568548"; //發起支付請求 int ret = UPPayAssistEx.startPay(MainActivity.this, null, null, tn, serverMode); if (ret == UPPayAssistEx.PLUGIN_NOT_FOUND) { //安裝Asset中提供的UPPayPlugin.apk // 此處可根據實際狀況,添加相應的處理邏輯 UPPayAssistEx.installUPPayPlugin(this); } } /** * uupay處理支付結果 */ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (data == null) { return; } String str = data.getExtras().getString("pay_result"); String msg = ""; /* * 支付控件返回字符串:success、fail、cancel 分別表明支付成功,支付失敗,支付取消 */ if (str.equalsIgnoreCase("success")) { msg = "支付成功!"; } else if (str.equalsIgnoreCase("fail")) { msg = "支付失敗!"; } else if (str.equalsIgnoreCase("cancel")) { msg = "用戶取消了支付"; } //下面就是進行用戶提示 Toast.makeText(getApplicationContext(), msg, 0).show(); } }
RSA密鑰生成命令json
關鍵方法:api
//經過支付請求.拿到支付串碼 String tn = "201503281059506568548"; //發起支付請求 int ret = UPPayAssistEx.startPay(MainActivity.this, null, null, tn, serverMode); if (ret == UPPayAssistEx.PLUGIN_NOT_FOUND) { //安裝Asset中提供的UPPayPlugin.apk // 此處可根據實際狀況,添加相應的處理邏輯 UPPayAssistEx.installUPPayPlugin(this); }
處理支付結果:在onactivityForResult中處理
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { initData(); if (data == null) { return; } String uupayResult = data.getExtras().getString("pay_result"); Logger.i(TAG, "pay_result:" + uupayResult); if (uupayResult != null && !"".equals(uupayResult)) { Logger.i(TAG, "pay_result:" + uupayResult); Message msg = new Message(); if (uupayResult.equalsIgnoreCase("success")) { msg.what = UUPAYSUCCESS; } else if (uupayResult.equalsIgnoreCase("fail")) { msg.what = UUPAYFAIL; } /*else if (uupayResult.equalsIgnoreCase("cancel")) { msg = "用戶取消了支付"; }*/ handler.sendMessage(msg); } super.onActivityResult(requestCode, resultCode, data); }
微信
關鍵方法:安全
private void sendPayReq(WXPayData info) { api = WXAPIFactory.createWXAPI(this, info.getAppid()); PayReq req = new PayReq(); req.appId = info.getAppid(); req.partnerId = info.getPartnerid(); req.prepayId = info.getPrepayid();//預支付id req.nonceStr = info.getNoncestr();//32位內的隨機串,防重發 req.timeStamp = String.valueOf(info.getTimestamp());//時間戳,爲 1970 年 1 月 1 日 00:00 到請求發起時間的秒數 req.packageValue = info.getPackage1(); req.sign = info.getApp_signature(); // 在支付以前,若是應用沒有註冊到微信,應該先調用IWXMsg.registerApp將應用註冊到微信 api.sendReq(req); }
處理支付結果:在WXPayEntryActivity.java
errCode = resp.errCode; Logger.i(TAG, "微信支付結果:" + String.valueOf(resp.errCode)); if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { /*AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.app_tip); builder.setMessage(getString(R.string.pay_result_callback_msg, String.valueOf(resp.errCode))); builder.show();*/ } Message msg = new Message(); if (errCode == 0) { msg.what = PayActivity.WEIXINPAYSUCCESS; } else { msg.what = PayActivity.WEIXINPAYFAIL; } PayActivity.instance.handler.sendMessage(msg); finish();
安全碼:
數字簽名+";"+包名; 輸入「安全碼」。安全碼的組成規則爲:Android簽名證書的sha1值+「;」+packagename(即:數字簽名+分號+包名),例如: BB:0D:AC:74:D3:21:E1:43:67:71:9B:62:91:AF:A1:66:6E:44:5D:75;com.baidumap.dem服務器
public class PayDemoActivity extends FragmentActivity { // 商戶PID public static final String PARTNER = "2016012501118845"; // 商戶收款帳號 public static final String SELLER = "6225757524716173"; // 商戶私鑰,pkcs8格式 public static final String RSA_PRIVATE = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALTam792ATycFFDXWg6VEQofa3lT4qWkmcyXLnbSZVHV/brDdDNfeHMJWwvsvuJYNxEDZOYL/AA7/WuBLI+KklXhFUnu/NjQWmXzndiQI15Mfq+2TDh1Cf9H7ypUHah8RrcTwaM9H1/SWP7f2o2QOucB2Y/bI4Faq3ISwONXztTvAgMBAAECgYEAjK4cRwOhFKeIehX6XKuB9LDaJielfxoZ9PaI0y74V38w/q15X1jdVgaqBw2ismjSdO6B9xzNatU/XPe/VO0CxHFZ3/5Qhc/b724MsTxGyVC8TMI/oHMgAlVE3cR4/fwj0fhsYUYbSy9yCTqyinpdLZcNkUpMBJaeaM4jQJZvaSECQQDm7TrKPyJ1mgkKZADco+/HzcX1OnLvGtjFnSxD4LUShFfpYW5bWthy+869Jt9iIbOVDkvrfANMKhOuk0sEany/AkEAyH2SUFJUA1r+csi6WDf694npi6gtY0MhcNgGmoVr3g1daWf3cbx81VUE9y4ffqH91mdxWlVMVsCQetNYywdD0QJAAKQsA5/FQrpYyBSbBAHYip+BqzqsUwmqDHJxSwb2ucRwUg+ZNNu9uiQE4PWYrTcWvpU5lL/VaoK7Z0K1dJ+vFQJBAKV78F7X9XxniQqZYCYc3sufS+P4Rq5d5KZNyPWWFvjLs0SjifyZBbjYWibkLR7K+sgTzd4v9bjNbPPUqr+6GWECQAk6JYzWuS8D7ns/JEbI1fuUzm2U8/Q2R60dq7EFtbw+Po1dxZzUJ+V5JhW9exvhrr7lVII/0aB8nv/LUE+2XCo="; // 支付寶公鑰 public static final String RSA_PUBLIC = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB"; private static final int SDK_PAY_FLAG = 1; private static final int SDK_CHECK_FLAG = 2; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SDK_PAY_FLAG: { PayResult payResult = new PayResult((String) msg.obj); /** * 同步返回的結果必須放置到服務端進行驗證(驗證的規則請看https://doc.open.alipay.com/doc2/ * detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665& * docType=1) 建議商戶依賴異步通知 */ String resultInfo = payResult.getResult();// 同步返回須要驗證的信息 String resultStatus = payResult.getResultStatus(); // 判斷resultStatus 爲「9000」則表明支付成功,具體狀態碼錶明含義可參考接口文檔 if (TextUtils.equals(resultStatus, "9000")) { Toast.makeText(PayDemoActivity.this, "支付成功", Toast.LENGTH_SHORT).show(); } else { // 判斷resultStatus 爲非"9000"則表明可能支付失敗 // "8000"表明支付結果由於支付渠道緣由或者系統緣由還在等待支付結果確認,最終交易是否成功以服務端異步通知爲準(小几率狀態) if (TextUtils.equals(resultStatus, "8000")) { Toast.makeText(PayDemoActivity.this, "支付結果確認中", Toast.LENGTH_SHORT).show(); } else { // 其餘值就能夠判斷爲支付失敗,包括用戶主動取消支付,或者系統返回的錯誤 Toast.makeText(PayDemoActivity.this, "支付失敗", Toast.LENGTH_SHORT).show(); } } break; } case SDK_CHECK_FLAG: { Toast.makeText(PayDemoActivity.this, "檢查結果爲:" + msg.obj, Toast.LENGTH_SHORT).show(); break; } default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pay_main); } /** * call alipay sdk pay. 調用SDK支付 * */ public void pay(View v) { if (TextUtils.isEmpty(PARTNER) || TextUtils.isEmpty(RSA_PRIVATE) || TextUtils.isEmpty(SELLER)) { new AlertDialog.Builder(this) .setTitle("警告") .setMessage("須要配置PARTNER | RSA_PRIVATE| SELLER") .setPositiveButton("肯定", new DialogInterface.OnClickListener() { public void onClick( DialogInterface dialoginterface, int i) { // finish(); } }).show(); return; } String orderInfo = getOrderInfo("測試的商品", "該測試商品的詳細描述", "0.01"); /** * 特別注意,這裏的簽名邏輯須要放在服務端,切勿將私鑰泄露在代碼中! */ String sign = sign(orderInfo); try { /** * 僅需對sign 作URL編碼 */ sign = URLEncoder.encode(sign, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } /** * 完整的符合支付寶參數規範的訂單信息 */ final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType(); System.out.println("payInfo===========" + payInfo); Runnable payRunnable = new Runnable() { @Override public void run() { // 構造PayTask 對象 PayTask alipay = new PayTask(PayDemoActivity.this); // 調用支付接口,獲取支付結果 String result = alipay.pay(payInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; // 必須異步調用 Thread payThread = new Thread(payRunnable); payThread.start(); } /** * check whether the device has authentication alipay account. * 查詢終端設備是否存在支付寶認證帳戶 * */ public void check(View v) { Runnable checkRunnable = new Runnable() { @Override public void run() { // 構造PayTask 對象 PayTask payTask = new PayTask(PayDemoActivity.this); // 調用查詢接口,獲取查詢結果 boolean isExist = payTask.checkAccountIfExist(); Message msg = new Message(); msg.what = SDK_CHECK_FLAG; msg.obj = isExist; mHandler.sendMessage(msg); } }; Thread checkThread = new Thread(checkRunnable); checkThread.start(); } /** * get the sdk version. 獲取SDK版本號 * */ public void getSDKVersion() { PayTask payTask = new PayTask(this); String version = payTask.getVersion(); Toast.makeText(this, version, Toast.LENGTH_SHORT).show(); } /** * 原生的H5(手機網頁版支付切natvie支付) 【對應頁面網頁支付按鈕】 * * @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.taobao.com"; // url能夠是一號店或者美團等第三方的購物wap站點,在該網站的支付過程當中,支付寶sdk完成攔截支付 extras.putString("url", url); intent.putExtras(extras); startActivity(intent); } /** * create the order info. 建立訂單信息 * */ 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 + "\""; // 服務器異步通知頁面路徑 orderInfo += "¬ify_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; } /** * 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; } /** * sign the order info. 對訂單信息進行簽名,即加密 * * @param content * 待簽名訂單信息 */ private String sign(String content) { return SignUtils.sign(content, RSA_PRIVATE); } /** * get the sign type we use. 獲取簽名方式 * */ private String getSignType() { return "sign_type=\"RSA\""; } }