拿到支付宝接口的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;
}
}
};