拿到支付宝接口的andriod demo后有点无语,集成一个支付服务而已,要在十几个java类之间引用来引用去,这样不仅容易导致应用本身代码结构的复杂化,调试起来也很累,于是操刀改造之:
该删的删,该改写的改写,MobileSecurePayer之外的内容全部整合到MobileSecurePayerHelper之中。
[代码]java代码:
009 | package com.alipay.android; |
011 | import java.io.BufferedReader; |
013 | import java.io.FileOutputStream; |
014 | import java.io.IOException; |
015 | import java.io.InputStream; |
016 | import java.io.InputStreamReader; |
017 | import java.io.OutputStream; |
018 | import java.net.HttpURLConnection; |
020 | import java.security.KeyFactory; |
021 | import java.security.PrivateKey; |
022 | import java.security.PublicKey; |
023 | import java.security.Signature; |
024 | import java.security.spec.PKCS8EncodedKeySpec; |
025 | import java.security.spec.X509EncodedKeySpec; |
026 | import java.util.ArrayList; |
027 | import java.util.List; |
029 | import javax.crypto.Cipher; |
031 | import org.apache.http.client.entity.UrlEncodedFormEntity; |
032 | import org.apache.http.message.BasicNameValuePair; |
033 | import org.json.JSONException; |
034 | import org.json.JSONObject; |
036 | import android.content.Context; |
037 | import android.content.Intent; |
038 | import android.content.pm.PackageInfo; |
039 | import android.net.Uri; |
040 | import android.os.Handler; |
041 | import android.os.Message; |
042 | import android.util.Base64; |
044 | public class MobileSecurePayHelper { |
045 | static final String TAG = "MobileSecurePayHelper" ; |
047 | public static final String PARTNER = "" ; |
048 | public static final String SELLER = "" ; |
049 | public static final String RSA_PRIVATE = "" ; |
050 | public static final String RSA_ALIPAY_PUBLIC = "" ; |
052 | Context mContext = null ; |
053 | Handler mHandler = null ; |
057 | public static String Stream2String(InputStream is) { |
058 | BufferedReader reader = new BufferedReader( new InputStreamReader(is)); |
059 | StringBuilder sb = new StringBuilder(); |
062 | while ((line = reader.readLine()) != null ) |
065 | } catch (IOException e) { |
068 | return sb.toString(); |
071 | public static JSONObject string2JSON(String str, String split) { |
072 | JSONObject json = new JSONObject(); |
074 | String[] arrStr = str.split(split); |
075 | for ( int i = 0 ; i < arrStr.length; i++) { |
076 | String[] arrKeyValue = arrStr[i].split( "=" ); |
077 | json.put(arrKeyValue[ 0 ], |
078 | arrStr[i].substring(arrKeyValue[ 0 ].length() + 1 )); |
080 | } catch (Exception e) { |
086 | public static String SendAndWaitResponse(String strReqData, String strUrl) { |
087 | String strResponse = null ; |
088 | ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>(); |
089 | pairs.add( new BasicNameValuePair( "requestData" , strReqData)); |
091 | HttpURLConnection conn = null ; |
092 | UrlEncodedFormEntity p_entity; |
094 | p_entity = new UrlEncodedFormEntity(pairs, "utf-8" ); |
095 | URL url = new URL(strUrl); |
096 | conn = (HttpURLConnection) url.openConnection(); |
097 | conn.setConnectTimeout( 30 * 1000 ); |
098 | conn.setReadTimeout( 30 * 1000 ); |
099 | conn.setDoOutput( true ); |
100 | conn.addRequestProperty( "Content-type" , |
101 | "application/x-www-form-urlencoded;charset=utf-8" ); |
104 | OutputStream os = conn.getOutputStream(); |
105 | p_entity.writeTo(os); |
107 | InputStream content = conn.getInputStream(); |
108 | strResponse = Stream2String(content); |
109 | } catch (IOException e) { |
117 | public static boolean urlDownloadToFile(Context context, String strurl, |
119 | boolean bRet = false ; |
121 | URL url = new URL(strurl); |
122 | HttpURLConnection conn = null ; |
123 | conn = (HttpURLConnection) url.openConnection(); |
124 | conn.setConnectTimeout( 30 * 1000 ); |
125 | conn.setReadTimeout( 30 * 1000 ); |
126 | conn.setDoInput( true ); |
128 | InputStream is = conn.getInputStream(); |
129 | File file = new File(path); |
130 | file.createNewFile(); |
131 | FileOutputStream fos = new FileOutputStream(file); |
132 | byte [] temp = new byte [ 1024 ]; |
134 | while ((i = is.read(temp)) > 0 ) |
135 | fos.write(temp, 0 , i); |
139 | } catch (IOException e) { |
145 | public static String RsaEncode(String content, String key) { |
147 | X509EncodedKeySpec x509 = new X509EncodedKeySpec(Base64.decode(key, |
149 | KeyFactory kf = KeyFactory.getInstance( "RSA" ); |
150 | PublicKey pubKey = kf.generatePublic(x509); |
151 | Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" ); |
152 | cipher.init(Cipher.ENCRYPT_MODE, pubKey); |
153 | byte plaintext[] = content.getBytes( "UTF-8" ); |
154 | byte [] output = cipher.doFinal(plaintext); |
155 | return new String(Base64.encode(output, Base64.DEFAULT)); |
156 | } catch (Exception e) { |
162 | public static String RsaSign(String content, String privateKey) { |
164 | PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(Base64.decode( |
165 | privateKey, Base64.DEFAULT)); |
166 | KeyFactory kf = KeyFactory.getInstance( "RSA" ); |
167 | PrivateKey priKey = kf.generatePrivate(pkcs8); |
168 | Signature signature = Signature.getInstance( "SHA1WithRSA" ); |
169 | signature.initSign(priKey); |
170 | signature.update(content.getBytes( "utf-8" )); |
171 | byte [] signed = signature.sign(); |
172 | return new String(Base64.encode(signed, Base64.DEFAULT)); |
173 | } catch (Exception e) { |
179 | public static boolean RsaCheck(String content, String sign, String publicKey) { |
181 | KeyFactory keyFactory = KeyFactory.getInstance( "RSA" ); |
182 | byte [] encodedKey = Base64.decode(publicKey, Base64.DEFAULT); |
183 | PublicKey pubKey = keyFactory |
184 | .generatePublic( new X509EncodedKeySpec(encodedKey)); |
185 | Signature signature = Signature.getInstance( "SHA1WithRSA" ); |
186 | signature.initVerify(pubKey); |
187 | signature.update(content.getBytes( "utf-8" )); |
188 | boolean bverify = signature.verify(Base64.decode(sign, |
191 | } catch (Exception e) { |
197 | public MobileSecurePayHelper(Context context, Handler handler) { |
202 | public boolean detectService() { |
203 | boolean isExist = false ; |
204 | List<PackageInfo> pkgList = mContext.getPackageManager() |
205 | .getInstalledPackages( 0 ); |
206 | for ( int i = 0 ; i < pkgList.size(); i++) { |
207 | if (pkgList.get(i).packageName |
208 | .equalsIgnoreCase( "com.alipay.android.app" )) |
214 | public void downloadAliMSP() { |
215 | JSONObject Resp = null ; |
217 | JSONObject req = new JSONObject(); |
218 | req.put( "action" , "update" ); |
219 | JSONObject data = new JSONObject(); |
220 | data.put( "platform" , "android" ); |
221 | data.put( "version" , "2.2.3" ); |
222 | data.put( "partner" , "" ); |
223 | req.put( "data" , data); |
224 | Resp = new JSONObject(SendAndWaitResponse(req.toString(), |
225 | "https://msp.alipay.com/x.htm" )); |
226 | mUrl = Resp.getString( "updateUrl" ); |
227 | } catch (JSONException e) { |
231 | new Thread( new Runnable() { |
233 | mPath = mContext.getCacheDir().getAbsolutePath() + "/temp.apk" ; |
234 | urlDownloadToFile(mContext, mUrl, mPath); |
235 | Message msg = new Message(); |
237 | mHandler.sendMessage(msg); |
242 | public void installAliMSP() { |
246 | Runtime.getRuntime().exec( "chmod 777 " + mPath); |
247 | } catch (IOException e) { |
250 | Intent intent = new Intent(Intent.ACTION_VIEW); |
251 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
252 | intent.setDataAndType(Uri.parse( "file://" + mPath), |
253 | "application/vnd.android.package-archive" ); |
254 | mContext.startActivity(intent); |
集成很简单,一个OnClickListener负责调用
支付服务
,一个Handler负责处理支付过程中的相应事件:
[代码]java代码:
001 | private Handler m_mspHandler = new Handler() { |
002 | public void handleMessage(Message m) { |
005 | TextView tv = (TextView) findViewById(R.id.order_tips); |
006 | Button bt = (Button) findViewById(R.id.order_ok); |
007 | ProgressBar pb = (ProgressBar) findViewById(R.id.order_wait); |
010 | String ret = (String) m.obj; |
011 | String memo = "memo={" ; |
012 | int start = ret.indexOf(memo) + memo.length(); |
013 | int end = ret.indexOf( "};result=" ); |
014 | memo = ret.substring(start, end); |
016 | if (memo.indexOf( "付款成功" ) >= 0 ) |
017 | m_tips += "\r\n请注意查看短信,您将收到二维码凭证" ; |
023 | m_tips += "安全支付组件下载完成,开始安装...\r\n" ; |
025 | m_mspHelper.installAliMSP(); |
033 | private OnClickListener m_orderButtonListener = new OnClickListener() { |
034 | public void onClick(View v) { |
035 | String mobile = m_mobileEdt.getText().toString(); |
037 | TextView tv = (TextView) findViewById(R.id.order_tips); |
038 | Button bt = (Button) findViewById(R.id.order_ok); |
039 | ProgressBar pb = (ProgressBar) findViewById(R.id.order_wait); |
040 | if (mobile.length() != 11 ) { |
041 | m_tips += "无效的收货号码\r\n" ; |
045 | if (!m_date.after(m_today)) { |
046 | m_tips += "订货日期不能早于明天\r\n" ; |
050 | SoapObject request = new SoapObject( "http://airtimes.cn/" , |
052 | request.addProperty( "Uname" , m_intent.getStringExtra( "userid" )); |
053 | request.addProperty( "ProductId" , |
054 | m_intent.getStringExtra( "item_PID" )); |
055 | request.addProperty( "Sum" , "1" ); |
056 | request.addProperty( "PayAmount" , |
057 | m_intent.getStringExtra( "item_price" )); |
058 | request.addProperty( "SMSMobile" , mobile); |
061 | String.format( "%04d-%02d-%02d" , m_date.get( 1 ), |
062 | m_date.get( 2 ) + 1 , m_date.get( 5 ))); |
065 | m_tips += "正在创建订单,请稍候...\r\n" ; |
070 | HttpTransportSE httpTransport = new HttpTransportSE( |
071 | "http://www.android-study.com/serv.asmx" ); |
072 | SoapSerializationEnvelope envelope = new SoapSerializationEnvelope( |
074 | envelope.dotNet = true ; |
075 | envelope.bodyOut = request; |
078 | httpTransport.call(request.getNamespace() + request.getName(), |
080 | if (envelope.getResponse() != null ) |
081 | respond = envelope.getResponse().toString(); |
083 | respond = "false,null" ; |
084 | } catch (Exception ex) { |
085 | respond = "false," + ex.getMessage(); |
087 | if (respond.substring( 0 , 5 ).equals( "false" )) { |
088 | m_tips += "创建订单失败:" + respond.substring( 6 ) + "\r\n" ; |
095 | String msgs[] = respond.split( "[,]" ); |
097 | m_tips += "创建订单成功,开始支付...\r\n" ; |
100 | if (!m_mspHelper.detectService()) { |
101 | m_tips += "未安装安全支付组件,开始下载...\r\n" ; |
103 | m_mspHelper.downloadAliMSP(); |
107 | order = String.format( "partner=\"%s\"" , |
108 | MobileSecurePayHelper.PARTNER); |
109 | order += String.format( "&seller=\"%s\"" , |
110 | MobileSecurePayHelper.SELLER); |
111 | order += String.format( "&out_trade_no=\"%s\"" , msgs[ 1 ]); |
112 | order += String.format( "&subject=\"%s\"" , |
113 | m_intent.getStringExtra( "item_type" )); |
114 | order += String.format( "&body=\"%s\"" , |
115 | m_intent.getStringExtra( "item_name" )); |
116 | order += String.format( "&total_fee=\"%s\"" , |
117 | m_intent.getStringExtra( "item_price" )); |
118 | order += String.format( "¬ify_url=\"%s\"" , |
119 | "http://www.android-study.com/alipay.aspx" ); |
120 | String sign = URLEncoder.encode(MobileSecurePayHelper.RsaSign( |
121 | order, MobileSecurePayHelper.RSA_PRIVATE)); |
122 | order += String.format( "&sign=\"%s\"" , sign); |
123 | order += String.format( "&sign_type=\"%s\"" , "RSA" ); |
125 | com.alipay.android.MobileSecurePayer msp = new com.alipay.android.MobileSecurePayer(); |
126 | if (!msp.pay(order, m_mspHandler, 1 , OrderingActivity. this )) { |
127 | m_tips += "调用安全支付功能失败\r\n" ; |