支付宝应用支付
单击按钮,调用支付方法。
1 setContentView(R.layout.activity_main); 2 findViewById(R.id.button1).setOnClickListener( 3 new View.OnClickListener() { 4 @Override 5 public void onClick(View v) { 6 // TODO Auto-generated method stub 7 // 拿到 Fiap 对象并传入容器 8 Fiap fiap = new Fiap(MainActivity.this); 9 // 调用支付方法,并传入支付金额 10 fiap.android_pay(0.01); 11 } 12 }); 13 }
支付宝应用支付 Fiap.java
 
1 import java.io.BufferedReader; 2 import java.io.File; 3 import java.io.FileOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.net.HttpURLConnection; 9 import java.net.InetSocketAddress; 10 import java.net.Proxy; 11 import java.net.URL; 12 import java.net.URLEncoder; 13 import java.security.KeyFactory; 14 import java.security.PrivateKey; 15 import java.security.PublicKey; 16 import java.security.spec.PKCS8EncodedKeySpec; 17 import java.security.spec.X509EncodedKeySpec; 18 import java.util.ArrayList; 19 import java.util.List; 20 import javax.net.ssl.HostnameVerifier; 21 import javax.net.ssl.HttpsURLConnection; 22 import javax.net.ssl.SSLSession; 23 import org.apache.http.client.entity.UrlEncodedFormEntity; 24 import org.apache.http.message.BasicNameValuePair; 25 import org.json.JSONException; 26 import org.json.JSONObject; 27 import com.alipay.android.app.IAlixPay; 28 import com.alipay.android.app.IRemoteServiceCallback; 29 import android.annotation.SuppressLint; 30 import android.app.Activity; 31 import android.app.AlertDialog; 32 import android.app.ProgressDialog; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.DialogInterface; 36 import android.content.Intent; 37 import android.content.ServiceConnection; 38 import android.content.pm.PackageInfo; 39 import android.content.pm.PackageManager; 40 import android.net.ConnectivityManager; 41 import android.net.NetworkInfo; 42 import android.net.Uri; 43 import android.os.Bundle; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.RemoteException; 49 import android.util.Log; 50 import android.view.KeyEvent; 51 import android.widget.Toast; 52 53 54 @SuppressLint ("HandlerLeak") 55 public class Fiap{ 56 Activity mActivity = null; 57 58 // =================================== 59 // JAVA 的接口 60 // =================================== 61 62 63 public Fiap(Activity activity){ 64 65 mActivity = activity; 66 67 } 68 69 //这里传过来的是想支付多少钱(最好定义成double的,方便调试,毕竟每次测试都支付几元大洋不是每个人都负担的起的) 70 public void android_pay (double coin){ 71 72 //支付宝支付必须依赖网络,所以在这里必须加网络判定 73 if (!is_can_internet (mActivity)){ 74 75 fiapHandler.sendEmptyMessage(1); 76 return; 77 } 78 79 Message msg = new Message (); 80 Bundle bundle = new Bundle(); 81 bundle.putDouble("coin", coin); 82 msg.setData(bundle); 83 msg.what = 1; 84 fss.sendMessage (msg); 85 } 86 87 private Handler fiapHandler = new Handler(){ 88 89 public void handleMessage(Message msg) { 90 if (msg.what == 1) { 91 new AlertDialog.Builder (mActivity).setTitle ("提示").setMessage ("连接不到网络。").setPositiveButton ("确定", new DialogInterface.OnClickListener() { 92 @Override 93 public void onClick(DialogInterface dialog, int which) { 94 // TODO Auto-generated method stub 95 Intent intent = new Intent( 96 "android.settings.WIFI_SETTINGS"); 97 mActivity.startActivity(intent); 98 } 99 }).create ().show (); 100 } 101 }; 102 }; 103 104 // =================================== 105 // 支付宝 106 // =================================== 107 public class PartnerConfig { 108 109 110 //以下配置涉及到公司内容,所以略去,需自己配置 111 // 合作商户ID。用签约支付宝账号登录ms.alipay.com后,在账户信息页面获取。 112 public static final String PARTNER = ""; 113 // 商户收款的支付宝账号 114 public static final String SELLER = ""; 115 // 商户(RSA)私钥(注意一定要转PKCS8格式,否则在Android4.0及以上系统会支付失败) 116 public static final String RSA_PRIVATE = ""; 117 // 支付宝(RSA)公钥用签约支付宝账号登录ms.alipay.com后,在密钥管理页面获取。 118 public static final String RSA_ALIPAY_PUBLIC = ""; 119 } 120 121 122 private ProgressDialog mProgress = null; 123 124 125 public static class AlixOnCancelListener implements DialogInterface.OnCancelListener { 126 Activity mcontext; 127 128 129 AlixOnCancelListener (Activity context){ 130 mcontext = context; 131 } 132 133 134 public void onCancel (DialogInterface dialog){ 135 mcontext.onKeyDown (KeyEvent.KEYCODE_BACK, null); 136 } 137 } 138 139 140 private Handler fss = new Handler (){ 141 @SuppressWarnings ("deprecation") 142 public void handleMessage (Message msg){ 143 MobileSecurePayHelper mspHelper = new MobileSecurePayHelper (mActivity); 144 boolean isMobile_spExist = mspHelper.detectMobile_sp (); 145 if (!isMobile_spExist) 146 return; 147 // 根据订单信息开始进行支付 148 try{ 149 // 准备订单信息 150 Bundle bundle = msg.getData(); 151 double _coin = bundle.getDouble("coin"); 152 String orderInfo = getOrderInfo(_coin); 153 // 这里根据签名方式对订单信息进行签名 154 String signType = getSignType (); 155 String strsign = sign (signType, orderInfo); 156 // 对签名进行编码 157 strsign = URLEncoder.encode (strsign); 158 // 组装好参数 159 String info = orderInfo + "&sign=" + """ + strsign + """ + "&" + getSignType (); 160 // 调用pay方法进行支付 161 MobileSecurePayer msp = new MobileSecurePayer (); 162 boolean bRet = msp.pay (info, mHandler, AlixId.RQF_PAY, mActivity); 163 if (bRet){ 164 // 显示“正在支付”进度条 165 closeProgress (); 166 mProgress = BaseHelper.showProgress (mActivity, null, "正在支付", false, true); 167 } 168 } catch (Exception ex){ 169 ex.printStackTrace (); 170 } 171 } 172 }; 173 174 private Handler mHandler = new Handler (){ 175 public void handleMessage (Message msg){ 176 try{ 177 String strRet = (String) msg.obj; 178 switch (msg.what){ 179 case AlixId.RQF_PAY:{ 180 // 181 closeProgress (); 182 // 处理交易结果 183 try{ 184 // 获取交易状态码,具体状态代码请参看文档 185 String tradeStatus = "resultStatus={"; 186 int imemoStart = strRet.indexOf ("resultStatus="); 187 imemoStart += tradeStatus.length (); 188 int imemoEnd = strRet.indexOf ("};memo="); 189 tradeStatus = strRet.substring (imemoStart, imemoEnd); 190 //先验签通知 191 ResultChecker resultChecker = new ResultChecker (strRet); 192 int retVal = resultChecker.checkSign (); 193 if (retVal == ResultChecker.RESULT_CHECK_SIGN_FAILED){ 194 BaseHelper.showDialog (mActivity, "提示", "您的订单信息已被非法篡改。", android.R.drawable.ic_dialog_alert); 195 } else{ 196 if (tradeStatus.equals ("9000")){ 197 198 //程序到这里表示支付已经成功了,想干什么就在这里干吧 -v- 199 Toast.makeText(mActivity, "支付成功",Toast.LENGTH_LONG).show(); 200 Log.i("result of this pay:", "successful"); 201 202 } else if (!tradeStatus.equals ("4000")){ 203 204 //程序到这里表示此次支付失败,查看具体原因可以从这里打印个log 205 Toast.makeText(mActivity, "支付失败,交易状态码为:" + tradeStatus, Toast.LENGTH_LONG).show(); 206 Log.e("result of this pay", "falied"); 207 } 208 } 209 } catch (Exception e){ 210 e.printStackTrace (); 211 } 212 } 213 break; 214 } 215 super.handleMessage (msg); 216 } catch (Exception e){ 217 e.printStackTrace (); 218 } 219 } 220 }; 221 222 223 String getSignType (){ 224 String getSignType = "sign_type=" + """ + "RSA" + """; 225 return getSignType; 226 } 227 228 229 void closeProgress (){ 230 try{ 231 if (mProgress != null){ 232 mProgress.dismiss (); 233 mProgress = null; 234 } 235 } catch (Exception e){ 236 e.printStackTrace (); 237 } 238 } 239 240 241 String getOrderInfo (double position){ 242 243 String strOrderInfo = "partner=" + """ + PartnerConfig.PARTNER + """; 244 strOrderInfo += "&"; 245 strOrderInfo += "seller=" + """ + PartnerConfig.SELLER + """; 246 strOrderInfo += "&"; 247 strOrderInfo += "out_trade_no=" + """ + get_order_id () + """; 248 strOrderInfo += "&"; 249 250 //这里是显示到支付宝支付界面上的付费信息提示(这里一定要严格按照此格式填写) 251 strOrderInfo += "subject=" + ""猫币""; 252 strOrderInfo += "&"; 253 strOrderInfo += "body=" + ""购买猫币""; 254 strOrderInfo += "&"; 255 strOrderInfo += "total_fee=" + """ + position + """; 256 strOrderInfo += "&"; 257 strOrderInfo += "notify_url=" + """ + "http://notify.java.jpxx.org/index.jsp" + """; 258 return strOrderInfo; 259 } 260 261 262 String sign (String signType, String content){ 263 return Rsa.sign (content, PartnerConfig.RSA_PRIVATE); 264 } 265 266 267 public boolean is_can_internet (final Context context){ 268 try{ 269 ConnectivityManager manger = (ConnectivityManager) context.getSystemService (Context.CONNECTIVITY_SERVICE); 270 NetworkInfo info = manger.getActiveNetworkInfo (); 271 272 return (info != null && info.isConnected ()); 273 } catch (Exception e){ 274 275 return false; 276 } 277 } 278 279 280 public String get_order_id (){ 281 long ran1 = get_round (1111, 9999); 282 long ran2 = get_round (1111, 9999); 283 284 //注掉的这里是返回的渠道号(我们用的友盟)+随机数和当前系统时间组合 285 //return android_get_umeng_channel () + "_" + ran1 + System.currentTimeMillis () + ran2; 286 return "_"+ran1 + System.currentTimeMillis () + ran2; 287 } 288 289 290 public long get_round (int min, int max){ 291 return Math.round (Math.random () * (max - min) + min); 292 } 293 294 295 //================================================================================================= 296 // 297 // 支付宝不用动的 298 // ================================================================================================== 299 public final class AlixId { 300 public static final int BASE_ID = 0; 301 public static final int RQF_PAY = BASE_ID + 1; 302 public static final int RQF_INSTALL_CHECK = RQF_PAY + 1; 303 } 304 305 final class AlixDefine { 306 public static final String IMEI = "imei"; 307 public static final String IMSI = "imsi"; 308 public static final String KEY = "key"; 309 public static final String USER_AGENT = "user_agent"; 310 public static final String VERSION = "version"; 311 public static final String DEVICE = "device"; 312 public static final String SID = "sid"; 313 public static final String partner = "partner"; 314 public static final String charset = "charset"; 315 public static final String sign_type = "sign_type"; 316 public static final String sign = "sign"; 317 public static final String URL = "URL"; 318 public static final String split = "&"; 319 public static final String AlixPay = "AlixPay"; 320 public static final String action = "action"; 321 public static final String actionUpdate = "update"; 322 public static final String data = "data"; 323 public static final String platform = "platform"; 324 } 325 326 public static final class Base64 { 327 static private final int BASELENGTH = 128; 328 static private final int LOOKUPLENGTH = 64; 329 static private final int TWENTYFOURBITGROUP = 24; 330 static private final int EIGHTBIT = 8; 331 static private final int SIXTEENBIT = 16; 332 static private final int FOURBYTE = 4; 333 static private final int SIGN = -128; 334 static private final char PAD = '='; 335 static private final boolean fDebug = false; 336 static final private byte[] base64Alphabet = new byte[BASELENGTH]; 337 static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; 338 static{ 339 for (int i = 0; i < BASELENGTH; ++i){ 340 base64Alphabet[i] = -1; 341 } 342 for (int i = 'Z'; i >= 'A'; i--){ 343 base64Alphabet[i] = (byte) (i - 'A'); 344 } 345 for (int i = 'z'; i >= 'a'; i--){ 346 base64Alphabet[i] = (byte) (i - 'a' + 26); 347 } 348 for (int i = '9'; i >= '0'; i--){ 349 base64Alphabet[i] = (byte) (i - '0' + 52); 350 } 351 base64Alphabet['+'] = 62; 352 base64Alphabet['/'] = 63; 353 for (int i = 0; i <= 25; i++){ 354 lookUpBase64Alphabet[i] = (char) ('A' + i); 355 } 356 for (int i = 26, j = 0; i <= 51; i++, j++){ 357 lookUpBase64Alphabet[i] = (char) ('a' + j); 358 } 359 for (int i = 52, j = 0; i <= 61; i++, j++){ 360 lookUpBase64Alphabet[i] = (char) ('0' + j); 361 } 362 lookUpBase64Alphabet[62] = (char) '+'; 363 lookUpBase64Alphabet[63] = (char) '/'; 364 } 365 366 367 private static boolean isWhiteSpace (char octect){ 368 return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); 369 } 370 371 372 private static boolean isPad (char octect){ 373 return (octect == PAD); 374 } 375 376 377 private static boolean isData (char octect){ 378 return (octect < BASELENGTH && base64Alphabet[octect] != -1); 379 } 380 381 382 383 public static String encode (byte[] binaryData){ 384 if (binaryData == null){ 385 return null; 386 } 387 int lengthDataBits = binaryData.length * EIGHTBIT; 388 if (lengthDataBits == 0){ 389 return ""; 390 } 391 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 392 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 393 int numberQuartet = fewerThan24bits != 0? numberTriplets + 1 : numberTriplets; 394 char encodedData[] = null; 395 encodedData = new char[numberQuartet * 4]; 396 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 397 int encodedIndex = 0; 398 int dataIndex = 0; 399 if (fDebug){ 400 System.out.println ("number of triplets = " + numberTriplets); 401 } 402 for (int i = 0; i < numberTriplets; i++){ 403 b1 = binaryData[dataIndex++]; 404 b2 = binaryData[dataIndex++]; 405 b3 = binaryData[dataIndex++]; 406 if (fDebug){ 407 System.out.println ("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3); 408 } 409 l = (byte) (b2 & 0x0f); 410 k = (byte) (b1 & 0x03); 411 byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 412 byte val2 = ((b2 & SIGN) == 0)? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 413 byte val3 = ((b3 & SIGN) == 0)? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); 414 if (fDebug){ 415 System.out.println ("val2 = " + val2); 416 System.out.println ("k4 = " + (k << 4)); 417 System.out.println ("vak = " + (val2 | (k << 4))); 418 } 419 encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 420 encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 421 encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; 422 encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; 423 } 424 // form integral number of 6-bit groups 425 if (fewerThan24bits == EIGHTBIT){ 426 b1 = binaryData[dataIndex]; 427 k = (byte) (b1 & 0x03); 428 if (fDebug){ 429 System.out.println ("b1=" + b1); 430 System.out.println ("b1<<2 = " + (b1 >> 2)); 431 } 432 byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 433 encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 434 encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; 435 encodedData[encodedIndex++] = PAD; 436 encodedData[encodedIndex++] = PAD; 437 } else if (fewerThan24bits == SIXTEENBIT){ 438 b1 = binaryData[dataIndex]; 439 b2 = binaryData[dataIndex + 1]; 440 l = (byte) (b2 & 0x0f); 441 k = (byte) (b1 & 0x03); 442 byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 443 byte val2 = ((b2 & SIGN) == 0)? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 444 encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; 445 encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; 446 encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; 447 encodedData[encodedIndex++] = PAD; 448 } 449 return new String (encodedData); 450 } 451 452 453 454 public static byte[] decode (String encoded){ 455 if (encoded == null){ 456 return null; 457 } 458 char[] base64Data = encoded.toCharArray (); 459 // remove white spaces 460 int len = removeWhiteSpace (base64Data); 461 if (len % FOURBYTE != 0){ 462 return null;// should be divisible by four 463 } 464 int numberQuadruple = (len / FOURBYTE); 465 if (numberQuadruple == 0){ 466 return new byte[0]; 467 } 468 byte decodedData[] = null; 469 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; 470 char d1 = 0, d2 = 0, d3 = 0, d4 = 0; 471 int i = 0; 472 int encodedIndex = 0; 473 int dataIndex = 0; 474 decodedData = new byte[(numberQuadruple) * 3]; 475 for (; i < numberQuadruple - 1; i++){ 476 if (!isData ((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++])) || !isData ((d3 = base64Data[dataIndex++])) || !isData ((d4 = base64Data[dataIndex++]))){ 477 return null; 478 }// if found "no data" just return null 479 b1 = base64Alphabet[d1]; 480 b2 = base64Alphabet[d2]; 481 b3 = base64Alphabet[d3]; 482 b4 = base64Alphabet[d4]; 483 decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 484 decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 485 decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 486 } 487 if (!isData ((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++]))){ 488 return null;// if found "no data" just return null 489 } 490 b1 = base64Alphabet[d1]; 491 b2 = base64Alphabet[d2]; 492 d3 = base64Data[dataIndex++]; 493 d4 = base64Data[dataIndex++]; 494 if (!isData ((d3)) || !isData ((d4))){// Check if they are PAD characters 495 if (isPad (d3) && isPad (d4)){ 496 if ((b2 & 0xf) != 0)// last 4 bits should be zero 497 { 498 return null; 499 } 500 byte[] tmp = new byte[i * 3 + 1]; 501 System.arraycopy (decodedData, 0, tmp, 0, i * 3); 502 tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 503 return tmp; 504 } else if (!isPad (d3) && isPad (d4)){ 505 b3 = base64Alphabet[d3]; 506 if ((b3 & 0x3) != 0)// last 2 bits should be zero 507 { 508 return null; 509 } 510 byte[] tmp = new byte[i * 3 + 2]; 511 System.arraycopy (decodedData, 0, tmp, 0, i * 3); 512 tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 513 tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 514 return tmp; 515 } else{ 516 return null; 517 } 518 } else{ // No PAD e.g 3cQl 519 b3 = base64Alphabet[d3]; 520 b4 = base64Alphabet[d4]; 521 decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); 522 decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 523 decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); 524 } 525 return decodedData; 526 } 527 528 529 530 private static int removeWhiteSpace (char[] data){ 531 if (data == null){ 532 return 0; 533 } 534 // count characters that's not whitespace 535 int newSize = 0; 536 int len = data.length; 537 for (int i = 0; i < len; i++){ 538 if (!isWhiteSpace (data[i])){ 539 data[newSize++] = data[i]; 540 } 541 } 542 return newSize; 543 } 544 } 545 546 public static class BaseHelper { 547 548 public static String convertStreamToString (InputStream is){ 549 BufferedReader reader = new BufferedReader (new InputStreamReader (is)); 550 StringBuilder sb = new StringBuilder (); 551 String line = null; 552 try{ 553 while ((line = reader.readLine ()) != null){ 554 sb.append (line); 555 } 556 } catch (IOException e){ 557 e.printStackTrace (); 558 } finally{ 559 try{ 560 is.close (); 561 } catch (IOException e){ 562 e.printStackTrace (); 563 } 564 } 565 return sb.toString (); 566 } 567 568 569 570 public static void showDialog (Activity context, String strTitle, String strText, int icon){ 571 AlertDialog.Builder tDialog = new AlertDialog.Builder (context); 572 tDialog.setIcon (icon); 573 tDialog.setTitle (strTitle); 574 tDialog.setMessage (strText); 575 tDialog.setPositiveButton ("确定", null); 576 tDialog.show (); 577 } 578 579 580 581 public static void log (String tag, String info){ 582 // Log.d(tag, info); 583 } 584 585 586 587 public static void chmod (String permission, String path){ 588 try{ 589 String command = "chmod " + permission + " " + path; 590 Runtime runtime = Runtime.getRuntime (); 591 runtime.exec (command); 592 } catch (IOException e){ 593 e.printStackTrace (); 594 } 595 } 596 597 598 // 599 // show the progress bar. 600 601 public static ProgressDialog showProgress (Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable){ 602 ProgressDialog dialog = new ProgressDialog (context); 603 dialog.setTitle (title); 604 dialog.setMessage (message); 605 dialog.setIndeterminate (indeterminate); 606 dialog.setCancelable (false); 607 // dialog.setDefaultButton(false); 608 dialog.setOnCancelListener (new Fiap.AlixOnCancelListener ((Activity) context)); 609 dialog.show (); 610 return dialog; 611 } 612 613 614 615 public static JSONObject string2JSON (String str, String split){ 616 JSONObject json = new JSONObject (); 617 try{ 618 String[] arrStr = str.split (split); 619 for (int i = 0; i < arrStr.length; i++){ 620 String[] arrKeyValue = arrStr[i].split ("="); 621 json.put (arrKeyValue[0], arrStr[i].substring (arrKeyValue[0].length () + 1)); 622 } 623 } catch (Exception e){ 624 e.printStackTrace (); 625 } 626 return json; 627 } 628 } 629 630 public class Constant { 631 public final static String server_url = "https://msp.alipay.com/x.htm"; 632 } 633 634 public class MobileSecurePayer { 635 Integer lock = 0; 636 IAlixPay mAlixPay = null; 637 boolean mbPaying = false; 638 Activity mActivity = null; 639 // 和安全支付服务建立连接 640 private ServiceConnection mAlixPayConnection = new ServiceConnection (){ 641 public void onServiceConnected (ComponentName className, IBinder service){ 642 // 643 // wake up the binder to continue. 644 // 获得通信通道 645 synchronized (lock){ 646 mAlixPay = IAlixPay.Stub.asInterface (service); 647 lock.notify (); 648 } 649 } 650 651 652 public void onServiceDisconnected (ComponentName className){ 653 mAlixPay = null; 654 } 655 }; 656 657 658 659 public boolean pay (final String strOrderInfo, final Handler callback, final int myWhat, final Activity activity){ 660 if (mbPaying) 661 return false; 662 mbPaying = true; 663 // 664 mActivity = activity; 665 // bind the service. 666 // 绑定服务 667 if (mAlixPay == null){ 668 // 绑定安全支付服务需要获取上下文环境, 669 // 如果绑定不成功使用mActivity.getApplicationContext().bindService 670 // 解绑时同理 671 mActivity.getApplicationContext ().bindService (new Intent (IAlixPay.class.getName ()), mAlixPayConnection, Context.BIND_AUTO_CREATE); 672 } 673 // else ok. 674 // 实例一个线程来进行支付 675 new Thread (new Runnable (){ 676 public void run (){ 677 try{ 678 // wait for the service bind operation to completely 679 // finished. 680 // Note: this is important,otherwise the next mAlixPay.Pay() 681 // will fail. 682 // 等待安全支付服务绑定操作结束 683 // 注意:这里很重要,否则mAlixPay.Pay()方法会失败 684 synchronized (lock){ 685 if (mAlixPay == null) 686 lock.wait (); 687 } 688 // register a Callback for the service. 689 // 为安全支付服务注册一个回调 690 mAlixPay.registerCallback (mCallback); 691 // call the MobileSecurePay service. 692 // 调用安全支付服务的pay方法 693 String strRet = mAlixPay.Pay (strOrderInfo); 694 // set the flag to indicate that we have finished. 695 // unregister the Callback, and unbind the service. 696 // 将mbPaying置为false,表示支付结束 697 // 移除回调的注册,解绑安全支付服务 698 mbPaying = false; 699 mAlixPay.unregisterCallback (mCallback); 700 mActivity.getApplicationContext ().unbindService (mAlixPayConnection); 701 // send the result back to caller. 702 // 发送交易结果 703 Message msg = new Message (); 704 msg.what = myWhat; 705 msg.obj = strRet; 706 callback.sendMessage (msg); 707 } catch (Exception e){ 708 e.printStackTrace (); 709 // send the result back to caller. 710 // 发送交易结果 711 Message msg = new Message (); 712 msg.what = myWhat; 713 msg.obj = e.toString (); 714 callback.sendMessage (msg); 715 } 716 } 717 }).start (); 718 return true; 719 } 720 721 722 723 private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub (){ 724 725 public void startActivity (String packageName, String className, int iCallingPid, Bundle bundle) throws RemoteException{ 726 Intent intent = new Intent (Intent.ACTION_MAIN, null); 727 if (bundle == null) 728 bundle = new Bundle (); 729 // else ok. 730 try{ 731 bundle.putInt ("CallingPid", iCallingPid); 732 intent.putExtras (bundle); 733 } catch (Exception e){ 734 e.printStackTrace (); 735 } 736 intent.setClassName (packageName, className); 737 mActivity.startActivity (intent); 738 } 739 740 741 @Override 742 public boolean isHideLoadingScreen () throws RemoteException{ 743 return false; 744 } 745 746 747 @Override 748 public void payEnd (boolean arg0, String arg1) throws RemoteException{ 749 750 } 751 }; 752 } 753 754 public class MobileSecurePayHelper { 755 static final String TAG = "MobileSecurePayHelper"; 756 private ProgressDialog mProgress = null; 757 Context mContext = null; 758 759 760 public MobileSecurePayHelper (Context context){ 761 this.mContext = context; 762 } 763 764 765 766 public boolean detectMobile_sp (){ 767 boolean isMobile_spExist = isMobile_spExist (); 768 if (!isMobile_spExist){ 769 // 获取系统缓冲绝对路径获取/data/data//cache目录 770 File cacheDir = mContext.getCacheDir (); 771 final String cachePath = cacheDir.getAbsolutePath () + "/temp.apk"; 772 mProgress = BaseHelper.showProgress (mContext, null, "正在检测安全支付服务版本", false, true); 773 // 实例新线程检测是否有新版本进行下载 774 new Thread (new Runnable (){ 775 public void run (){ 776 // 检测是否有新的版本。 777 String newApkdlUrl = checkNewUpdate (); 778 closeProgress (); 779 // 动态下载 780 if (newApkdlUrl != null) 781 retrieveApkFromNet (mContext, newApkdlUrl, cachePath); 782 showInstallConfirmDialog (mContext, cachePath); 783 } 784 }).start (); 785 } 786 return isMobile_spExist; 787 } 788 789 790 791 public void showInstallConfirmDialog (final Context context, final String cachePath){ 792 Looper.prepare (); 793 AlertDialog.Builder tDialog = new AlertDialog.Builder (context); 794 tDialog.setTitle ("安装提示"); 795 tDialog.setMessage ("为保证您的交易安全,需要您安装支付宝安全支付服务,才能进行付款。\n\n点击确定,立即安装。"); 796 tDialog.setPositiveButton ("确定", new DialogInterface.OnClickListener (){ 797 public void onClick (DialogInterface dialog, int which){ 798 // 799 // 修改apk权限 800 BaseHelper.chmod ("777", cachePath); 801 // 802 // install the apk. 803 // 安装安全支付服务APK 804 Intent intent = new Intent (Intent.ACTION_VIEW); 805 intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); 806 intent.setDataAndType (Uri.parse ("file://" + cachePath), "application/vnd.android.package-archive"); 807 context.startActivity (intent); 808 } 809 }); 810 tDialog.setNegativeButton ("取消", new DialogInterface.OnClickListener (){ 811 public void onClick (DialogInterface dialog, int which){} 812 }); 813 tDialog.show (); 814 Looper.loop (); 815 } 816 817 818 819 public boolean isMobile_spExist (){ 820 PackageManager manager = mContext.getPackageManager (); 821 List<PackageInfo> pkgList = manager.getInstalledPackages (0); 822 for (int i = 0; i < pkgList.size (); i++){ 823 PackageInfo pI = pkgList.get (i); 824 if (pI.packageName.equalsIgnoreCase ("com.alipay.android.app")) 825 return true; 826 } 827 return false; 828 } 829 830 831 832 public boolean retrieveApkFromAssets (Context context, String fileName, String path){ 833 boolean bRet = false; 834 try{ 835 InputStream is = context.getAssets ().open (fileName); 836 File file = new File (path); 837 file.createNewFile (); 838 FileOutputStream fos = new FileOutputStream (file); 839 byte[] temp = new byte[1024]; 840 int i = 0; 841 while ((i = is.read (temp)) > 0){ 842 fos.write (temp, 0, i); 843 } 844 fos.close (); 845 is.close (); 846 bRet = true; 847 } catch (IOException e){ 848 e.printStackTrace (); 849 } 850 return bRet; 851 } 852 853 854 855 public PackageInfo getApkInfo (Context context, String archiveFilePath){ 856 PackageManager pm = context.getPackageManager (); 857 PackageInfo apkInfo = pm.getPackageArchiveInfo (archiveFilePath, PackageManager.GET_META_DATA); 858 return apkInfo; 859 } 860 861 862 863 public String checkNewUpdate (){ 864 String url = null; 865 try{ 866 // JSONObject resp = sendCheckNewUpdate (packageInfo.versionName); 867 JSONObject resp = sendCheckNewUpdate("1.0.0"); 868 if (resp.getString ("needUpdate").equalsIgnoreCase ("true")){ 869 url = resp.getString ("updateUrl"); 870 } 871 // else ok. 872 } catch (Exception e){ 873 e.printStackTrace (); 874 } 875 return url; 876 } 877 878 879 880 public JSONObject sendCheckNewUpdate (String versionName){ 881 JSONObject objResp = null; 882 try{ 883 JSONObject req = new JSONObject (); 884 req.put (AlixDefine.action, AlixDefine.actionUpdate); 885 JSONObject data = new JSONObject (); 886 data.put (AlixDefine.platform, "android"); 887 data.put (AlixDefine.VERSION, versionName); 888 data.put (AlixDefine.partner, ""); 889 req.put (AlixDefine.data, data); 890 objResp = sendRequest (req.toString ()); 891 } catch (JSONException e){ 892 e.printStackTrace (); 893 } 894 return objResp; 895 } 896 897 898 899 public JSONObject sendRequest (final String content){ 900 NetworkManager nM = new NetworkManager (this.mContext); 901 // 902 JSONObject jsonResponse = null; 903 try{ 904 String response = null; 905 synchronized (nM){ 906 // 907 response = nM.SendAndWaitResponse (content, Constant.server_url); 908 } 909 jsonResponse = new JSONObject (response); 910 } catch (Exception e){ 911 e.printStackTrace (); 912 } 913 // 914 if (jsonResponse != null) 915 BaseHelper.log (TAG, jsonResponse.toString ()); 916 return jsonResponse; 917 } 918 919 920 921 public boolean retrieveApkFromNet (Context context, String strurl, String filename){ 922 boolean bRet = false; 923 try{ 924 NetworkManager nM = new NetworkManager (this.mContext); 925 bRet = nM.urlDownloadToFile (context, strurl, filename); 926 } catch (Exception e){ 927 e.printStackTrace (); 928 } 929 return bRet; 930 } 931 932 933 // 934 // close the progress bar 935 void closeProgress (){ 936 try{ 937 if (mProgress != null){ 938 mProgress.dismiss (); 939 mProgress = null; 940 } 941 } catch (Exception e){ 942 e.printStackTrace (); 943 } 944 } 945 } 946 947 public class NetworkManager { 948 static final String TAG = "NetworkManager"; 949 private int connectTimeout = 30 * 1000; 950 private int readTimeout = 30 * 1000; 951 Proxy mProxy = null; 952 Context mContext; 953 954 955 public NetworkManager (Context context){ 956 this.mContext = context; 957 setDefaultHostnameVerifier (); 958 } 959 960 961 962 @SuppressWarnings ("deprecation") 963 private void detectProxy (){ 964 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService (Context.CONNECTIVITY_SERVICE); 965 NetworkInfo ni = cm.getActiveNetworkInfo (); 966 if (ni != null && ni.isAvailable () && ni.getType () == ConnectivityManager.TYPE_MOBILE){ 967 String proxyHost = android.net.Proxy.getDefaultHost (); 968 int port = android.net.Proxy.getDefaultPort (); 969 if (proxyHost != null){ 970 final InetSocketAddress sa = new InetSocketAddress (proxyHost, port); 971 mProxy = new Proxy (Proxy.Type.HTTP, sa); 972 } 973 } 974 } 975 976 977 private void setDefaultHostnameVerifier (){ 978 // 979 HostnameVerifier hv = new HostnameVerifier (){ 980 public boolean verify (String hostname, SSLSession session){ 981 return true; 982 } 983 }; 984 HttpsURLConnection.setDefaultHostnameVerifier (hv); 985 } 986 987 988 989 public String SendAndWaitResponse (String strReqData, String strUrl){ 990 // 991 detectProxy (); 992 String strResponse = null; 993 ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair> (); 994 pairs.add (new BasicNameValuePair ("requestData", strReqData)); 995 HttpURLConnection httpConnect = null; 996 UrlEncodedFormEntity p_entity; 997 try{ 998 p_entity = new UrlEncodedFormEntity (pairs, "utf-8"); 999 URL url = new URL (strUrl); 1000 if (mProxy != null){ 1001 httpConnect = (HttpURLConnection) url.openConnection (mProxy); 1002 } else{ 1003 httpConnect = (HttpURLConnection) url.openConnection (); 1004 } 1005 httpConnect.setConnectTimeout (connectTimeout); 1006 httpConnect.setReadTimeout (readTimeout); 1007 httpConnect.setDoOutput (true); 1008 httpConnect.addRequestProperty ("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); 1009 httpConnect.connect (); 1010 OutputStream os = httpConnect.getOutputStream (); 1011 p_entity.writeTo (os); 1012 os.flush (); 1013 InputStream content = httpConnect.getInputStream (); 1014 strResponse = BaseHelper.convertStreamToString (content); 1015 BaseHelper.log (TAG, "response " + strResponse); 1016 } catch (IOException e){ 1017 e.printStackTrace (); 1018 } finally{ 1019 httpConnect.disconnect (); 1020 } 1021 return strResponse; 1022 } 1023 1024 1025 1026 public boolean urlDownloadToFile (Context context, String strurl, String path){ 1027 boolean bRet = false; 1028 // 1029 detectProxy (); 1030 try{ 1031 URL url = new URL (strurl); 1032 HttpURLConnection conn = null; 1033 if (mProxy != null){ 1034 conn = (HttpURLConnection) url.openConnection (mProxy); 1035 } else{ 1036 conn = (HttpURLConnection) url.openConnection (); 1037 } 1038 conn.setConnectTimeout (connectTimeout); 1039 conn.setReadTimeout (readTimeout); 1040 conn.setDoInput (true); 1041 conn.connect (); 1042 InputStream is = conn.getInputStream (); 1043 File file = new File (path); 1044 file.createNewFile (); 1045 FileOutputStream fos = new FileOutputStream (file); 1046 byte[] temp = new byte[1024]; 1047 int i = 0; 1048 while ((i = is.read (temp)) > 0){ 1049 fos.write (temp, 0, i); 1050 } 1051 fos.close (); 1052 is.close (); 1053 bRet = true; 1054 } catch (IOException e){ 1055 e.printStackTrace (); 1056 } 1057 return bRet; 1058 } 1059 } 1060 1061 public class ResultChecker { 1062 public static final int RESULT_INVALID_PARAM = 0; 1063 public static final int RESULT_CHECK_SIGN_FAILED = 1; 1064 public static final int RESULT_CHECK_SIGN_SUCCEED = 2; 1065 String mContent; 1066 1067 1068 public ResultChecker (String content){ 1069 this.mContent = content; 1070 } 1071 1072 1073 1074 int checkSign (){ 1075 int retVal = RESULT_CHECK_SIGN_SUCCEED; 1076 try{ 1077 JSONObject objContent = BaseHelper.string2JSON (this.mContent, ";"); 1078 String result = objContent.getString ("result"); 1079 result = result.substring (1, result.length () - 1); 1080 // 获取待签名数据 1081 int iSignContentEnd = result.indexOf ("&sign_type="); 1082 String signContent = result.substring (0, iSignContentEnd); 1083 // 获取签名 1084 JSONObject objResult = BaseHelper.string2JSON (result, "&"); 1085 String signType = objResult.getString ("sign_type"); 1086 signType = signType.replace (""", ""); 1087 String sign = objResult.getString ("sign"); 1088 sign = sign.replace (""", ""); 1089 // 进行验签 返回验签结果 1090 if (signType.equalsIgnoreCase ("RSA")){ 1091 if (!Rsa.doCheck (signContent, sign, PartnerConfig.RSA_ALIPAY_PUBLIC)) 1092 retVal = RESULT_CHECK_SIGN_FAILED; 1093 } 1094 } catch (Exception e){ 1095 retVal = RESULT_INVALID_PARAM; 1096 e.printStackTrace (); 1097 } 1098 return retVal; 1099 } 1100 } 1101 1102 public static class Rsa { 1103 public static final String SIGN_ALGORITHMS = "SHA1WithRSA"; 1104 1105 1106 public static String sign (String content, String privateKey){ 1107 String charset = "utf-8"; 1108 try{ 1109 PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec (Base64.decode (privateKey)); 1110 KeyFactory keyf = KeyFactory.getInstance ("RSA"); 1111 PrivateKey priKey = keyf.generatePrivate (priPKCS8); 1112 java.security.Signature signature = java.security.Signature.getInstance (SIGN_ALGORITHMS); 1113 signature.initSign (priKey); 1114 signature.update (content.getBytes (charset)); 1115 byte[] signed = signature.sign (); 1116 return Base64.encode (signed); 1117 } catch (Exception e){ 1118 e.printStackTrace (); 1119 } 1120 return null; 1121 } 1122 1123 1124 public static boolean doCheck (String content, String sign, String publicKey){ 1125 try{ 1126 KeyFactory keyFactory = KeyFactory.getInstance ("RSA"); 1127 byte[] encodedKey = Base64.decode (publicKey); 1128 PublicKey pubKey = keyFactory.generatePublic (new X509EncodedKeySpec (encodedKey)); 1129 java.security.Signature signature = java.security.Signature.getInstance (SIGN_ALGORITHMS); 1130 signature.initVerify (pubKey); 1131 signature.update (content.getBytes ("utf-8")); 1132 boolean bverify = signature.verify (Base64.decode (sign)); 1133 return bverify; 1134 } catch (Exception e){ 1135 e.printStackTrace (); 1136 } 1137 return false; 1138 } 1139 } 1140 }
 
                    
                
 
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号