在做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
这几个参数在做支付的时候服务器都会给到,但是要注意一下,这几个参数都不能为空或者空字符串,否则会支付失败