一、導入Demo中須要用到的Jar包html
二、配置AndroidManifest.xml(這裏直接放經常使用的權限)java
<!--所需權限--> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_LOGS" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <!--廣播跳轉--> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!--百度地圖--> <!--百度地圖權限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!--Mob分享--> <uses-permission android:name="android.permission.GET_TASKS" /> <!-- 短信驗證登錄功能須要添加次權限來自動填充驗證碼,用不到能夠去掉 --> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS" /> <!--微信支付權限--> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!--支付寶支付權限--> <!-- 安卓讀寫sd權限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
支付回調android
<!--支付寶支付--> <!-- 支付寶H5頁面支付用的 --> <activity android:name="com.alipay.sdk.app.H5PayActivity" android:configChanges="orientation|keyboardHidden|navigation" android:exported="false" android:screenOrientation="behind" /> <!-- 支付寶App支付頁面用的 --> <activity android:name="com.alipay.sdk.auth.AuthActivity" android:configChanges="orientation|keyboardHidden|navigation" android:exported="false" android:screenOrientation="behind" />
三、請求後臺接口拿到簽過名的信息(appKey,訂單信息等等),這裏我獲取數據,是直接給後臺傳遞的商品id,若是有的須要商品數量直接給傳給後臺,後臺根據id查詢出商品的信息,而後返回給前臺所須要的支付參數。ios
支付寶返回參數用例(開始集成的時候看過好多博客都沒有返回參數數據結構,結果一臉懵逼,在這裏貼出,未加密以前的0.0):express
格式化後的:json
{ "msg":"success", "code":200, "data":"alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=大家申請的app_id&biz_content=%7B%22out_trade_no%22%3A%22HY201806210002%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22%E4%BC%98%E9%93%BA%E4%BC%9A%E5%91%98%E6%9C%8D%E5%8A%A1%E8%B4%B9%22%2C%22total_amount%22%3A%220.01%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2F大家的回調地址%2FaliPayCallBack%2FcallBack&sign=buipaoj2F8xl5XCAUVoJz%2Fbh8dHbaoRmdzoAEzqKRJqtZATT4bfFdzSHurAAL5C5gvntFrDTGHgNRGw%2BNZBtG4DfetOzcpHMAyjslrmUIMIr1YGC7Qya04mFBCh%2B0UIa1E7RISZWSbIVCHpZISknNgF2oTuTixNosXvDXzkGYGBUoaxdh1f6%2F%2Bw9lqKz7mkhsUc0x8lCeJHw4MnTS4gSLU%2BDmOCk6Tkiwb4Yv4Mz%2F6j7XReeagfX7qxs5qbObnnPX%2FFmu9T%2BF0LwJaPxr5Xys8kr8E4bhd4f7Y5FimXiw%2BG7EFkY0I69boiRob7zo%2BbWQ%2F53TAMeTXX5RJybEdXhrA%3D%3D&sign_type=RSA2×tamp=2018-06-21+14%3A11%3A40&version=1.0", "status":"0" }
後臺返回信息以後接下來就是咱們的事情了,調起支付寶進行支付api
/*支付寶測試*/ private void testZfbPay(final String key, final String value) { StringRequest stringRequest = new StringRequest(Request.Method.POST, NetWorkUrl.ZFBPAY, new Response.Listener<String>() { @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onResponse(String s) { Log.e("GoPayOrderActivity", "-------getJson2-------" + s.toString()); /*判斷code*/ String code = (JSONObject.parseObject(s.toString()).getString("code")); if (code.equals("200")) { String orderInfo = (JSONObject.parseObject(s.toString()).getString("data"));//返回的信息 MyALipayUtils.ALiPayBuilder builder = new MyALipayUtils.ALiPayBuilder(); builder.build().toALiPay(GoPayOrderActivity.this, orderInfo); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } }) { @Override public Map<String, String> getParams() throws AuthFailureError { Log.e("GoPayOrderActivity", "getParams:-----------------> " + userEntity.getPhone()); Map<String, String> map = new HashMap<String, String>(); map.put("account", userEntity.getPhone()); map.put(key, value); map.put("token", userEntity.getToken()); return map; } @Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<String, String>(); if (userEntity.getToken().equals("") && userEntity != null) { headers.put("Authorization", userEntity.getToken()); } return headers; } }; /*設置請求一次*/ stringRequest.setRetryPolicy( new DefaultRetryPolicy( 5000,//默認超時時間,應設置一個稍微大點兒的,例如本處的500000 DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默認最大嘗試次數 DefaultRetryPolicy.DEFAULT_BACKOFF_MULT ) ); AppApplication.getHttpQueues().add(stringRequest);/*請求數據*/ }
MyALipayUtils.java這個類直接copy使用就能夠微信
/** * Created by dingchao on 2018/3/20. */ public class MyALipayUtils { private static final int SDK_PAY_FLAG = 1; private Activity context; private ALiPayBuilder builder; private MyALipayUtils(ALiPayBuilder builder) { this.builder = builder; } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { // 返回碼 含義 // 9000 訂單支付成功 // 8000 正在處理中,支付結果未知(有可能已經支付成功),請查詢商戶訂單列表中訂單的支付狀態 // 4000 訂單支付失敗 // 5000 重複請求 // 6001 用戶中途取消 // 6002 網絡鏈接出錯 // 6004 支付結果未知(有可能已經支付成功),請查詢商戶訂單列表中訂單的支付狀態 // 其它 其它支付錯誤 PayResult payResult = new PayResult((Map<String, String>) msg.obj); switch (payResult.getResultStatus()) { case "9000": MobclickAgent.onEvent(context, "payment_success", "付款成功"); Toast.makeText(context, "支付成功", Toast.LENGTH_SHORT).show(); AppApplication.finishActivity(); context.finish(); // Toast.makeText(this, "支付成功", Toast.LENGTH_SHORT).show(); /*跳轉個人會員頁面*/ // Intent intent = new Intent(context, MyVipActivity.class); // context.startActivity(intent); break; case "8000": Toast.makeText(context, "正在處理中", Toast.LENGTH_SHORT).show(); break; case "4000": MobclickAgent.onEvent(context, "payment_fali", "付款失敗"); Toast.makeText(context, "訂單支付失敗", Toast.LENGTH_SHORT).show(); break; case "5000": Toast.makeText(context, "重複請求", Toast.LENGTH_SHORT).show(); break; case "6001": Toast.makeText(context, "已取消支付", Toast.LENGTH_SHORT).show(); break; case "6002": Toast.makeText(context, "網絡鏈接出錯", Toast.LENGTH_SHORT).show(); break; case "6004": Toast.makeText(context, "正在處理中", Toast.LENGTH_SHORT).show(); break; default: MobclickAgent.onEvent(context, "payment_fali", "付款失敗"); Toast.makeText(context, "支付失敗", Toast.LENGTH_SHORT).show(); break; } } }; /** * 簽名發在客戶端來作。 * * @param context */ public void toALiPay(final Activity context) { this.context = context; boolean rsa2 = (builder.getRsa2().length() > 0); Map<String, String> params = buildOrderParamMap(rsa2); String orderParam = buildOrderParam(params); String privateKey = rsa2 ? builder.getRsa2() : builder.getRsa(); String sign = getSign(params, privateKey, rsa2); final String orderInfo = orderParam + "&" + sign; Log.e("chx", "toALiPay: " + orderInfo); Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(context); Map<String, String> result = alipay.payV2 (orderInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); } /** * 簽名在服務端來作 * * @param context * @param orderInfo */ public void toALiPay(final Activity context, final String orderInfo) { this.context = context; Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(context); Map<String, String> result = alipay.payV2 (orderInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; Thread payThread = new Thread(payRunnable); payThread.start(); } /** * 構造支付訂單參數列表 * * @param * @param * @return */ private Map<String, String> buildOrderParamMap(boolean rsa2) { Map<String, String> keyValues = new HashMap<String, String>(); keyValues.put("app_id", builder.appid); keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\"" + builder.money + "\",\"subject\":\"" + builder.title + "\",\"out_trade_no\":\"" + builder.orderTradeId + "\"}"); keyValues.put("charset", "utf-8"); keyValues.put("method", "alipay.trade.app.pay"); //回調接口 keyValues.put("notify_url", builder.getNotifyUrl()); keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA"); // keyValues.put("timestamp", "2016-07-29 16:55:53"); keyValues.put("timestamp", getCurrentTimeString()); keyValues.put("version", "1.0"); return keyValues; } /** * 構造支付訂單參數信息 * * @param map 支付訂單參數 * @return */ private String buildOrderParam(Map<String, String> map) { List<String> keys = new ArrayList<String>(map.keySet()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < keys.size() - 1; i++) { String key = keys.get(i); String value = map.get(key); sb.append(buildKeyValue(key, value, true)); sb.append("&"); Log.e("chx", "buildOrderParam: " + buildKeyValue(key, value, true)); } String tailKey = keys.get(keys.size() - 1); String tailValue = map.get(tailKey); sb.append(buildKeyValue(tailKey, tailValue, true)); return sb.toString(); } /** * 對支付參數信息進行簽名 * * @param map 待簽名受權信息 * @return */ private String getSign(Map<String, String> map, String rsaKey, boolean rsa2) { List<String> keys = new ArrayList<String>(map.keySet()); // key排序 Collections.sort(keys); StringBuilder authInfo = new StringBuilder(); for (int i = 0; i < keys.size() - 1; i++) { String key = keys.get(i); String value = map.get(key); authInfo.append(buildKeyValue(key, value, false)); authInfo.append("&"); } String tailKey = keys.get(keys.size() - 1); String tailValue = map.get(tailKey); authInfo.append(buildKeyValue(tailKey, tailValue, false)); String oriSign = sign(authInfo.toString(), rsaKey, rsa2); String encodedSign = ""; try { encodedSign = URLEncoder.encode(oriSign, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return "sign=" + encodedSign; } private static final String ALGORITHM = "RSA"; private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; private static final String DEFAULT_CHARSET = "UTF-8"; private String getAlgorithms(boolean rsa2) { return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS; } private String sign(String content, String privateKey, boolean rsa2) { 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(getAlgorithms(rsa2)); signature.initSign(priKey); signature.update(content.getBytes(DEFAULT_CHARSET)); byte[] signed = signature.sign(); return Base64.encode(signed); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 拼接鍵值對 * * @param key * @param value * @param isEncode * @return */ private String buildKeyValue(String key, String value, boolean isEncode) { StringBuilder sb = new StringBuilder(); sb.append(key); sb.append("="); if (isEncode) { try { sb.append(URLEncoder.encode(value, "UTF-8")); } catch (UnsupportedEncodingException e) { sb.append(value); } } else { sb.append(value); } return sb.toString(); } /** * 獲取當前日期字符串 * * @return */ private String getCurrentTimeString() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return df.format(new Date()); } public static class ALiPayBuilder { private String rsa2 = ""; private String rsa = ""; private String appid; private String money; private String title; private String notifyUrl; private String orderTradeId; public MyALipayUtils build() { return new MyALipayUtils(this); } public String getOrderTradeId() { return orderTradeId; } public ALiPayBuilder setOrderTradeId(String orderTradeId) { this.orderTradeId = orderTradeId; return this; } public String getRsa2() { return rsa2; } public ALiPayBuilder setRsa2(String rsa2) { this.rsa2 = rsa2; return this; } public String getRsa() { return rsa; } public ALiPayBuilder setRsa(String rsa) { this.rsa = rsa; return this; } public String getAppid() { return appid; } public ALiPayBuilder setAppid(String appid) { this.appid = appid; return this; } public String getMoney() { return money; } public ALiPayBuilder setMoney(String money) { this.money = money; return this; } public String getTitle() { return title; } public ALiPayBuilder setTitle(String title) { this.title = title; return this; } public String getNotifyUrl() { return notifyUrl; } public ALiPayBuilder setNotifyUrl(String notifyUrl) { this.notifyUrl = notifyUrl; return this; } } }
完成上述操做,你的app在螞蟻金服後臺應用上線以後,就徹底能夠調用支付了,可是在開發階段,應用沒有上線,你是不能進行調試的,因此支付寶有沙箱模式能夠進行調試,ios沒有喲網絡
進行沙箱調試在Activity的的onCreate()方法中添加數據結構
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);//支付寶沙箱環境,正式需註釋
別忘了讓大家後臺把appKey等信息換成沙箱的,而後測試支付的時候,須要下載一個沙箱支付寶,這個你能夠隨意支付,附上連接
沙箱首頁:https://sandbox.alipaydev.com/user/accountDetails.htm?currentBar=1
App支付接入文檔:https://docs.open.alipay.com/204/105051
沙箱錢包下載:
調試都沒有問題以後,就能夠在螞蟻金服開發者平臺進行應用上線,而後沙箱代碼就能夠註釋了,這樣支付寶支付就接入完成
若是問題或建議請發送到個人郵箱:dingchao7323@qq.com