拿到支付宝的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<BasicNameValuePair> pairs=new ArrayList<BasicNameValuePair>();
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<PackageInfo> 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://****/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://****/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;
}
}
};