微信APP支付

来源:互联网 发布:centos twisted 安装 编辑:程序博客网 时间:2024/04/30 13:47

微信支付有三个步骤:

1.获取access_token.

2.根据access_token获取预付订单

3.发起支付并调用微信支付

下面就直接上代码.


注意:wxpayentryactivity一定要放在xxx.xxx.wxapi包下,不然支付结果回调访问不到页面

准备工作:

public class Constants {// APP_ID 替换为你的应用从官方网站申请到的合法appId    public static final String APP_ID = "wxd930ea5d5a258f4f";        /** 商家向财付通申请的商家id */    public static final String PARTNER_ID = "1900000109";    public static final String PARTNER_KEY = "8934e7d15453e97507ef794cf7b0519d";    public  static final String APP_SECRET = "db426a9829e4b49a0dcac7b4162da6b6";    public static final String APP_KEY = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K"; // wxd930ea5d5a258f4f 对应的支付密钥    }


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;}}}
public class WXErrorInfo {public String errcode;public String errmsg;}

public class WXPrepayIdInfo {public String prepayid;public String errcode;public String errmsg;}
public class WXTokenInfo {public String access_token;public int expires_in;//有效时间}


public class WXUtils {private static final String TAG="WXUtils";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;                  }            @Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] chain,String authType) throws java.security.cert.CertificateException {}          };                    sslContext.init(null, new TrustManager[] { tm }, null);          }            @Overridepublic Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {return sslContext.getSocketFactory().createSocket(socket, host,port, autoClose);}@Overridepublic Socket createSocket() throws IOException {return sslContext.getSocketFactory().createSocket();} }  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 errorwhile (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;}public 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();    } }}



获取token

