微信支付

原创 2015年07月08日 10:30:16

随着电商时代的发展,微信成为主流,微信支付也随之到来,小生开发步骤如下:

1.申请微信开放平台账号,开通微信支付,会获取到AppID,AppSecret,PaySignKey,PartnerID,PartnerKey(后来修改后,少了某一个参数,后面在更新吧)

提前都准备好了,接下来是代码阶段。

2.验证微信是否支持微信支付。

<span style="white-space:pre">	</span>// 微信是否支持支付
	public static boolean isPay(Context context) {
		<span style="font-family: Arial, Helvetica, sans-serif;">IWXAPI </span><span style="font-family: Arial, Helvetica, sans-serif;">api = WXAPIFactory.createWXAPI(context, AppID, false);</span>
		boolean isPaySupported = api.getWXAppSupportAPI() >= TIMELINE_SUPPORTED_VERSION;
		return isPaySupported;
	}

3.获取微信支付的token

private static class GetAccessTokenTask extends
			AsyncTask<Void, Void, GetAccessTokenResult> {

		@Override
		protected void onPostExecute(GetAccessTokenResult result) {

			if (result.localRetCode == LocalRetCode.ERR_OK) {
				Editor editor = context.getSharedPreferences(Pref.PY6,
						Context.MODE_PRIVATE).edit();
				editor.putString("accessToken", result.accessToken).commit();
				editor.putInt("accessToken_time",
						Integer.parseInt(String.valueOf(Util.genTimeStamp())))
						.commit();

				GetPrepayIdTask getPrepayId = new GetPrepayIdTask(
						result.accessToken);
				getPrepayId.execute();
			} else {
				if (dialog != null) {
					dialog.dismiss();

				}
				context.getSharedPreferences(Pref.PY6, Context.MODE_PRIVATE)
						.edit().remove("accessToken").commit();
				context.getSharedPreferences(Pref.PY6, Context.MODE_PRIVATE)
						.edit().remove("accessToken_time").commit();
				Toast.makeText(context, R.string.system_fail,
						Toast.LENGTH_SHORT).show();
			}
		}

		@Override
		protected GetAccessTokenResult doInBackground(Void... params) {
			GetAccessTokenResult result = new GetAccessTokenResult();

			String url = String
					.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s",
							"client_credential", AppID, AppSecret);

			byte[] buf = Util.httpGet(url);
			if (buf == null || buf.length == 0) {
				result.localRetCode = LocalRetCode.ERR_HTTP;
				return result;
			}

			String content = new String(buf);
			result.parseFrom(content);
			return result;
		}
	}
4.  获取PrepayId

