微信支付步骤:
1.先去微信开放平台申请账号,创建移动应用,并审核通过,这样就可以获取到
// APP_ID 替换为你的应用从官方网站申请到的合法appId
public static final String APP_ID = "wwwwwwww";
// 微信支付商户号
public static final String APP_TENANT = "yyyyyy";
// 秘钥(审核通过后会邮件通知你,然后让你登陆在里面设置秘钥)
public static final String APP_TENANT_SIGN = "XXXXXXXXXXXXXXXXXXXXX";
2.接入微信支付的SDK
3.在AndroidManifest.xml文件中加入
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.yyyyy">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- for mta statistics -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop" />
<receiver android:name=".AppRegister">
<intent-filter>
<action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
</intent-filter>
</receiver>
</application>
</manifest>
4.在你的包(必须是AndroidManifest.xml中的包名,上面3中的com.xxx.yyyyy)下面创建wxapi文件,在wxapi文件下面创建WXPayEntryActivity.java类;
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_result);
api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
/**
* 微信支付成功或失败取消支付的回调方法
* @param resp
*/
@Override
public void onResp(BaseResp resp) {
Log.e("WXPayEntryActivity", "onPayFinish, errCode = " + 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();
// }
System.out.println(resp.errCode);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
if (resp.errCode == 0) { // 0 成功 展示成功页面
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("微信支付结果");
builder.setMessage("支付订单成功!");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.show();
} else if (resp.errCode == -1) { // -1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
Toast.makeText(WXPayEntryActivity.this, "支付出错:" + resp.errStr, Toast.LENGTH_SHORT)
.show();
finish();
} else if (resp.errCode == -2) { // -2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。
Toast.makeText(WXPayEntryActivity.this, "取消支付:" + resp.errStr, Toast.LENGTH_SHORT)
.show();
finish();
}
}
}
}
5.写一个广播类:AppRegister.java(这一步关系到是否能接收到微信的回调)
public class AppRegister extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
// 将该app注册到微信
msgApi.registerApp("11225566666");
}
}
注册到清单文件中:
<receiver android:name=".AppRegister">
<intent-filter>
<action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
</intent-filter>
</receiver>
接下来就是重点了:(踩坑比较多)
public class MainActivity extends Activity {
private IWXAPI api;
private OrderPayBean orderPaybean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 商户APP工程中引入微信JAR包,调用API前,需要先向微信注册您的APPID
api = WXAPIFactory.createWXAPI(this, Constants.APP_ID); // 参数二是申请的APPID
// 将该app注册到微信
api.registerApp(Constants.APP_ID); // 参数是申请的APPID
orderPaybean = new OrderPayBean();
initData();
// if (!TextUtils.isEmpty(IpUtil.getIPAddress(this))) {
// String ipAddress = IpUtil.getIPAddress(this);
// String s = ipAddress.substring(1,ipAddress.length()).trim();
// Log.e("手机当前ip地址 = ", s);
// }
// Log.e("手机当前ip地址", IpUtil.getIPAddress(this));
}
private void initData() {
orderPaybean.appid = Constants.APP_ID;
orderPaybean.body = "微信支付";
orderPaybean.mch_id = Constants.APP_TENANT; // 商户号
orderPaybean.nonce_str = Constants.genNonceStr(); // 获得随机字符串
orderPaybean.notify_url = "https://www.google.com"; // //微信通知后台支付结果url
orderPaybean.total_fee = 1;
orderPaybean.trade_type = "APP";
orderPaybean.out_trade_no = Constants.getNonceStr();
orderPaybean.spbill_create_ip = "196.168.1.1";
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", orderPaybean.appid);
parameters.put("body", orderPaybean.body);
parameters.put("mch_id", orderPaybean.mch_id);
parameters.put("nonce_str", orderPaybean.nonce_str);
parameters.put("notify_url", orderPaybean.notify_url);
parameters.put("out_trade_no", orderPaybean.out_trade_no);
parameters.put("total_fee", orderPaybean.total_fee);
parameters.put("trade_type", orderPaybean.trade_type);
parameters.put("spbill_create_ip", orderPaybean.spbill_create_ip);
parameters.put("sign", Constants.createSign("UTF-8", parameters, Constants.APP_TENANT_SIGN));//传入签名好的参数值
StringBuilder xmlBuilder = new StringBuilder();
xmlBuilder.append("<xml>");
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
xmlBuilder.append("<").append(k).append(">");
xmlBuilder.append(v);
xmlBuilder.append("</").append(k).append(">");
}
xmlBuilder.append("</xml>");
System.out.println(xmlBuilder.toString());
try {
new GetPrepayId(new String(xmlBuilder.toString().getBytes(), "ISO8859-1")).execute();//这一步非常重要,不这样转换编码的话,传递中文就会报“签名错误”,这是很多人都会遇到的错误。
} catch (Exception e) {
e.printStackTrace();
}
}
public class GetPrepayId extends AsyncTask {
String str;
public GetPrepayId(String str) {
this.str = str;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Object doInBackground(Object[] params) {
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
Log.e("参数", ">>>>" + str);
byte[] buf = Util.httpPost(url, str); // 发起订单向微信获取预支付交易会话标识prepay_id
String content = null;
if (buf != null) {
content = new String(buf);
}
// String content = new String(buf);
Log.e("返回数据", ">>>>" + content);
Map<String, String> map = Constants.xmlToMap(content);
String nonceStr = Constants.genNonceStr();
String timeStamp = String.valueOf(Constants.genTimeStamp());
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", orderPaybean.appid);
parameters.put("partnerid", orderPaybean.mch_id);
parameters.put("prepayid", map.get("prepay_id"));
parameters.put("package", "Sign=WXPay");
parameters.put("noncestr", nonceStr);
parameters.put("timestamp", timeStamp);
PayReq request = new PayReq();
request.appId = orderPaybean.appid;
request.partnerId = orderPaybean.mch_id;
request.prepayId = map.get("prepay_id");
request.packageValue = "Sign=WXPay";
request.nonceStr = nonceStr;
request.timeStamp = timeStamp;
request.sign = Constants.createSign("UTF-8", parameters, Constants.APP_TENANT_SIGN);
api.sendReq(request); // 发起支付
return content;
}
}
}
PS:
当手机上面的微信在别处登陆的时候有时候会支付失败的(不提示没登录)
到此结束,感谢阅读。
当然奉上源码源码
下面贴上完整的代码:
工具类:Constants.java
package com.fly.weixin.utils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
public class Constants {
// APP_ID 替换为你的应用从官方网站申请到的合法appId
public static final String APP_ID = "flyflflyflyfly";
// 微信支付商户号
public static final String APP_TENANT = "20170611";
// 应用签名
// public static final String APP_TENANT_SIGN = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYyy";
// 秘钥
public static final String APP_TENANT_SIGN = "xxxxxxxxxxxxxxxxxxxxxxxxx";
//**********************************************************************************************************************************
/**
* 微信支付签名算法sign
* @param characterEncoding 签名编码(UTF-8)
* @param parameters 要签名的参数的集合
* @param key 商户自己设置的key
*/
@SuppressWarnings("unchecked")
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters, String key){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
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=" + key);
System.out.println(sb.toString());
String sign = WxMd5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
System.out.println(sign);
return sign;
}
/**
* 获取时间戳
* @return
*/
public static long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
* 获得随机字符串
* @return
*/
public static String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
// 生成随机号,防重复
public static String getNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000))
.getBytes());
}
public static Map<String, String> xmlToMap(String xmlstr) {
Map<String, String> map = new HashMap<>();
try {
SAXReader reader = new SAXReader();
InputStream ins = new ByteArrayInputStream(xmlstr.getBytes("UTF-8"));
Document doc = reader.read(ins);
Element root = doc.getRootElement();
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
}
IpUtil.java
package com.fly.weixin.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
* Created by Administrator on 2017/6/7.
*
*/
public class IpUtil {
/**
* 获取手机的ip地址
* @param context
* @return
*/
public static String getIPAddress(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info != null && info.isConnected()) {
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
try {
//Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
} else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
return ipAddress;
}
} else {
//当前无网络连接,请在设置中打开网络
}
return null;
}
/**
* 将得到的int类型的IP转换为String类型
*
* @param ip
* @return
*/
public static String intIP2StringIP(int ip) {
return (ip & 0xFF) + "." +
((ip >> 8) & 0xFF) + "." +
((ip >> 16) & 0xFF) + "." +
(ip >> 24 & 0xFF);
}
}
MD5.java
package com.fly.weixin.utils;
import java.security.MessageDigest;
public class MD5 {
private MD5() {}
public final static String getMessageDigest(byte[] buffer) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(buffer);
byte[] md = mdTemp.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
return null;
}
}
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f"};
/**
* 转换字节数组为16进制字串
* @param b 字节数组
* @return 16进制字串
*/
public static String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte aB : b) {
resultSb.append(byteToHexString(aB));
}
return resultSb.toString();
}
/**
* 转换byte到16进制
* @param b 要转换的byte
* @return 16进制格式
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
/**
* MD5编码
* @param origin 原始字符串
* @return 经过MD5加密之后的结果
*/
public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = origin;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(resultString.getBytes("UTF-8"));
resultString = byteArrayToHexString(md.digest());
} catch (Exception e) {
e.printStackTrace();
}
return resultString;
}
}
Util.java
package com.fly.weixin.utils;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.util.Log;
import junit.framework.Assert;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class Util {
private static final String TAG = "SDK_Sample.Util";
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(CompressFormat.PNG, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static byte[] httpGet(final String url) {
if (url == null || url.length() == 0) {
Log.e(TAG, "httpGet, url is null");
return null;
}
HttpClient httpClient = getNewHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse resp = httpClient.execute(httpGet);
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
Log.e(TAG, "httpGet exception, e = " + e.getMessage());
e.printStackTrace();
return null;
}
}
public static byte[] httpPost(String url, String entity) {
if (url == null || url.length() == 0) {
Log.e(TAG, "httpPost, url is null");
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) {
Log.e(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
return null;
}
return EntityUtils.toByteArray(resp.getEntity());
} catch (Exception e) {
Log.e(TAG, "httpPost exception, e = " + e.getMessage());
e.printStackTrace();
return null;
}
}
private static class SSLSocketFactoryEx extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
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 byte[] readFromFile(String fileName, int offset, int len) {
if (fileName == null) {
return null;
}
File file = new File(fileName);
if (!file.exists()) {
Log.i(TAG, "readFromFile: file not found");
return null;
}
if (len == -1) {
len = (int) file.length();
}
Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len));
if(offset <0){
Log.e(TAG, "readFromFile invalid offset:" + offset);
return null;
}
if(len <=0 ){
Log.e(TAG, "readFromFile invalid len:" + len);
return null;
}
if(offset + len > (int) file.length()){
Log.e(TAG, "readFromFile invalid file len:" + file.length());
return null;
}
byte[] b = null;
try {
RandomAccessFile in = new RandomAccessFile(fileName, "r");
b = new byte[len]; // ���������ļ���С������
in.seek(offset);
in.readFully(b);
in.close();
} catch (Exception e) {
Log.e(TAG, "readFromFile : errMsg = " + e.getMessage());
e.printStackTrace();
}
return b;
}
private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440;
public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) {
Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0);
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inJustDecodeBounds = true;
Bitmap tmp = BitmapFactory.decodeFile(path, options);
if (tmp != null) {
tmp.recycle();
tmp = null;
}
Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop);
final double beY = options.outHeight * 1.0 / height;
final double beX = options.outWidth * 1.0 / width;
Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY);
options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));
if (options.inSampleSize <= 1) {
options.inSampleSize = 1;
}
// NOTE: out of memory error
while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {
options.inSampleSize++;
}
int newHeight = height;
int newWidth = width;
if (crop) {
if (beY > beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
} else {
if (beY < beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
}
options.inJustDecodeBounds = false;
Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize);
Bitmap bm = BitmapFactory.decodeFile(path, options);
if (bm == null) {
Log.e(TAG, "bitmap decode failed");
return null;
}
Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight());
final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
if (scale != null) {
bm.recycle();
bm = scale;
}
if (crop) {
final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);
if (cropped == null) {
return bm;
}
bm.recycle();
bm = cropped;
Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight());
}
return bm;
} catch (final OutOfMemoryError e) {
Log.e(TAG, "decode bitmap failed: " + e.getMessage());
options = null;
}
return null;
}
public static String sha1(String str) {
if (str == null || str.length() == 0) {
return null;
}
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes());
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
public static List<String> stringsToList(final String[] src) {
if (src == null || src.length == 0) {
return null;
}
final List<String> result = new ArrayList<String>();
for (int i = 0; i < src.length; i++) {
result.add(src[i]);
}
return result;
}
}
WxMd5.java
package com.fly.weixin.utils;
import java.security.MessageDigest;
/**
* Created by Administrator on 2017/6/6.
*/
public class WxMd5 {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes("utf-8")));
} catch (Exception exception) {
}
return resultString;
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
bean包下的:OrderPayBean.java
package com.fly.weixin.bean;
import java.io.Serializable;
/**
* Created by fly on 2017/6/6.
*/
public class OrderPayBean implements Serializable {
public String appid; //appid
public String body; //商品描述
public String mch_id; //商户ID
public String nonce_str; //随机字符串
public String notify_url; //微信通知后台支付结果url
public String out_trade_no; //我们自己的订单号
public String spbill_create_ip; //客户端IP
public int total_fee; //总的支付金额
public String trade_type; //因为是移动应用 所以是APP
public String sign; //以上所有参数的MD5签名
}
wxapi包下:WXPayEntryActivity.java
package com.fly.weixin.wxapi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.fly.weixin.R;
import com.fly.weixin.utils.Constants;
import com.tencent.mm.opensdk.constants.ConstantsAPI;
import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
/**
* 把这个activity设置成dialog的样式,效果会更好
*/
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";
private IWXAPI api;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_result);
api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
api.handleIntent(getIntent(), this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
api.handleIntent(intent, this);
}
@Override
public void onReq(BaseReq req) {
}
/**
* 微信支付成功或失败取消支付的回调方法
* @param resp
*/
@Override
public void onResp(BaseResp resp) {
Log.e("WXPayEntryActivity", "onPayFinish, errCode = " + 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();
// }
System.out.println(resp.errCode);
if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
if (resp.errCode == 0) { // 0 成功 展示成功页面
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("微信支付结果");
builder.setMessage("支付订单成功!");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.show();
} else if (resp.errCode == -1) { // -1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
Toast.makeText(WXPayEntryActivity.this, "支付出错:" + resp.errStr, Toast.LENGTH_SHORT)
.show();
finish();
} else if (resp.errCode == -2) { // -2 用户取消 无需处理。发生场景:用户不支付了,点击取消,返回APP。
Toast.makeText(WXPayEntryActivity.this, "取消支付:" + resp.errStr, Toast.LENGTH_SHORT)
.show();
finish();
}
}
}
}
广播:
package com.fly.weixin.wx_success;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.fly.weixin.utils.Constants;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
public class AppRegister extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
// 将该app注册到微信
msgApi.registerApp(Constants.APP_ID);
}
}
发起支付的代码:MainActivity.java
package com.fly.weixin.wx_success;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import com.fly.weixin.R;
import com.fly.weixin.bean.OrderPayBean;
import com.fly.weixin.utils.Constants;
import com.fly.weixin.utils.Util;
import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class MainActivity extends Activity {
private IWXAPI api;
private OrderPayBean orderPaybean;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 商户APP工程中引入微信JAR包,调用API前,需要先向微信注册您的APPID
api = WXAPIFactory.createWXAPI(this, Constants.APP_ID); // 参数二是申请的APPID
// 将该app注册到微信
api.registerApp(Constants.APP_ID); // 参数是申请的APPID
orderPaybean = new OrderPayBean();
initData();
// if (!TextUtils.isEmpty(IpUtil.getIPAddress(this))) {
// String ipAddress = IpUtil.getIPAddress(this);
// String s = ipAddress.substring(1,ipAddress.length()).trim();
// Log.e("手机当前ip地址 = ", s);
// }
// Log.e("手机当前ip地址", IpUtil.getIPAddress(this));
}
private void initData() {
orderPaybean.appid = Constants.APP_ID;
orderPaybean.body = "微信支付";
orderPaybean.mch_id = Constants.APP_TENANT; // 商户号
orderPaybean.nonce_str = Constants.genNonceStr(); // 获得随机字符串
orderPaybean.notify_url = "https://www.google.com"; // //微信通知后台支付结果url
orderPaybean.total_fee = 1;
orderPaybean.trade_type = "APP";
orderPaybean.out_trade_no = Constants.getNonceStr();
orderPaybean.spbill_create_ip = "196.168.1.1";
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", orderPaybean.appid);
parameters.put("body", orderPaybean.body);
parameters.put("mch_id", orderPaybean.mch_id);
parameters.put("nonce_str", orderPaybean.nonce_str);
parameters.put("notify_url", orderPaybean.notify_url);
parameters.put("out_trade_no", orderPaybean.out_trade_no);
parameters.put("total_fee", orderPaybean.total_fee);
parameters.put("trade_type", orderPaybean.trade_type);
parameters.put("spbill_create_ip", orderPaybean.spbill_create_ip);
parameters.put("sign", Constants.createSign("UTF-8", parameters, Constants.APP_TENANT_SIGN));//传入签名好的参数值
StringBuilder xmlBuilder = new StringBuilder();
xmlBuilder.append("<xml>");
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
xmlBuilder.append("<").append(k).append(">");
xmlBuilder.append(v);
xmlBuilder.append("</").append(k).append(">");
}
xmlBuilder.append("</xml>");
System.out.println(xmlBuilder.toString());
try {
new GetPrepayId(new String(xmlBuilder.toString().getBytes(), "ISO8859-1")).execute();//这一步非常重要,不这样转换编码的话,传递中文就会报“签名错误”,这是很多人都会遇到的错误。
} catch (Exception e) {
e.printStackTrace();
}
}
public class GetPrepayId extends AsyncTask {
String str;
public GetPrepayId(String str) {
this.str = str;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Object doInBackground(Object[] params) {
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
Log.e("参数", ">>>>" + str);
byte[] buf = Util.httpPost(url, str); // 发起订单向微信获取预支付交易会话标识prepay_id
String content = null;
if (buf != null) {
content = new String(buf);
}
// String content = new String(buf);
Log.e("返回数据", ">>>>" + content);
Map<String, String> map = Constants.xmlToMap(content);
String nonceStr = Constants.genNonceStr();
String timeStamp = String.valueOf(Constants.genTimeStamp());
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
parameters.put("appid", orderPaybean.appid);
parameters.put("partnerid", orderPaybean.mch_id);
parameters.put("prepayid", map.get("prepay_id"));
parameters.put("package", "Sign=WXPay");
parameters.put("noncestr", nonceStr);
parameters.put("timestamp", timeStamp);
PayReq request = new PayReq();
request.appId = orderPaybean.appid;
request.partnerId = orderPaybean.mch_id;
request.prepayId = map.get("prepay_id");
request.packageValue = "Sign=WXPay";
request.nonceStr = nonceStr;
request.timeStamp = timeStamp;
request.sign = Constants.createSign("UTF-8", parameters, Constants.APP_TENANT_SIGN);
api.sendReq(request); // 发起支付
return content;
}
}
}
配置文件:
apply plugin: 'com.android.application'
android {
signingConfigs {
fly_wx {
keyAlias 'keyStore'
keyPassword 'android'
storeFile file('C:/Users/Administrator.SKY-20170131CUA/Desktop/keyStore.jks')
storePassword 'android'
}
}
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.fly.weixin"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
/*ndk{
moduleName "helloJni"/*//*生成的so文件名,必填
abiFilters "armeabi", "armeabi-v7a", "x86" //配置输出的abi体系结构下的so库,
}*/
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.fly_wx
}
debug {
signingConfig signingConfigs.fly_wx
}
}
useLibrary 'org.apache.http.legacy'
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
compile files('libs/dom4j-1.6.1.jar')
}