Android微信支付功能整合【全攻略】
遵循:BY-SA
作者:譚東
時間:2016年10月28日
環境:Windows 7
Android版微信支付官方文件和Demo問題很多,官方也沒有及時更新和細化開發整合文件。
這裡分享我整合Android客戶端微信支付的思路和部分程式碼。希望對大家有幫助。
遇到的問題無非以下幾種:
1、提示簽名不對;
2、打包簽名後的APK無法調起微信支付客戶端,直接返回回撥頁;
3、不支援中文的Body;
4、支付的錢倍數不對,因為微信的單位是分;
... ...
首先,本文針對的是最新版微信Android支付SDK3.1.1寫的,大家可以放心使用。
首先,把WXPayEntryActivity.java複製到我們的包名下的.wxapi目錄下,要一致。
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
WXPayEntryActivity.java官方Demo裡有,我這裡也複製一份我的,僅供參考。
public class WXPayEntryActivity extends BaseActivity implements IWXAPIEventHandler { private IWXAPI api; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); api = WXAPIFactory.createWXAPI(this, Conf.APP_ID); api.handleIntent(getIntent(), this); getSupportActionBar().setIcon(R.drawable.logo_gray); getSupportActionBar().setTitle("購買積分"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); Drawable dw = getResources().getDrawable(R.drawable.color_bg); getSupportActionBar().setBackgroundDrawable(dw); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { this.finish(); } return super.onOptionsItemSelected(item); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq baseReq) { } @Override public void onResp(BaseResp baseResp) { if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { Log.d("info", "onPayFinish,errCode=" + baseResp.errCode); if (baseResp.errCode == 0) { ToastUtil.showToast(this, "支付成功"); Intent intent = new Intent("ACTION_PAY"); sendBroadcast(intent); this.finish(); } else if (baseResp.errCode == -1) { ToastUtil.showToast(this, "配置錯誤"); this.finish(); } else if (baseResp.errCode == -2) { ToastUtil.showToast(this, "使用者取消"); this.finish(); } } else { ToastUtil.showToast(this, baseResp.errStr); } } }
這裡說一下Android微信支付流程,這裡本地客戶端都處理了所有的流程。
客戶端把所有需要的資訊拼接為XML後,統一下單,傳送給微信伺服器API請求,獲取訂單id,也就是prepayId。獲取到這個prepayId後,我們再把必要的資料欄位sign簽名MD5後,調起微信支付客戶端就可以了。比支付寶麻煩很多。
1、在程式的啟動頁,例如歡迎頁就可以註冊微信API的ID了。
IWXAPI msgApi = WXAPIFactory.createWXAPI(this, Conf.APP_ID);
msgApi.registerApp(Conf.APP_ID);
完畢。
2、接下來處理微信POST請求的必要引數的拼接和加密等處理。寫PayActivity.java
把必填的引數處理下:
nonce_str:隨機字串,不長於32位。
out_trade_no:商戶系統內部的訂單號,32個字元內、可包含字母。
spbill_create_ip:使用者端實際ip,16位,可寫固定值。
notify_url:暫時寫成固定的,http://www.weixin.qq.com/wxpay/pay.php。
最麻煩的,sign:32位簽名,參照簽名生成演算法。
以上這些演算法我都會寫成工具類,供大家參考。
簽名演算法:
附上整個支付程式碼:
PayActivity.java裡關於支付的程式碼:
private IWXAPI api;
private String stringA;
private String noneString;
private String out_trade_no;
private String sign;
private String prepayId;
private String ip;
private String body = "商品-積分充值";
private static final String order_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//POST請求統一下單介面地址
private String notify_url = "http://www.weixin.qq.com/wxpay/pay.php";
private String entity;//XML形式的post請求實體
private void payWeixin(int money) {
api = WXAPIFactory.createWXAPI(this, Conf.APP_ID);
try {
body = new String(body.getBytes(), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
noneString = Utils.createRandomString(true, 32);//32位隨機字串
out_trade_no = Utils.createRandomString(true, 20) + Utils.timeStamp();//30位內部隨機訂單號
ip = "123.123.123.123";
stringA = "appid=" + Conf.APP_ID + "&body=" + body + "&mch_id=" + Conf.MCH_ID + "&nonce_str=" + noneString + "¬ify_url=" + notify_url + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + ip + "&" +
"total_fee=" + money + "&trade_type=APP";
String stringSignTemp = stringA + "&key=" + Conf.KEY;
sign = Utils.getMD5(stringSignTemp).toUpperCase(Locale.getDefault());
entity = "<xml><appid>" + Conf.APP_ID + "</appid><mch_id>" + Conf.MCH_ID + "</mch_id><nonce_str>" + noneString + "</nonce_str><sign>" + sign +
"</sign><body>" + body + "</body><out_trade_no>" + out_trade_no + "</out_trade_no><total_fee>" + money +
"</total_fee><spbill_create_ip>" + ip + "</spbill_create_ip><notify_url>" + notify_url + "</notify_url><trade_type>APP</trade_type></xml>";
try {
entity = new String(entity.getBytes(), "ISO8859-1");//想要支援中文的Boby,那就要把XML轉碼為ISO8859-1即可
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
try {
byte[] buf = Utils.httpPost(order_url, entity);
Message message = new Message();
message.what = 0;
message.obj = buf;
handler.sendMessage(message);
} catch (Exception e) {
Log.e("info", "異常:" + e.getMessage());
}
}
}).start();
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
byte[] buf = (byte[]) msg.obj;
if (buf != null && buf.length > 0) {
String content = new String(buf);
OrderResult orderResult = Tools.parseXml(new ByteArrayInputStream(content.getBytes()));
if (!TextUtils.equals(orderResult.getReturnCode(), "SUCCESS")) {
Toast.makeText(PayActivity.this, orderResult.getReturnMsg(), Toast.LENGTH_SHORT).show();
return;
}
if (!TextUtils.equals(orderResult.getResultCode(), "SUCCESS")) {
Toast.makeText(PayActivity.this, orderResult.getErrorDesc(), Toast.LENGTH_SHORT).show();
return;
}
PayReq req = new PayReq();
req.appId = Conf.APP_ID;
req.partnerId = Conf.MCH_ID;
req.prepayId = orderResult.getPrepayId();
req.packageValue = "Sign=WXPay";
req.nonceStr = noneString;
String timeStamp = Utils.timeStamp();
req.timeStamp = timeStamp;
req.sign = Utils.getMD5("appid=" + Conf.APP_ID + "&noncestr=" + noneString + "&package=Sign=WXPay" +
"&partnerid=" + Conf.MCH_ID + "&prepayid=" + orderResult.getPrepayId() + "×tamp=" + timeStamp + "&key=" + Conf.KEY).toUpperCase(Locale.getDefault());
api.sendReq(req);
} else {
Log.d("PAY_GET", "伺服器請求錯誤");
Toast.makeText(PayActivity.this, "伺服器請求錯誤", Toast.LENGTH_SHORT).show();
}
break;
}
}
};
Utils工具類程式碼:
public class Utils {
/**
* 產生隨機字串
*
* @param numberFlag 是否允許有字母
* @param length 隨機字串長度
* @return 隨機字串
*/
public static String createRandomString(boolean numberFlag, int length) {
String retStr = "";
String strTable = numberFlag ? "1234567890" : "1234567890abcdefghijkmnpqrstuvwxyz";
int len = strTable.length();
boolean bDone = true;
do {
retStr = "";
int count = 0;
for (int i = 0; i < length; i++) {
double dblR = Math.random() * len;
int intR = (int) Math.floor(dblR);
char c = strTable.charAt(intR);
if (('0' <= c) && (c <= '9')) {
count++;
}
retStr += strTable.charAt(intR);
}
if (count >= 2) {
bDone = false;
}
} while (bDone);
return retStr;
}
/**
* 獲取MD5加密後的字串
*
* @param val 待加密字串
* @return 加密後字串
*/
public static String getMD5(String val) {
byte[] m = new byte[0];
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(val.getBytes());
m = md5.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return getString(m);
}
private static String getString(byte[] b) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
sb.append(b[i]);
}
return sb.toString();
}
/**
* 獲取10位長度的時間戳
*
* @return 10位時間戳
*/
public static String timeStamp() {
String time = String.valueOf(System.currentTimeMillis());
return time.substring(0, 10);
}
public static byte[] httpGet(final String url) {
if (url == null || url.length() == 0) {
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse resp = httpClient.execute(httpGet);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] httpPost(String url, String entity) {
if (url == null || url.length() == 0) {
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
httpPost.setEntity(new StringEntity(entity));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = httpClient.execute(httpPost);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
public static OrderResult parseXml(InputStream is) {
XmlPullParser parser = Xml.newPullParser();
OrderResult orderResult = null;
try {
parser.setInput(is, "UTF-8");
int type = parser.getEventType();
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
if (parser.getName().equals("xml")) {
orderResult = new OrderResult();
} else if (parser.getName().equals("return_code")) {
orderResult.setReturnCode(parser.nextText());
} else if (parser.getName().equals("return_msg")) {
orderResult.setReturnMsg(parser.nextText());
} else if (parser.getName().equals("result_code")) {
orderResult.setResultCode(parser.nextText());
} else if (parser.getName().equals("err_code_des")) {
orderResult.setErrorDesc(parser.nextText());
} else if (parser.getName().equals("prepay_id")) {
orderResult.setPrepayId(parser.nextText());
} else if (parser.getName().equals("sign")) {
orderResult.setSign(parser.nextText());
}
break;
case XmlPullParser.END_TAG:
break;
}
type = parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return orderResult;
}
}
這樣整個微信Android支付整合就完畢了。
相關推薦
Android微信支付功能整合【全攻略】
遵循:BY-SA 作者:譚東 時間:2016年10月28日 環境:Windows 7 Android版微信支付官方文件和Demo問題很多,官方也沒有及時更新和細化開發整合文件。 這裡分享我整合Android客戶端微信支付的思路和部分程式碼。希望對大家有幫
Android微信分享功能整合開發指南(這一篇就夠了)
前言 本文介紹的只是微信開發中的一個功能,分享。看到網上很多關於微信分享的部落格、帖子,說實話,沒幾篇寫的全的,很多都是複製貼上,介紹的也不全,缺少程式碼的分析,關鍵性的程式碼總是漏一句兩句,看著就很難受。所以,在這裡我打算寫一篇關於微信分享的部落格,總結一下
幹貨:微信營銷引流方法全攻略
同時 線下 網站發布 有一個 nag 消費 ffffff 分享圖片 傳統 很多人問我有沒有快速加粉絲的方法,經過幾天的總結整理,整理出如下多種微信營銷免費快速加粉秘籍,希望對大家有幫助,請切記,無論那一種方法只要你執行力好都會起到很好的效果。方法不在於多,而在於極致,一定要
縱橫開闔-微信小程式之通訊錄全攻略
Create by jsliang on 2018-11-21 20:46:36 Recently revised in 2018-11-25 00:24:14 Hello 小夥伴們,如果覺得本文還不錯,記得給個 star , 你們的 star 是我學習的動力!GitHub 地址 開
【轉】微信小程序實現微信支付功能(可用)
arr 必須 enc red use sam func 結束 單表 原博: https://blog.csdn.net/fredrik/article/details/79697963 微信小程序實現微信支付功能 直接把裏面的參數替換成你的就
Android支付寶 微信支付 簡單整合
最近專案需求 改版了支付方式,支付寶 微信都切換了 海外版,還集成了paypal,前幾天隨手記錄了一下paypal的整合,今天 整理一下 支付寶 和微信的,支付寶 微信 賬戶申請 應用建立就不說了,截圖太麻煩,這裡只貼 一些 關鍵程式碼片段,假設 支付寶 微信 賬號申請
整合ping++支付寶微信支付功能遇到的坑
1、匯入官方專案時,不能像常規那樣匯入專案時,刪掉一些資料夾,更改檔案中版本,什麼都不改,直接開啟即 可。錯誤時,android studio會報錯:android studio error: style attribute ‘@android:attr/windowEnterAni
關於android微信支付 和 支付寶支付的整合
最近專案中要整合微信和支付寶支付 在沒有接觸支付之間 覺得還是比較難的 但真正去實現的時候還是比較簡單的 就是有不少坑要去踩過之後才知道 支付寶支付 : 對於支付寶支付 我個人理解還是比較簡單的 https://open.alipay.com/platform/home.h
Android微信支付整合和踩過的坑
近公司需要微信支付,所以不得不去看看微信支付文件。但是你懂得,那文件寫的真帶勁,看不懂。我直接放棄,開始整合。但是調起微信支付的時候:結果碼為-1,心裡一驚,肯定哪裡錯了,就開始找坑。所以把自己解決的過程分享給大家,讓整合微信支付成為很容易的一件事。 2、我們需要的資源
Android 微信支付整合重點(已經看過官方開發文件)
整合微信支付重點,適用於有整合經驗並且已經看過開發文件的同學 1.申請開通 按照官方文件步驟 (註冊平臺賬號——認證(300 如果失敗3次需再付300認證,資訊提前確認)——建立應用稽核(簽名用微信的提取工具)——開通支付功能——整合) 2.整合
android H5呼叫微信支付功能之坑慘了
一路過關一路坑,1:微信開發平臺在建立應用時跟debug和release 包沒什麼關係,主要看的是包名、簽名、APP ID、商戶ID、金鑰、訂單號、隨機時間msgApi = WXAPIFactory.createWXAPI(this, "APP ID"); msgApi.re
Android微信支付整合流程及其常見錯誤
[支付寶整合傳送門:http://blog.csdn.net/hx7013/article/details/61476320] 一、你需要關心的東西 1.申請與認證 2.上傳金鑰(商戶KEY),包名和簽名的修改 3.服務端整合 4
H5調起微信支付功能
需要 con 返回 alert list 訂單 團隊 eve window 第一步:需要後端返回需要的以下參數: 該操作是你提交完訂單信息後在接口所返回的json, 其次將其存儲起來,我用的localStorage var payParams = {
微信支付功能
and ini edm this substring pac pfx inpu code js wx.request({ url: url + ‘/team!jfchongzhi.action?openid=‘ + openid + ‘&weibi
spring boot項目之微信支付功能實現詳細介紹
tab 流程 invalid body 正方形 無法 數據 fmt -s 對接微信支付功能主要有以下幾個步驟, 而其第一個關鍵點就是獲取OpenID,在這裏介紹兩種獲取方式: 一、微信授權 微信網頁授權 如果用戶在微信客戶端中訪問第三方網頁,公
微信小程序 使用微信支付功能實現在線支付訂單
navi order lose ray 如果 image 全部 extern base 以前做過PC頁面微信支付,但是這次在小程序 直接調用微信支付功能還是方便很多 先放個微信官方API鏈接:https://pay.weixin.qq.com/wiki/doc/api/wx
PHP實現 APP端微信支付功能
1.我封裝好的一個支付類檔案,多餘的東西都去除掉了,並且把配置引數放到了這個支付類中,只需要修改Weixinpayandroid方法內的幾個引數就可以直接複製使用: class Wxpayandroid { //引數配置 public $config = array( 'appid' =&
Android 微信支付的統一下單
準備工作 申請微信開發者賬號,新增應用及申請開通微信支付功能,如 檢視開通流程 統一下單的介面文件: 檢視介面 開發 ①下載sdk: sdk和demo下載 ②可以匯入包 在build.gradle檔案中,新增如下依賴即可: depende
微信支付功能實現
< view class= "container"> < input type= "text" bindinput= "getOrderCode" style= "border:1px solid #ccc;"
android 微信支付,body為中文字元,簽名錯誤
微信支付訂單生產方法: /** * 根據您的訂單資訊 生成 微信產品支付訂單資訊 */ private String createWeChatOrder() { StringBuffer xml = new StringBuffer();