private static class GetPrepayIdTask extends
			AsyncTask<Void, Void, GetPrepayIdResult> {

		private String accessT;

		public GetPrepayIdTask(String accessToken) {
			this.accessT = accessToken;
		}

		@Override
		protected void onPreExecute() {

		}

		@Override
		protected void onPostExecute(GetPrepayIdResult result) {
			if (result.localRetCode == LocalRetCode.ERR_OK) {
				sendPayReq(result);
			} else {

				if (dialog != null) {
					dialog.dismiss();
				}

				context.getSharedPreferences(Pref.PY6, Context.MODE_PRIVATE)
						.edit().remove("accessToken").commit();
				context.getSharedPreferences(Pref.PY6, Context.MODE_PRIVATE)
						.edit().remove("accessToken_time").commit();

				Toast.makeText(context, R.string.system_fail,
						Toast.LENGTH_SHORT).show();
			}
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
		}

		@Override
		protected GetPrepayIdResult doInBackground(Void... params) {

			String url = String.format(
					"https://api.weixin.qq.com/pay/genprepay?access_token=%s",
					accessT);
			Bundle b = Util.genProductArgs(body, money, traceId, AppID,
					PartnerID, PaySignKey, PartnerKey, moneye);
			timeStamp = b.getLong("timeStamp");
			String entity = b.getString("json");
			packageValue = b.getString("packageValue");
			nonceStr = b.getString("nonceStr");

			GetPrepayIdResult result = new GetPrepayIdResult();

			byte[] buf = Util.httpPost(url, entity);
			if (buf == null || buf.length == 0) {
				result.localRetCode = LocalRetCode.ERR_HTTP;
				return result;
			}

			String content = new String(buf);
			result.parseFrom(content);
			return result;
		}
	} 
 private static class GetPrepayIdResult {


<span style="white-space:pre">		</span>public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER;
<span style="white-space:pre">		</span>public String prepayId;
<span style="white-space:pre">		</span>public int errCode;
<span style="white-space:pre">		</span>public String errMsg;


<span style="white-space:pre">		</span>public void parseFrom(String content) {


<span style="white-space:pre">			</span>if (content == null || content.length() <= 0) {
<span style="white-space:pre">				</span>localRetCode = LocalRetCode.ERR_JSON;
<span style="white-space:pre">				</span>return;
<span style="white-space:pre">			</span>}


<span style="white-space:pre">			</span>try {
<span style="white-space:pre">				</span>JSONObject json = new JSONObject(content);
<span style="white-space:pre">				</span>if (json.has("prepayid")) { // success case
<span style="white-space:pre">					</span>prepayId = json.getString("prepayid");
<span style="white-space:pre">					</span>localRetCode = LocalRetCode.ERR_OK;
<span style="white-space:pre">				</span>} else {
<span style="white-space:pre">					</span>localRetCode = LocalRetCode.ERR_JSON;
<span style="white-space:pre">				</span>}


<span style="white-space:pre">				</span>errCode = json.getInt("errcode");
<span style="white-space:pre">				</span>errMsg = json.getString("errmsg");


<span style="white-space:pre">			</span>} catch (Exception e) {
<span style="white-space:pre">				</span>localRetCode = LocalRetCode.ERR_JSON;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}

<span style="white-space:pre">	</span>private static enum LocalRetCode {
<span style="white-space:pre">		</span>ERR_OK, ERR_HTTP, ERR_JSON, ERR_OTHER
<span style="white-space:pre">	</span>}

5.调起微信支付,在此一定要打包支付,打包用的key必须和生成签名的MD5所用的key是一样的,而且每次测试必须打包在测试。

// 第三步: 调起微信支付 在WXPayEntryActivity 接受微信支付返回的结果
	private static void sendPayReq(GetPrepayIdResult result) {

		PayReq req = new PayReq();
		req.appId = AppID;
		req.partnerId = PartnerID;
		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", PaySignKey));
		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 = Util.genSign(signParams);

		// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信

		boolean b = api.sendReq(req);
		
		// System.out.println(sb.toString());

		if (dialog != null) {
			dialog.dismiss();
		}

	}

6.微信支付中间需要的方法 ,签名,包名等

public class Util {
	
	public static final String TAG = "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;
		}
	}
	
	public 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();
		} 
	}  

	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(); 
	   } 
	}
	
	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;
	}
	
	public 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;
	}

	public static String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}
	
	public static long genTimeStamp() {
		return System.currentTimeMillis() / 1000;
	}
	
	/**
	 * 建议 traceid 字段包含用户信息及订单信息,方便后续对订单状态的查询和跟踪
	 */
	
	public static String getTraceId() {
		return "crestxu_" + genTimeStamp(); 
	}
	
	/**
	 * 注意:商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一
	 */
	public static String genOutTradNo() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}
	
	public static 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 = Util.sha1(sb.toString());
		Log.d(TAG, "genSign, sha1 = " + sha1);
		return sha1;
	}
	
	public static String genPackage(List<NameValuePair> params, String PartnerKey) {
		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(PartnerKey); 
		
		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		
		return URLEncodedUtils.format(params, "UTF-8") + "&sign=" + packageSign;
	}
	
	public static Bundle genProductArgs(String body, String money, String traceId, String AppID, String PartnerID,
			String PaySignKey, String PartnerKey, String mone) {
		Bundle b = new Bundle();
		JSONObject json = new JSONObject();
		long timeStamp;
		String packageValue;
		String nonceStr;
		try {
			json.put("appid", AppID);
//			String traceId = getTraceId();  
			json.put("traceid", traceId);
			nonceStr = genNonceStr();
			json.put("noncestr", nonceStr);
			
			List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
			packageParams.add(new BasicNameValuePair("attach", mone));   //  TODO 余额
			packageParams.add(new BasicNameValuePair("bank_type", "WX"));
			packageParams.add(new BasicNameValuePair("body", body.replaceAll(" ", ""))); // 订单内容
			packageParams.add(new BasicNameValuePair("fee_type", "1"));	 // 支付币种 暂时只有1
			packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
//			packageParams.add(new BasicNameValuePair("notify_url", "http://www.py6.com/api/payment/weixin/")); // 正式
//			packageParams.add(new BasicNameValuePair("notify_url", "http://weixin.qq.com")); 
			packageParams.add(new BasicNameValuePair("notify_url", "http://www.py6.com/api/payment/paytest/wxpay.php?act=wxpay&op=0pay")); // 测试
			packageParams.add(new BasicNameValuePair("out_trade_no", traceId));
			packageParams.add(new BasicNameValuePair("partner", PartnerID));
			packageParams.add(new BasicNameValuePair("spbill_create_ip", "192.168.1.1"));
			packageParams.add(new BasicNameValuePair("total_fee", money));   //  TODO 订单总价钱
			
			packageValue = genPackage(packageParams, PartnerKey);
			
			json.put("package", packageValue);
			timeStamp = genTimeStamp();
			json.put("timestamp", timeStamp);
			
			List<NameValuePair> signParams = new LinkedList<NameValuePair>();
			signParams.add(new BasicNameValuePair("appid", AppID));
			signParams.add(new BasicNameValuePair("appkey", PaySignKey));
			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;
		}
		
		b.putString("json", json.toString());
		b.putLong("timeStamp", timeStamp);
		b.putString("packageValue", packageValue);
		b.putString("nonceStr", nonceStr);
		return b;
	}
}


