在做Android支付的时候肯定会用到支付宝支付, 根据官方给出的demo做起来非常费劲,所以我们需要一次简单的封装。封装的代码也很简单,就是将官网给的demo提取出一个类来方便使用。
1 | <span style= "font-size: medium;" > /** |
8 | public static final String PARTNER = "123456789" ; |
10 | public static final String SELLER = "qibin0506@gmail.com" ; |
12 | public static final String RSA_PRIVATE = "rsa_private" ; |
14 | public static final String RSA_PUBLIC = "rsa_public" ; |
15 | private static final int SDK_PAY_FLAG = 1 ; |
16 | private WeakReference<Activity> mActivity; |
17 | private OnAlipayListener mListener; |
18 | public Alipay(Activity activity) { |
19 | mActivity = new WeakReference<Activity>(activity); |
21 | @SuppressLint ( "HandlerLeak" ) |
22 | private Handler mHandler = new Handler() { |
23 | public void handleMessage(Message msg) { |
24 | if (msg.what == SDK_PAY_FLAG) { |
25 | PayResult payResult = new PayResult((String) msg.obj); |
27 | String resultInfo = payResult.getResult(); |
28 | String resultStatus = payResult.getResultStatus(); |
30 | if (TextUtils.equals(resultStatus, "9000" )) { |
31 | if (mListener != null ) mListener.onSuccess(); |
36 | if (TextUtils.equals(resultStatus, "8000" )) { |
37 | if (mListener != null ) mListener.onWait(); |
40 | if (mListener != null ) mListener.onCancel(); |
49 | * @param title 标题 不能为空或者“” |
50 | * @param desc 描述 不能为空或者“” |
51 | * @param price 价格 不能为空或者“” |
52 | * @param sn 商品唯一货号 不能为空或者“” |
53 | * @param url 服务器回调url 不能为空或者“” |
55 | public void pay(String title, String desc, String price, String sn, String url) { |
57 | String orderInfo = getOrderInfo(title, desc, price, sn, url); |
59 | String sign = sign(orderInfo); |
62 | sign = URLEncoder.encode(sign, "UTF-8" ); |
63 | } catch (UnsupportedEncodingException e) { |
67 | final String payInfo = orderInfo + "&sign=/" " + sign + " / "&" |
69 | Runnable payRunnable = new Runnable() { |
72 | Activity activity = mActivity.get(); |
73 | if (activity == null ) return ; |
75 | PayTask alipay = new PayTask(activity); |
77 | String result = alipay.pay(payInfo); |
78 | Message msg = new Message(); |
79 | msg.what = SDK_PAY_FLAG; |
81 | mHandler.sendMessage(msg); |
85 | Thread payThread = new Thread(payRunnable); |
89 | * create the order info. 创建订单信息 |
92 | public String getOrderInfo(String subject, String body, String price, |
93 | String sn, String url) { |
95 | String orderInfo = "partner=" + "/" " + PARTNER + " / "" ; |
97 | orderInfo += "&seller_id=" + "/" " + SELLER + " / "" ; |
99 | orderInfo += "&out_trade_no=" + "/" " + sn + " / "" ; |
101 | orderInfo += "&subject=" + "/" " + subject + " / "" ; |
103 | orderInfo += "&body=" + "/" " + body + " / "" ; |
105 | orderInfo += "&total_fee=" + "/" " + price + " / "" ; |
107 | orderInfo += "¬ify_url=" + "/" " + url + " / "" ; |
109 | orderInfo += "&service=/" mobile.securitypay.pay/ "" ; |
111 | orderInfo += "&payment_type=/" 1 / "" ; |
113 | orderInfo += "&_input_charset=/" utf- 8 / "" ; |
119 | orderInfo += "&it_b_pay=/" 30m/ "" ; |
123 | orderInfo += "&return_url=/" m.alipay.com/ "" ; |
129 | * sign the order info. 对订单信息进行签名 |
134 | public String sign(String content) { |
135 | return SignUtils.sign(content, RSA_PRIVATE); |
138 | * get the sign type we use. 获取签名方式 |
141 | public String getSignType() { |
142 | return "sign_type=/" RSA/ "" ; |
144 | public void setListener(OnAlipayListener l) { |
153 | public static class OnAlipayListener { |
157 | public void onSuccess() {} |
161 | public void onCancel() {} |
165 | public void onWait() {} |
169 | private static final int BASELENGTH = 128 ; |
170 | private static final int LOOKUPLENGTH = 64 ; |
171 | private static final int TWENTYFOURBITGROUP = 24 ; |
172 | private static final int EIGHTBIT = 8 ; |
173 | private static final int SIXTEENBIT = 16 ; |
174 | private static final int FOURBYTE = 4 ; |
175 | private static final int SIGN = - 128 ; |
176 | private static char PAD = '=' ; |
177 | private static byte [] base64Alphabet = new byte [BASELENGTH]; |
178 | private static char [] lookUpBase64Alphabet = new char [LOOKUPLENGTH]; |
180 | for ( int i = 0 ; i < BASELENGTH; ++i) { |
181 | base64Alphabet[i] = - 1 ; |
183 | for ( int i = 'Z' ; i >= 'A' ; i--) { |
184 | base64Alphabet[i] = ( byte ) (i - 'A' ); |
186 | for ( int i = 'z' ; i >= 'a' ; i--) { |
187 | base64Alphabet[i] = ( byte ) (i - 'a' + 26 ); |
189 | for ( int i = '9' ; i >= '0' ; i--) { |
190 | base64Alphabet[i] = ( byte ) (i - '0' + 52 ); |
192 | base64Alphabet[ '+' ] = 62 ; |
193 | base64Alphabet[ '/' ] = 63 ; |
194 | for ( int i = 0 ; i <= 25 ; i++) { |
195 | lookUpBase64Alphabet[i] = ( char ) ( 'A' + i); |
197 | for ( int i = 26 , j = 0 ; i <= 51 ; i++, j++) { |
198 | lookUpBase64Alphabet[i] = ( char ) ( 'a' + j); |
200 | for ( int i = 52 , j = 0 ; i <= 61 ; i++, j++) { |
201 | lookUpBase64Alphabet[i] = ( char ) ( '0' + j); |
203 | lookUpBase64Alphabet[ 62 ] = ( char ) '+' ; |
204 | lookUpBase64Alphabet[ 63 ] = ( char ) '/' ; |
206 | private static boolean isWhiteSpace( char octect) { |
207 | return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9 ); |
209 | private static boolean isPad( char octect) { |
210 | return (octect == PAD); |
212 | private static boolean isData( char octect) { |
213 | return (octect < BASELENGTH && base64Alphabet[octect] != - 1 ); |
216 | * Encodes hex octects into Base64 |
219 | * Array containing binaryData |
220 | * @return Encoded Base64 array |
222 | public static String encode( byte [] binaryData) { |
223 | if (binaryData == null ) { |
226 | int lengthDataBits = binaryData.length * EIGHTBIT; |
227 | if (lengthDataBits == 0 ) { |
230 | int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; |
231 | int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; |
232 | int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 |
234 | char encodedData[] = null ; |
235 | encodedData = new char [numberQuartet * 4 ]; |
236 | byte k = 0 , l = 0 , b1 = 0 , b2 = 0 , b3 = 0 ; |
237 | int encodedIndex = 0 ; |
239 | for ( int i = 0 ; i < numberTriplets; i++) { |
240 | b1 = binaryData[dataIndex++]; |
241 | b2 = binaryData[dataIndex++]; |
242 | b3 = binaryData[dataIndex++]; |
243 | l = ( byte ) (b2 & 0x0f ); |
244 | k = ( byte ) (b1 & 0x03 ); |
245 | byte val1 = ((b1 & SIGN) == 0 ) ? ( byte ) (b1 >> 2 ) |
246 | : ( byte ) ((b1) >> 2 ^ 0xc0 ); |
247 | byte val2 = ((b2 & SIGN) == 0 ) ? ( byte ) (b2 >> 4 ) |
248 | : ( byte ) ((b2) >> 4 ^ 0xf0 ); |
249 | byte val3 = ((b3 & SIGN) == 0 ) ? ( byte ) (b3 >> 6 ) |
250 | : ( byte ) ((b3) >> 6 ^ 0xfc ); |
251 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
252 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4 )]; |
253 | encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2 ) | val3]; |
254 | encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f ]; |
257 | if (fewerThan24bits == EIGHTBIT) { |
258 | b1 = binaryData[dataIndex]; |
259 | k = ( byte ) (b1 & 0x03 ); |
260 | byte val1 = ((b1 & SIGN) == 0 ) ? ( byte ) (b1 >> 2 ) |
261 | : ( byte ) ((b1) >> 2 ^ 0xc0 ); |
262 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
263 | encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4 ]; |
264 | encodedData[encodedIndex++] = PAD; |
265 | encodedData[encodedIndex++] = PAD; |
266 | } else if (fewerThan24bits == SIXTEENBIT) { |
267 | b1 = binaryData[dataIndex]; |
268 | b2 = binaryData[dataIndex + 1 ]; |
269 | l = ( byte ) (b2 & 0x0f ); |
270 | k = ( byte ) (b1 & 0x03 ); |
271 | byte val1 = ((b1 & SIGN) == 0 ) ? ( byte ) (b1 >> 2 ) |
272 | : ( byte ) ((b1) >> 2 ^ 0xc0 ); |
273 | byte val2 = ((b2 & SIGN) == 0 ) ? ( byte ) (b2 >> 4 ) |
274 | : ( byte ) ((b2) >> 4 ^ 0xf0 ); |
275 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
276 | encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4 )]; |
277 | encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2 ]; |
278 | encodedData[encodedIndex++] = PAD; |
280 | return new String(encodedData); |
283 | * Decodes Base64 data into octects |
286 | * string containing Base64 data |
287 | * @return Array containind decoded data. |
289 | public static byte [] decode(String encoded) { |
290 | if (encoded == null ) { |
293 | char [] base64Data = encoded.toCharArray(); |
295 | int len = removeWhiteSpace(base64Data); |
296 | if (len % FOURBYTE != 0 ) { |
299 | int numberQuadruple = (len / FOURBYTE); |
300 | if (numberQuadruple == 0 ) { |
303 | byte decodedData[] = null ; |
304 | byte b1 = 0 , b2 = 0 , b3 = 0 , b4 = 0 ; |
305 | char d1 = 0 , d2 = 0 , d3 = 0 , d4 = 0 ; |
307 | int encodedIndex = 0 ; |
309 | decodedData = new byte [(numberQuadruple) * 3 ]; |
310 | for (; i < numberQuadruple - 1 ; i++) { |
311 | if (!isData((d1 = base64Data[dataIndex++])) |
312 | || !isData((d2 = base64Data[dataIndex++])) |
313 | || !isData((d3 = base64Data[dataIndex++])) |
314 | || !isData((d4 = base64Data[dataIndex++]))) { |
317 | b1 = base64Alphabet[d1]; |
318 | b2 = base64Alphabet[d2]; |
319 | b3 = base64Alphabet[d3]; |
320 | b4 = base64Alphabet[d4]; |
321 | decodedData[encodedIndex++] = ( byte ) (b1 << 2 | b2 >> 4 ); |
322 | decodedData[encodedIndex++] = ( byte ) (((b2 & 0xf ) << 4 ) | ((b3 >> 2 ) & 0xf )); |
323 | decodedData[encodedIndex++] = ( byte ) (b3 << 6 | b4); |
325 | if (!isData((d1 = base64Data[dataIndex++])) |
326 | || !isData((d2 = base64Data[dataIndex++]))) { |
329 | b1 = base64Alphabet[d1]; |
330 | b2 = base64Alphabet[d2]; |
331 | d3 = base64Data[dataIndex++]; |
332 | d4 = base64Data[dataIndex++]; |
333 | if (!isData((d3)) || !isData((d4))) { |
334 | if (isPad(d3) && isPad(d4)) { |
339 | byte [] tmp = new byte [i * 3 + 1 ]; |
340 | System.arraycopy(decodedData, 0 , tmp, 0 , i * 3 ); |
341 | tmp[encodedIndex] = ( byte ) (b1 << 2 | b2 >> 4 ); |
343 | } else if (!isPad(d3) && isPad(d4)) { |
344 | b3 = base64Alphabet[d3]; |
349 | byte [] tmp = new byte [i * 3 + 2 ]; |
350 | System.arraycopy(decodedData, 0 , tmp, 0 , i * 3 ); |
351 | tmp[encodedIndex++] = ( byte ) (b1 << 2 | b2 >> 4 ); |
352 | tmp[encodedIndex] = ( byte ) (((b2 & 0xf ) << 4 ) | ((b3 >> 2 ) & 0xf )); |
358 | b3 = base64Alphabet[d3]; |
359 | b4 = base64Alphabet[d4]; |
360 | decodedData[encodedIndex++] = ( byte ) (b1 << 2 | b2 >> 4 ); |
361 | decodedData[encodedIndex++] = ( byte ) (((b2 & 0xf ) << 4 ) | ((b3 >> 2 ) & 0xf )); |
362 | decodedData[encodedIndex++] = ( byte ) (b3 << 6 | b4); |
367 | * remove WhiteSpace from MIME containing encoded Base64 data. |
370 | * the byte array of base64 data (with WS) |
371 | * @return the new length |
373 | private static int removeWhiteSpace( char [] data) { |
379 | int len = data.length; |
380 | for ( int i = 0 ; i < len; i++) { |
381 | if (!isWhiteSpace(data[i])) { |
382 | data[newSize++] = data[i]; |
389 | private String resultStatus; |
390 | private String result; |
392 | public PayResult(String rawResult) { |
393 | if (TextUtils.isEmpty(rawResult)) |
395 | String[] resultParams = rawResult.split( ";" ); |
396 | for (String resultParam : resultParams) { |
397 | if (resultParam.startsWith( "resultStatus" )) { |
398 | resultStatus = gatValue(resultParam, "resultStatus" ); |
400 | if (resultParam.startsWith( "result" )) { |
401 | result = gatValue(resultParam, "result" ); |
403 | if (resultParam.startsWith( "memo" )) { |
404 | memo = gatValue(resultParam, "memo" ); |
409 | public String toString() { |
410 | return "resultStatus={" + resultStatus + "};memo={" + memo |
411 | + "};result={" + result + "}" ; |
413 | private String gatValue(String content, String key) { |
414 | String prefix = key + "={" ; |
415 | return content.substring(content.indexOf(prefix) + prefix.length(), |
416 | content.lastIndexOf( "}" )); |
419 | * @return the resultStatus |
421 | public String getResultStatus() { |
427 | public String getMemo() { |
433 | public String getResult() { |
438 | private static final String ALGORITHM = "RSA" ; |
439 | private static final String SIGN_ALGORITHMS = "SHA1WithRSA" ; |
440 | private static final String DEFAULT_CHARSET = "UTF-8" ; |
441 | public static String sign(String content, String privateKey) { |
443 | PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( |
444 | Base64.decode(privateKey)); |
445 | KeyFactory keyf = KeyFactory.getInstance(ALGORITHM); |
446 | PrivateKey priKey = keyf.generatePrivate(priPKCS8); |
447 | java.security.Signature signature = java.security.Signature |
448 | .getInstance(SIGN_ALGORITHMS); |
449 | signature.initSign(priKey); |
450 | signature.update(content.getBytes(DEFAULT_CHARSET)); |
451 | byte [] signed = signature.sign(); |
452 | return Base64.encode(signed); |
453 | } catch (Exception e) { |
前面的几个常量是需要去支付宝官网获取的,获取后直接替换就ok,其他的代码基本都是从demo中copy出来的, 现在我们就将支付功能封装到了一个类中,那么如何使用呢?
1 | <span style= "font-size: medium;" >Alipay alipay = new Alipay(OrderConfirmActivity. this ); |
2 | alipay.setListener(mAlipayListener); |
3 | alipay.pay(desc, mOrder.getShopName(), String.valueOf(orderAmount), orderSn, url); |
7 | private Alipay.OnAlipayListener mAlipayListener = new Alipay.OnAlipayListener() { |
9 | public void onSuccess() { |
10 | onOrderSubmitSuccess(); |
13 | public void onCancel() { |
14 | onUserOrderCanceled(); |
15 | Toast.makeText(OrderConfirmActivity. this , R.string.pay_failed, |
16 | Toast.LENGTH_SHORT).show(); |
19 | public void onWait() { |
new出对象来,只需要调用pay方法就ok啦, 不过支付的回调我们还是必须的,当然这个也不麻烦。这里说一下pay方法的几个参数,
- title 支付的标题
- desc 支付的描述
- price 支付的金额
- sn 商品的唯一货号
- url 服务器的回调url
这几个参数在做支付的时候服务器都会给到,但是要注意一下,这几个参数都不能为空或者空字符串,否则会支付失败