1.我们看官方文档的步骤
APP端开发步骤: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
在微信开放平台(https://open.weixin.qq.com)上申请开发应用,管理中心-->创建移动应用,
需要填写资料信息,审核时间大概7个工作日。
审核通过后,微信开放平台会生成APP的唯一标识AppID和AppSecret(要保存好);
在应用详情中有获得微信支付能力选项,我们可以去申请开通,开通后微信会给我们微信支付商户平台的账号和密码
登录地址:https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F
我们可以看 https://jingyan.baidu.com/article/75ab0bcbbf7034d6864db2c3.html,微信支付商户平台-配置密钥。
由此我们在开发过程中需要的三个东西:AppID、商户平台账号MCH_ID、商户密钥API_KEY都有了;
签名工具下载地址https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk
创建请求微信统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
返回结果model
public class WXPrepareModel {
private String return_code;
private String return_msg;
private String appid;
private String mch_id;
private String nonce_str;
private String sign;
private String result_code;
private String prepay_id;
private String trade_type;
public String getReturn_code() {
return return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResult_code() {
return result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getPrepay_id() {
return prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
@Override
public String toString() {
return "WXPrepareModel{" +
"return_code='" + return_code + '\'' +
", return_msg='" + return_msg + '\'' +
", appid='" + appid + '\'' +
", mch_id='" + mch_id + '\'' +
", nonce_str='" + nonce_str + '\'' +
", sign='" + sign + '\'' +
", result_code='" + result_code + '\'' +
", prepay_id='" + prepay_id + '\'' +
", trade_type='" + trade_type + '\'' +
'}';
}
}
public class WXPayManager {
// MARK: - 微信参数配置
public static String API_KEY = ""; // 商户秘钥
public static String MCH_ID = ""; // 商户id
public static String APPID = "";
// 微信支付成功后向咱们后台的,回调地址
public static String WXNotify_url = "";
// MARK: - 随机字符串生成
public static String getRandomString(int length) {
//length表示生成字符串的长度
String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
// MARK: - 请求xml组装
public static String getRequestXml(SortedMap parameters){
StringBuffer sb = new StringBuffer();
sb.append("");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String key = (String)entry.getKey();
String value = (String)entry.getValue();
if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
sb.append("<"+key+">"+""+key+">");
}else {
sb.append("<"+key+">"+value+""+key+">");
}
}
sb.append(" ");
return sb.toString();
}
// MARK: - 生成签名
public static String createSign(String characterEncoding,SortedMap parameters){
StringBuffer sb = new StringBuffer();
//所有参与传参的参数按照accsii排序(升序)
Set es = parameters.entrySet();
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
//请求方法
private static String httpsRequest(Activity activity, String requestUrl, String requestMethod, String outputStr) {
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
System.out.println("连接超时:{}"+ ce);
Toast.makeText(activity, "连接超时", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
System.out.println("https请求异常:{}"+ e);
Toast.makeText(activity, "网络异常", Toast.LENGTH_SHORT).show();
}
return null;
}
// MARK: - 请求微信接口,生成微信后台的预支付订单
// 官方:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
public static void generatePrepaymentOrder(final Activity activity,
final String appid,
String body,
final String mch_id,
String nonce_str,
String wxnotify_url,
String out_trade_no,
String spbill_create_ip,
String total_fee,
String trade_type) {
final SortedMap parameterMap = new TreeMap();
parameterMap.put("appid", WXPayManager.APPID);
parameterMap.put("mch_id", WXPayManager.MCH_ID);
parameterMap.put("nonce_str", nonce_str);
parameterMap.put("body", body);
parameterMap.put("out_trade_no", out_trade_no);
parameterMap.put("total_fee", total_fee);
parameterMap.put("spbill_create_ip", spbill_create_ip);
parameterMap.put("notify_url", WXPayManager.WXNotify_url);
parameterMap.put("trade_type", trade_type);
final String sign = WXPayManager.createSign("UTF-8", parameterMap);
System.out.println("sign==" + sign);
parameterMap.put("sign", sign);
final String requestXML = WXPayManager.getRequestXml(parameterMap);
System.out.println("requestXML==" + requestXML);
new Thread(){
@Override
public void run() {
super.run();
String result = httpsRequest(activity,
"https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
requestXML);
System.out.println("result==" + result);
try {
WXPrepareModel prepareModel = WXPayManager.doXMLParse(result);
System.out.println("prepareModel==" + prepareModel.toString());
if (prepareModel.getResult_code().equals("SUCCESS") &&
prepareModel.getReturn_code().equals("SUCCESS")) {
// 构造参数列表
String packageStr = "Sign=WXPay";
String timestamp = "" + System.currentTimeMillis() / 1000;
SortedMap parameters = new TreeMap();
parameters.put("appid", prepareModel.getAppid());
parameters.put("partnerid", prepareModel.getMch_id());
parameters.put("prepayid", prepareModel.getPrepay_id());
parameters.put("noncestr", prepareModel.getNonce_str());
parameters.put("package", packageStr);
parameters.put("timestamp", timestamp);
String signStr = createSign("UTF-8", parameters);
System.out.println("signStr==" + signStr);
toPay(activity,
prepareModel.getAppid(),
prepareModel.getMch_id(),
prepareModel.getPrepay_id(),
prepareModel.getNonce_str(),
timestamp,
packageStr,
signStr);
} else {
System.out.println("生成微信后台预支付订单id失败");
System.out.println("prepareModel.getReturn_msg==" + prepareModel.getReturn_msg());
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("生成微信后台预支付订单id请求结果的 xml解析失败");
}
}
}.start();
}
// MARK: - 解析 xml
public static WXPrepareModel doXMLParse(String strxml) throws Exception {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if(null == strxml || "".equals(strxml)) {
return null;
}
// Map m = new HashMap();
InputStream inputStream = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
XmlPullParser pullParser = Xml.newPullParser();
// 设置 参数
pullParser.setInput(inputStream, "utf-8");
// 获取事件类型
int type = pullParser.getEventType();
WXPrepareModel resultModel = null;
while (type != XmlPullParser.END_DOCUMENT) {
// 正式解析
switch (type) {
case XmlPullParser.START_TAG: {
// 解析开始标签
// 具体判断解析到的是哪个标签
if ("xml".equals(pullParser.getName())) {
resultModel = new WXPrepareModel();
} else if ("return_code".equals(pullParser.getName())) {
String return_code = pullParser.nextText();
System.out.println("return_code==" + return_code);
resultModel.setReturn_code(return_code);
} else if ("return_msg".equals(pullParser.getName())) {
String return_msg = pullParser.nextText();
resultModel.setReturn_msg(return_msg);
} else if ("appid".equals(pullParser.getName())) {
String appid = pullParser.nextText();
resultModel.setAppid(appid);
} else if ("mch_id".equals(pullParser.getName())) {
String mch_id = pullParser.nextText();
resultModel.setMch_id(mch_id);
} else if ("nonce_str".equals(pullParser.getName())) {
String nonce_str = pullParser.nextText();
resultModel.setNonce_str(nonce_str);
} else if ("sign".equals(pullParser.getName())) {
String sign = pullParser.nextText();
resultModel.setSign(sign);
} else if ("result_code".equals(pullParser.getName())) {
String result_code = pullParser.nextText();
resultModel.setResult_code(result_code);
} else if ("prepay_id".equals(pullParser.getName())) {
String prepay_id = pullParser.nextText();
resultModel.setPrepay_id(prepay_id);
} else if ("trade_type".equals(pullParser.getName())) {
String trade_type = pullParser.nextText();
resultModel.setTrade_type(trade_type);
}
break;
}
case XmlPullParser.END_TAG: {
// 解析结束标签
if ("xml".equals(pullParser.getName())) {
// 把对象放到集合中
// weatherList.add(channelModel);
}
break;
}
}
// 不停的向下解析
type = pullParser.next();
}
//关闭流
inputStream.close();
return resultModel;
}
// MARK: - 判断手机是否安装微信,微信版本是否支持支付
public static Boolean chechWXCanPay(Activity activity) {
IWXAPI api = WXAPIFactory.createWXAPI(activity, WXPayManager.APPID, false);
Boolean isCanPay = true;
if (!api.isWXAppInstalled()) {
Toast.makeText(activity, "您的手机没有安装微信", Toast.LENGTH_SHORT).show();
isCanPay = false;
} else {
boolean isPaySupported = api.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT;
if (!isPaySupported) {
// Toast.makeText(activity, String.valueOf(isPaySupported), Toast.LENGTH_SHORT).show();
Toast.makeText(activity, "您的微信版本过低,不支持支付", Toast.LENGTH_SHORT).show();
isCanPay = false;
}
}
return isCanPay;
}
// MARK: - 进入微信客服端去支付
public static void toPay(final Activity activity,
final String appId,
final String mch_id,
final String prepayid,
final String noncestr,
final String timestamp,
final String packageValue,
final String sign) {
// 在主线程中执行
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// IWXAPI 是第三方app和微信通信的openapi接口
// 通过WXAPIFactory工厂,获取IWXAPI的实例
IWXAPI api = WXAPIFactory.createWXAPI(activity, WXPayManager.APPID, false);
// 将该app注册到微信
api.registerApp(WXPayManager.APPID);
System.out.println("appId==" + appId);
System.out.println("mch_id==" + mch_id);
System.out.println("prepayid==" + prepayid);
System.out.println("noncestr==" + noncestr);
System.out.println("timestamp==" + timestamp);
System.out.println("packageValue==" + packageValue);
System.out.println("sign==" + sign);
PayReq req = new PayReq();
req.appId = appId;
req.partnerId = mch_id;
req.prepayId = prepayid;
req.nonceStr = noncestr;
req.timeStamp = timestamp;
req.packageValue = packageValue;
req.sign = sign;
Toast.makeText(activity, "正常调起支付", Toast.LENGTH_SHORT).show();
// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
api.sendReq(req);
}
});
}
}
获取ip地址
public class IPHelper {
// MARK: - 获取内网IP地址
/**
* 获取ip地址
* @return
*/
public static String getHostIP() {
String hostIp = null;
try {
Enumeration nis = NetworkInterface.getNetworkInterfaces();
InetAddress ia = null;
while (nis.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) nis.nextElement();
Enumeration ias = ni.getInetAddresses();
while (ias.hasMoreElements()) {
ia = ias.nextElement();
if (ia instanceof Inet6Address) {
continue;// skip ipv6
}
String ip = ia.getHostAddress();
if (!"127.0.0.1".equals(ip)) {
hostIp = ia.getHostAddress();
break;
}
}
}
} catch (SocketException e) {
Log.i("yao", "SocketException");
e.printStackTrace();
}
if (hostIp == null) {
hostIp = "0.0.0.0";
}
return hostIp;
}
// MARK: - 获取外网IP地址
/**
* 获取IP地址
* @return
*/
public static String GetNetIp() {
URL infoUrl = null;
InputStream inStream = null;
String line = "";
try {
infoUrl = new URL("http://pv.sohu.com/cityjson?ie=utf-8");
URLConnection connection = infoUrl.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
inStream = httpConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
StringBuilder strber = new StringBuilder();
while ((line = reader.readLine()) != null)
strber.append(line + "\n");
inStream.close();
// 从反馈的结果中提取出IP地址
int start = strber.indexOf("{");
int end = strber.indexOf("}");
String json = strber.substring(start, end + 1);
if (json != null) {
try {
JSONObject jsonObject = new JSONObject(json);
line = jsonObject.optString("cip");
} catch (JSONException e) {
e.printStackTrace();
}
}
return line;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return line;
}
}
把inputStream 转换为 String
public class StreamTools {
// 把一个 inputStream 转换为一个 String
public static String readStream(InputStream inputStream) throws Exception {
// 定义一个内存输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = -1;
byte[] buffer = new byte[1024]; //1kb
while ((len = inputStream.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
inputStream.close();
String content = new String(baos.toByteArray());
// 如果服务器是以 gbk 方式编码的,则这个地方写 gbk;否则返回的是乱码
// String content = new String(baos.toByteArray(), "gbk");
return content;
}
}
4.APP端调起支付的参数列表,官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12
微信支付官方 Demo:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1
在开发文档API详细说明 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_4
中,点击Android资源下载可以看到
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN
在 Android Studio环境下集成和在 eclipse环境下集成微信支付 SDK的方法;
Android Studio环境下:已改用gradle形式,发布到jcenter( http://jcenter.bintray.com/),请开发者使用gradle来编译、更新微信SDK。
在build.gradle文件中,添加如下依赖即可:
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
或
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
}
(其中,前者包含统计功能)
eclipse环境下:点击下载 Android开发工具包
注意:因为微信SDK从4.0.2版本开始已改用gradle形式,后续Android开发工具包将不再更新,请开发者尽快改用gradle方式编译、更新微信SDK。
使用微信语音识别接口、语音合成接口。点击下载 语音SDK+Demo+开发文档
使用微信图像识别接口。点击下载 图像SDK+Demo+开发文档
使用微信卡券功能接口。点击下载 卡券SDK+开发文档
范例代码
包含了一个完整的范例工程。该范例的使用可以参阅Android平台上手指南:HelloWeixin@Android。点击下载
签名生成工具
用于获取安装到手机的第三方应用签名的apk包。点击下载 签名生成工具
我们用到这个类,微信支付成功后点击返回商户
WXPayEntryActivity.java ,是支付结果页面;
弹窗中,resp.errCode值的意义:
0 | 成功 | 展示成功页面 |
-1 | 错误 | 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。 |
-2 | 用户取消 | 无需处理。发生场景:用户不支付了,点击取消,返回APP。 |