6.微信支付回调:这里比较坑 必须是有个包是:包名+wxap 列如包名是com.a.a 那就的创建一个包 com.a.a.wxapi 里面放入微信的回调类WXPayEntryActivity

7.遇到类似8位数字的报错 可以找wepayTS@tencent.com 邮件解决,小生当时开发就遇到很多错误,都是邮件解决的,微信支付文档里面有个测试网址,参数提交都可以到里面进行测试的




版权声明:本文为博主原创文章,转载请著名出处。

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

微信支付详解

1.为什么会有两种JS方法可以发起微信支付? 当你登陆微信公众号之后,左边有两个菜单栏,一个是微信支付,一个是开发者中心。 在开发者中心中,有一个微信JS-SDK说明文档。 在此说明文档中,有一...
  • Truong
  • Truong
  • 2015年08月08日 21:25
  • 12194

Android 微信支付详解与Demo

最近公司弄Ionic框架,项目中需要微信支付,无奈,把我调过去弄,期间也是几近崩溃,好在皇天不负有心人,在看别人的文档,终于是在项目中集成了微信支付,下面作为一个小白的我,想要把我的经验分享给大家,希...

微信支付

Java版的微信支付开发

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

微信支付-公众号支付(java实现)

最近两周实现了调用微信接口使用微信进行支付的需求,包含公众号支付及扫码支付两种方式,由于微信文档写的较为简略,现将调用微信接口进行支付流程进行记录及分享。 本文旨在对公众号支付的实现流程进行介...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:微信支付
举报原因:
原因补充:

(最多只允许输入30个字)