开发环境Visual Studio 2015,Xamarin 3.11.1537,Xamarin Android5.1.7.12
下载支付宝移动支付的SDK(http://doc.open.alipay.com/doc2/detail?treeId=54&articleId=103419&docType=1),找到Andriud的SDK,其中有一个alipaySDK-20151014.jar(这个版本,以后肯定会变化),这是我们使用的重点。
在Visual Studio中创建一个绑定库文件
把支付宝的alipaySDK-20151014.jar添加到Jars文件夹下,先中alipaySDK-20151014.jar,打开属性窗口,设置生成操作为EmbeddedJar,库文件搞定。
Android中使用绑定库文件
在Visual Studio中创建一个BlankApp应用,然后在打开项目属性,Android Manifest选项卡,在Required permissions中选择ACCESS_WIFI_STATE和INTERNET权限,添加绑定库生成的dll到当前项目的引用中。
添加签名生成类
using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace App1
{
class SignatureUtils
{
/// <summary>
/// 签名
/// </summary>
/// <param name="content">需要签名的内容</param>
/// <param name="privateKey">私钥</param>
/// <returns></returns>
public static string Sign(string content, string privateKey)
{
byte[] Data = Encoding.GetEncoding("utf-8").GetBytes(content);
RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
SHA1 sh = new SHA1CryptoServiceProvider();
byte[] signData = rsa.SignData(Data, sh);
sh.Clear();
return Convert.ToBase64String(signData);
}
/// <summary>
/// 对prikey进行处理,C#API默认的prikey是xml格式的,所以需要进行处理
/// </summary>
/// <param name="pemstr"></param>
/// <returns></returns>
private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)
{
byte[] pkcs8privatekey;
pkcs8privatekey = Convert.FromBase64String(pemstr);
if (pkcs8privatekey != null)
{
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey);
return rsa;
}
else
return null;
}
/// <summary>
/// 转换prikey
/// </summary>
/// <param name="pkcs8"></param>
/// <returns></returns>
private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
{
byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
byte[] seq = new byte[15];
MemoryStream mem = new MemoryStream(pkcs8);
int lenstream = (int)mem.Length;
BinaryReader binr = new BinaryReader(mem);
byte bt = 0;
ushort twobytes = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
return null;
bt = binr.ReadByte();
if (bt != 0x02)
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0001)
return null;
seq = binr.ReadBytes(15);
if (!CompareBytearrays(seq, SeqOID))
return null;
bt = binr.ReadByte();
if (bt != 0x04)
return null;
bt = binr.ReadByte();
if (bt == 0x81)
binr.ReadByte();
else
if (bt == 0x82)
binr.ReadUInt16();
byte[] rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));
RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);
return rsacsp;
}
catch (Exception)
{
return null;
}
finally { binr.Close(); }
}
private static bool CompareBytearrays(byte[] a, byte[] b)
{
if (a.Length != b.Length)
return false;
int i = 0;
foreach (byte c in a)
{
if (c != b[i])
return false;
i++;
}
return true;
}
/// <summary>
/// 处理私钥
/// </summary>
/// <param name="privkey"></param>
/// <returns></returns>
private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
MemoryStream mem = new MemoryStream(privkey);
BinaryReader binr = new BinaryReader(mem);
byte bt = 0;
ushort twobytes = 0;
int elems = 0;
try
{
twobytes = binr.ReadUInt16();
if (twobytes == 0x8130)
binr.ReadByte();
else if (twobytes == 0x8230)
binr.ReadInt16();
else
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102)
return null;
bt = binr.ReadByte();
if (bt != 0x00)
return null;
elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
CspParameters cspParams = new CspParameters();
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
//System.Security.Cryptography.RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, cspParams);
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024);
RSAParameters RSAparams = new RSAParameters();
RSAparams.Modulus = MODULUS;
RSAparams.Exponent = E;
RSAparams.D = D;
RSAparams.P = P;
RSAparams.Q = Q;
RSAparams.DP = DP;
RSAparams.DQ = DQ;
RSAparams.InverseQ = IQ;
RSA.ImportParameters(RSAparams);
return RSA;
}
catch (Exception)
{
return null;
}
finally { binr.Close(); }
}
/// <summary>
/// 获取binr的长度
/// </summary>
/// <param name="binr"></param>
/// <returns></returns>
private static int GetIntegerSize(BinaryReader binr)
{
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02)
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte();
else
if (bt == 0x82)
{
highbyte = binr.ReadByte();
lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt;
}
while (binr.ReadByte() == 0x00)
{
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current);
return count;
}
}
}
在主程序中添加如下代码:
using System;
using Android.App;
using Android.Widget;
using Android.OS;
using Java.Net;
namespace App1
{
[Activity(Label = "App1", MainLauncher = true)]
public class MainActivity : Activity
{
// 合作商户ID。用签约支付宝账号登录ms.alipay.com后,在账户信息页面获取。
public static string PARTNER = "替换你支付宝申请的partner";
// 商户收款的支付宝账号
public static string SELLER = "替换你支付宝申请的seller";
//商户私密
string RSA_PRIVATE = "替换你支付宝申请的private_key";
;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += HandleClick;
}
void HandleClick(object sender, EventArgs e)
{
System.Threading.Thread the = new System.Threading.Thread(Pay);
the.Start();
}
void Pay()
{
var con = getOrderInfo("test", "testbody");
var sign = SignatureUtils.Sign(con, RSA_PRIVATE);
sign = URLEncoder.Encode(sign, "utf-8");
con += "&sign=\"" + sign + "\"&" + MySignType;
Com.Alipay.Sdk.App.PayTask pa = new Com.Alipay.Sdk.App.PayTask(this);
var result = pa.Pay(con);
//调用结果查看result中是否返回是90000,如果是,则成功
}
#region 组合
public String getOrderInfo(String subject, String body)
{
// 签约合作者身份ID
String orderInfo = "partner=" + "\"" + PARTNER + "\"";
// 签约卖家支付宝账号
orderInfo += "&seller_id=" + "\"" + SELLER + "\"";
// 商户网站唯一订单号
orderInfo += "&out_trade_no=" + "\"DJ" + DateTime.Now.ToString("yyyyMMddhhmmss") + "\"";
// 商品名称
orderInfo += "&subject=" + "\"" + subject + "\"";
// 商品详情
orderInfo += "&body=" + "\"" + body + "\"";
// 商品金额
orderInfo += "&total_fee=" + "\"" + 0.01 + "\"";
// 服务器异步通知页面路径
orderInfo += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm"
+ "\"";
// 服务接口名称, 固定值
orderInfo += "&service=\"mobile.securitypay.pay\"";
// 支付类型, 固定值
orderInfo += "&payment_type=\"1\"";
// 参数编码, 固定值
orderInfo += "&_input_charset=\"utf-8\"";
// 设置未付款交易的超时时间
// 默认30分钟,一旦超时,该笔交易就会自动被关闭。
// 取值范围:1m~15d。
// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
// 该参数数值不接受小数点,如1.5h,可转换为90m。
orderInfo += "&it_b_pay=\"30m\"";
// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
orderInfo += "&return_url=\"m.alipay.com\"";
// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
// orderInfo += "&paymethod=\"expressGateway\"";
return orderInfo;
}
public String MySignType
{
get
{
return "sign_type=\"RSA\"";
}
}
#endregion
}
}
源代码见附件