Android应用集成支付宝接口的简化 拿到支付宝接口的andriod demo后有点无语,集成一个支付服务而已,要在十几个java类之间引用来引用去,这样不仅容易导致应用本身代码结构的复杂化,调试起来也很累,于是操刀改造之: 该删的删,该改写的改写,MobileSecurePayer之外的内容全部整合到MobileSecurePayerHelper之中。 /* * Copyright (C) 2010 The MobileSecurePay Project * All right reserved. * author: shiqun.shi@alipay.com *modify: fangle */ package com.alipay.android; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.List; import javax.crypto.Cipher; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.util.Base64; public class MobileSecurePayHelper { static final String TAG = "MobileSecurePayHelper"; public static final String PARTNER = ""; public static final String SELLER = ""; public static final String RSA_PRIVATE = ""; public static final String RSA_ALIPAY_PUBLIC = ""; Context mContext = null; Handler mHandler = null; String mUrl = null; String mPath = null; public static String Stream2String(InputStream is) { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; try { while ((line = reader.readLine()) != null) sb.append(line); is.close(); } catch (IOException e) { e.printStackTrace(); } return sb.toString(); } public static JSONObject string2JSON(String str, String split) { JSONObject json = new JSONObject(); try { String[] arrStr = str.split(split); for (int i = 0; i < arrStr.length; i++) { String[] arrKeyValue = arrStr[i].split("="); json.put(arrKeyValue[0], arrStr[i].substring(arrKeyValue[0].length() + 1)); } } catch (Exception e) { e.printStackTrace(); } return json; } public static String SendAndWaitResponse(String strReqData, String strUrl) { String strResponse = null; ArrayList pairs = new ArrayList(); pairs.add(new BasicNameValuePair("requestData", strReqData)); HttpURLConnection conn = null; UrlEncodedFormEntity p_entity; try { p_entity = new UrlEncodedFormEntity(pairs, "utf-8"); URL url = new URL(strUrl); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(30 * 1000); conn.setReadTimeout(30 * 1000); conn.setDoOutput(true); conn.addRequestProperty("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); conn.connect(); OutputStream os = conn.getOutputStream(); p_entity.writeTo(os); os.flush(); InputStream content = conn.getInputStream(); strResponse = Stream2String(content); } catch (IOException e) { e.printStackTrace(); } finally { conn.disconnect(); } return strResponse; } public static boolean urlDownloadToFile(Context context, String strurl, String path) { boolean bRet = false; try { URL url = new URL(strurl); HttpURLConnection conn = null; conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(30 * 1000); conn.setReadTimeout(30 * 1000); conn.setDoInput(true); conn.connect(); InputStream is = conn.getInputStream(); File file = new File(path); file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); byte[] temp = new byte[1024]; int i = 0; while ((i = is.read(temp)) > 0) fos.write(temp, 0, i); fos.close(); is.close(); bRet = true; } catch (IOException e) { e.printStackTrace(); } return bRet; } public static String RsaEncode(String content, String key) { try { X509EncodedKeySpec x509 = new X509EncodedKeySpec(Base64.decode(key, Base64.DEFAULT)); KeyFactory kf = KeyFactory.getInstance("RSA"); PublicKey pubKey = kf.generatePublic(x509); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, pubKey); byte plaintext[] = content.getBytes("UTF-8"); byte[] output = cipher.doFinal(plaintext); return new String(Base64.encode(output, Base64.DEFAULT)); } catch (Exception e) { e.printStackTrace(); } return null; } public static String RsaSign(String content, String privateKey) { try { PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(Base64.decode( privateKey, Base64.DEFAULT)); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey priKey = kf.generatePrivate(pkcs8); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(priKey); signature.update(content.getBytes("utf-8")); byte[] signed = signature.sign(); return new String(Base64.encode(signed, Base64.DEFAULT)); } catch (Exception e) { e.printStackTrace(); } return null; } public static boolean RsaCheck(String content, String sign, String publicKey) { try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); byte[] encodedKey = Base64.decode(publicKey, Base64.DEFAULT); PublicKey pubKey = keyFactory .generatePublic(new X509EncodedKeySpec(encodedKey)); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(pubKey); signature.update(content.getBytes("utf-8")); boolean bverify = signature.verify(Base64.decode(sign, Base64.DEFAULT)); return bverify; } catch (Exception e) { e.printStackTrace(); } return false; } public MobileSecurePayHelper(Context context, Handler handler) { mContext = context; mHandler = handler; } public boolean detectService() { boolean isExist = false; List pkgList = mContext.getPackageManager() .getInstalledPackages(0); for (int i = 0; i < pkgList.size(); i++) { if (pkgList.get(i).packageName .equalsIgnoreCase("com.alipay.android.app")) isExist = true; } return isExist; } public void downloadAliMSP() { JSONObject Resp = null; try { JSONObject req = new JSONObject(); req.put("action", "update"); JSONObject data = new JSONObject(); data.put("platform", "android"); data.put("version", "2.2.3"); data.put("partner", ""); req.put("data", data); Resp = new JSONObject(SendAndWaitResponse(req.toString(), "https://msp.alipay.com/x.htm")); mUrl = Resp.getString("updateUrl"); } catch (JSONException e) { e.printStackTrace(); return; } new Thread(new Runnable() { public void run() { mPath = mContext.getCacheDir().getAbsolutePath() + "/temp.apk"; urlDownloadToFile(mContext, mUrl, mPath); Message msg = new Message(); msg.what = 2; mHandler.sendMessage(msg); } }).start(); } public void installAliMSP() { if (mPath == null) return; try { Runtime.getRuntime().exec("chmod 777 " + mPath); } catch (IOException e) { e.printStackTrace(); } Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.parse("file://" + mPath), "application/vnd.android.package-archive"); mContext.startActivity(intent); } } 集成很简单,一个OnClickListener负责调用支付服务,一个Handler负责处理支付过程中的相应事件: private Handler m_mspHandler = new Handler() { public void handleMessage(Message m) { // 1:支付返回 // 2:支付组件下载完成 TextView tv = (TextView) findViewById(R.id.order_tips); Button bt = (Button) findViewById(R.id.order_ok); ProgressBar pb = (ProgressBar) findViewById(R.id.order_wait); switch (m.what) { case 1: String ret = (String) m.obj; String memo = "memo={"; int start = ret.indexOf(memo) + memo.length(); int end = ret.indexOf("};result="); memo = ret.substring(start, end); m_tips += memo; if (memo.indexOf("付款成功") >= 0) m_tips += "\r\n请注意查看短信,您将收到二维码凭证"; tv.setText(m_tips); bt.setVisibility(0); pb.setVisibility(4); break; case 2: m_tips += "安全支付组件下载完成,开始安装...\r\n"; tv.setText(m_tips); m_mspHelper.installAliMSP(); bt.setVisibility(0); pb.setVisibility(4); break; } } }; private OnClickListener m_orderButtonListener = new OnClickListener() { public void onClick(View v) { String mobile = m_mobileEdt.getText().toString(); m_tips = ""; TextView tv = (TextView) findViewById(R.id.order_tips); Button bt = (Button) findViewById(R.id.order_ok); ProgressBar pb = (ProgressBar) findViewById(R.id.order_wait); if (mobile.length() != 11) { m_tips += "无效的收货号码\r\n"; tv.setText(m_tips); return; } if (!m_date.after(m_today)) { m_tips += "订货日期不能早于明天\r\n"; tv.setText(m_tips); return; } SoapObject request = new SoapObject("http://airtimes.cn/", "MakeOrder"); request.addProperty("Uname", m_intent.getStringExtra("userid")); request.addProperty("ProductId", m_intent.getStringExtra("item_PID")); request.addProperty("Sum", "1"); request.addProperty("PayAmount", m_intent.getStringExtra("item_price")); request.addProperty("SMSMobile", mobile); request.addProperty( "ExpireDate", String.format("%04d-%02d-%02d", m_date.get(1), m_date.get(2) + 1, m_date.get(5))); // 显示等待条,提交订单信息 m_tips += "正在创建订单,请稍候...\r\n"; tv.setText(m_tips); bt.setVisibility(4); pb.setVisibility(0); HttpTransportSE httpTransport = new HttpTransportSE( "http://www.android-study.com/serv.asmx"); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( SoapEnvelope.VER11); envelope.dotNet = true; envelope.bodyOut = request; String respond; try { httpTransport.call(request.getNamespace() + request.getName(), envelope); if (envelope.getResponse() != null) respond = envelope.getResponse().toString(); else respond = "false,null"; } catch (Exception ex) { respond = "false," + ex.getMessage(); } if (respond.substring(0, 5).equals("false")) { m_tips += "创建订单失败:" + respond.substring(6) + "\r\n"; tv.setText(m_tips); bt.setVisibility(0); pb.setVisibility(4); return; } String msgs[] = respond.split("[,]"); String order; m_tips += "创建订单成功,开始支付...\r\n"; tv.setText(m_tips); if (!m_mspHelper.detectService()) { m_tips += "未安装安全支付组件,开始下载...\r\n"; tv.setText(m_tips); m_mspHelper.downloadAliMSP(); return; } order = String.format("partner=\"%s\"", MobileSecurePayHelper.PARTNER); order += String.format("&seller=\"%s\"", MobileSecurePayHelper.SELLER); order += String.format("&out_trade_no=\"%s\"", msgs[1]); order += String.format("&subject=\"%s\"", m_intent.getStringExtra("item_type")); order += String.format("&body=\"%s\"", m_intent.getStringExtra("item_name")); order += String.format("&total_fee=\"%s\"", m_intent.getStringExtra("item_price")); order += String.format("¬ify_url=\"%s\"", "http://www.android-study.com/alipay.aspx"); String sign = URLEncoder.encode(MobileSecurePayHelper.RsaSign( order, MobileSecurePayHelper.RSA_PRIVATE)); order += String.format("&sign=\"%s\"", sign); order += String.format("&sign_type=\"%s\"", "RSA"); com.alipay.android.MobileSecurePayer msp = new com.alipay.android.MobileSecurePayer(); if (!msp.pay(order, m_mspHandler, 1, OrderingActivity.this)) { m_tips += "调用安全支付功能失败\r\n"; tv.setText(m_tips); bt.setVisibility(0); pb.setVisibility(4); return; } } };