public class WXGetTokenAsyncTask extends AsyncTask<Void, Void, String> {GetAeecssTokenListener listener;public WXGetTokenAsyncTask(GetAeecssTokenListener listener){this.listener=listener;}@Overrideprotected void onCancelled() {super.onCancelled();}@Overrideprotected String doInBackground(Void... arg0) {String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",Constants.APP_ID, Constants.APP_SECRET);Log.d("tag", "get access token,url:"+url);HttpClient client=new DefaultHttpClient();HttpGet get=new HttpGet(url);try {HttpResponse response=client.execute(get);if(response.getStatusLine().getStatusCode()==200){byte[] bytes=EntityUtils.toByteArray(response.getEntity());return new String(bytes);}else{Log.e("tag", "get access token error:"+response.getStatusLine().getStatusCode());}} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}@Overrideprotected void onPostExecute(String result) {super.onPostExecute(result);if(!TextUtils.isEmpty(result)){try {JSONObject object=new JSONObject(result);if(object!=null){WXTokenInfo info=new WXTokenInfo();WXErrorInfo errorInfo=new WXErrorInfo();if(!object.isNull("access_token")){info.access_token=object.getString("access_token");}else if(!object.isNull("errcode")){errorInfo.errcode=object.getString("errcode");}if(!object.isNull("expires_in")){info.expires_in=object.getInt("expires_in");}else if(!object.isNull("errmsg")){errorInfo.errmsg=object.getString("errmsg");}listener.onFailure(errorInfo);listener.onSuccess(info);}} catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}interface GetAeecssTokenListener{public void onSuccess(WXTokenInfo tokenInfo);public void onFailure(WXErrorInfo errorInfo);}}

获取预付订单

public class WXGetPrepayIdTask extends AsyncTask<Void, Void, String> {String accessToken;private long timeStamp;private String nonceStr, packageValue;GetPrepayIdListener listener;Context context;IWXAPI api;public WXGetPrepayIdTask(String accessToken,IWXAPI api,GetPrepayIdListener listener,Context context){this.accessToken=accessToken;this.listener=listener;this.api=api;this.context=context;}@Overrideprotected String doInBackground(Void... arg0) {String url = String.format("https://api.weixin.qq.com/pay/genprepay?access_token=%s", accessToken);String entity = genProductArgs();Log.d("tag", "get prepayid, url = " + url);Log.d("tag", "get prepayid, entity = " + entity);byte[] buf = WXUtils.httpPost(url, entity);String string="";string=new String(buf);Log.d("tag", "get prepay-->"+string);return string;}@Overrideprotected void onCancelled() {super.onCancelled();}@Overrideprotected void onPostExecute(String result) {super.onPostExecute(result);if(!TextUtils.isEmpty(result)){try {JSONObject object=new JSONObject(result);String errcode="";WXPrepayIdInfo prepayIdInfo=new WXPrepayIdInfo();WXErrorInfo errorInfo=new WXErrorInfo();if(object!=null){if(!object.isNull("errcode")){errcode=object.getString("errcode");if(errcode.equals("0")){//成功if(!object.isNull("prepayid")){prepayIdInfo.prepayid=object.getString("prepayid");}if(!object.isNull("errmsg")){prepayIdInfo.errmsg=object.getString("errmsg");}prepayIdInfo.errcode="0";sendPayReq(prepayIdInfo);//开始调用微信支付}else{//失败errorInfo.errcode=object.getString("errcode");errorInfo.errmsg=object.getString("errmsg");}}}listener.onSuccess(prepayIdInfo);listener.onFailure(errorInfo);} catch (JSONException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}interface GetPrepayIdListener{public void onSuccess(WXPrepayIdInfo info);public void onFailure(WXErrorInfo errorInfo);}private String genProductArgs() {JSONObject json = new JSONObject();try {json.put("appid", Constants.APP_ID);String traceId = getTraceId();  // traceId 由开发者自定义,可用于订单的查询与跟踪,建议根据支付用户信息生成此idjson.put("traceid", traceId);nonceStr = genNonceStr();json.put("noncestr", nonceStr);WXPayInfo info=new WXPayInfo();//测试 暂时写死info.body="美特斯邦威";info.notify_url="http://www.baidu.com";info.total_fee="1";List<NameValuePair> packageParams = new LinkedList<NameValuePair>();packageParams.add(new BasicNameValuePair("bank_type", "WX"));packageParams.add(new BasicNameValuePair("body", info.body));packageParams.add(new BasicNameValuePair("fee_type", "1"));packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));packageParams.add(new BasicNameValuePair("notify_url", info.notify_url));packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));packageParams.add(new BasicNameValuePair("partner", Constants.PARTNER_ID));packageParams.add(new BasicNameValuePair("spbill_create_ip", getIP()));packageParams.add(new BasicNameValuePair("total_fee", info.total_fee));packageValue = genPackage(packageParams);json.put("package", packageValue);timeStamp = genTimeStamp();json.put("timestamp", timeStamp);List<NameValuePair> signParams = new LinkedList<NameValuePair>();signParams.add(new BasicNameValuePair("appid", Constants.APP_ID));signParams.add(new BasicNameValuePair("appkey", Constants.APP_KEY));signParams.add(new BasicNameValuePair("noncestr", nonceStr));signParams.add(new BasicNameValuePair("package", packageValue));signParams.add(new BasicNameValuePair("timestamp", String.valueOf(timeStamp)));signParams.add(new BasicNameValuePair("traceid", traceId));json.put("app_signature", genSign(signParams));json.put("sign_method", "sha1");} catch (Exception e) {Log.e("tag", "genProductArgs fail, ex = " + e.getMessage());return null;}return json.toString();}/** * 建议 traceid 字段包含用户信息及订单信息,方便后续对订单状态的查询和跟踪 */private String getTraceId() {return "crestxu_" + genTimeStamp(); }private long genTimeStamp() {return System.currentTimeMillis() / 1000;}private String genNonceStr() {Random random = new Random();return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}/** * 注意:商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一 */private String genOutTradNo() {Random random = new Random();return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());}private String genPackage(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();for (int i = 0; i < params.size(); i++) {sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());sb.append('&');}sb.append("key=");sb.append(Constants.PARTNER_KEY); // 注意:不能hardcode在客户端,建议genPackage这个过程都由服务器端完成// 进行md5摘要前,params内容为原始内容,未经过url encode处理String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign;}private String genSign(List<NameValuePair> params) {StringBuilder sb = new StringBuilder();int i = 0;for (; i < params.size() - 1; i++) {sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());sb.append('&');}sb.append(params.get(i).getName());sb.append('=');sb.append(params.get(i).getValue());String sha1 = WXUtils.sha1(sb.toString());return sha1;}public void sendPayReq(WXPrepayIdInfo result) {PayReq req = new PayReq();req.appId = Constants.APP_ID;req.partnerId = Constants.PARTNER_ID;req.prepayId = result.prepayid;req.nonceStr = nonceStr;req.timeStamp = String.valueOf(timeStamp);//req.packageValue = "Sign=" + packageValue;req.packageValue = "Sign=WXPay";List<NameValuePair> signParams = new LinkedList<NameValuePair>();signParams.add(new BasicNameValuePair("appid", req.appId));signParams.add(new BasicNameValuePair("appkey", Constants.APP_KEY));signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));signParams.add(new BasicNameValuePair("package", req.packageValue));signParams.add(new BasicNameValuePair("partnerid", req.partnerId));signParams.add(new BasicNameValuePair("prepayid", req.prepayId));signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));req.sign = genSign(signParams);// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信boolean bool=api.sendReq(req);Log.d("tag", "是否跳转:"+bool);}private String getIP(){String ip="";ConnectivityManager connectMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo info = connectMgr.getActiveNetworkInfo();if(info !=null &&info.getType() == ConnectivityManager.TYPE_WIFI){WifiManager wifiManager = (WifiManager)context. getSystemService(Context.WIFI_SERVICE);  //判断wifi是否开启  if (!wifiManager.isWifiEnabled()) {  wifiManager.setWifiEnabled(true);    }  WifiInfo wifiInfo = wifiManager.getConnectionInfo();       int ipAddress = wifiInfo.getIpAddress();ip = intToIp(ipAddress);}else if(info !=null && info.getType() ==  ConnectivityManager.TYPE_MOBILE){try  {  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())  {  ip= inetAddress.getHostAddress().toString();  }  }  }  }  catch (SocketException ex)  {  Log.e("WifiPreference IpAddress", ex.toString());  }  }else if(info==null){Toast.makeText(context, "当前网络不可用", Toast.LENGTH_SHORT).show();}Log.d("tag", "ip:"+ip);return ip;}private String intToIp(int i) {       return (i & 0xFF ) + "." +       ((i >> 8 ) & 0xFF) + "." +       ((i >> 16 ) & 0xFF) + "." +       ( i >> 24 & 0xFF) ;  }   }

发起支付

public class WXMannager {private static IWXAPI api;private static WXMannager mannager;private static Context context;public static synchronized WXMannager getInstance(Context ctx){api = WXAPIFactory.createWXAPI(ctx, Constants.APP_ID);if(mannager==null){mannager=new WXMannager();}context=ctx;return mannager;}public  void startPay(){new WXGetTokenAsyncTask(new GetAeecssTokenListener() {@Overridepublic void onSuccess(WXTokenInfo tokenInfo) {// TODO Auto-generated method stubnew WXGetPrepayIdTask(tokenInfo.access_token, api, new GetPrepayIdListener() {@Overridepublic void onSuccess(WXPrepayIdInfo info) {//不做处理}@Overridepublic void onFailure(WXErrorInfo errorInfo) {// TODO Auto-generated method stubLog.e("tag", "get prepayid error:"+errorInfo.errcode+","+errorInfo.errmsg);}},context).execute();}@Overridepublic void onFailure(WXErrorInfo errorInfo) {// TODO Auto-generated method stubLog.e("tag", "get access_token error:"+errorInfo.errcode+","+errorInfo.errmsg);}}).execute();}}


常见错误处理:第一次支付成功,后面每次打开都返回-1,或者直接跳转到支付结果回调页面并且支付失败,检查keystore是否和申请微信支付应用时一致,而且包名也要一致.


相关资源下载:微信支付官方demo及相关开发者文档
0 0
原创粉丝点击