最近公司有需求在项目中要植入支付宝支付等功能。 在完成植入的过程中,遇到了一些坑,今天趁趁任务不多做了个总结。分享给大家,希望以小伙伴不要陷入这些坑中以免浪费很多的时间。
首先说一下遇到的坑及其碰到的问题
1.java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer
原因:
com.android.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.lang.ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer
又这个错误,总么办?
最终是因为:
最终因为传入私钥错误。需要重新生成私钥:
2.在handler里面接受消息的时候,PayResult 转换失败,原因是你在进行
调用支付宝接口的时候,所发送的参数类型不一致导致的。eg:
首先说一下遇到的坑及其碰到的问题
1.java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer
原因:
- public class SignUtils {
- private static final String ALGORITHM = “RSA”;
- private static final String SIGN_ALGORITHMS = “SHA1WithRSA”;
- private static final String DEFAULT_CHARSET = “UTF-8”;
- public static String sign(String content, String privateKey) {
- try {
- java.security.Signature signature = java.security.Signature
- .getInstance(SIGN_ALGORITHMS);
- PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
- KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
- PrivateKey priKey = keyf.generatePrivate(priPKCS8);
- PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
- KeyFactory keyFactory = KeyFactory.getInstance(”RSA”, “BC”);
- PrivateKey priKey = keyFactory.generatePrivate(privSpec);
- signature.initSign(priKey);
- signature.update(content.getBytes(DEFAULT_CHARSET));
- byte[] signed = signature.sign();
- return PayBase64.encode(signed);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
public class SignUtils {
private static final String ALGORITHM = "RSA";
private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
private static final String DEFAULT_CHARSET = "UTF-8";
public static String sign(String content, String privateKey) {
try {
java.security.Signature signature = java.security.Signature
.getInstance(SIGN_ALGORITHMS);
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
PrivateKey priKey = keyFactory.generatePrivate(privSpec);
signature.initSign(priKey);
signature.update(content.getBytes(DEFAULT_CHARSET));
byte[] signed = signature.sign();
return PayBase64.encode(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
修改之后,发现
com.android.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.lang.ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer
又这个错误,总么办?
最终是因为:
最终因为传入私钥错误。需要重新生成私钥:
2.在handler里面接受消息的时候,PayResult 转换失败,原因是你在进行
调用支付宝接口的时候,所发送的参数类型不一致导致的。eg:
- PayTask payTask = new PayTask(DocPayConunselActivity.this);
- // String result = payTask.pay(signInfo, true);
- Map<String, String> result = payTask.payV2(signInfo, true);
- Message message = mHandler.obtainMessage();
- message.what = SDK_PAY_FLAG;
- message.obj = result;
- mHandler.sendMessage(message);
PayTask payTask = new PayTask(DocPayConunselActivity.this);
// String result = payTask.pay(signInfo, true);
Map<String, String> result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message);
另外 如果返回的resultStatus是6002的时候,网络出错,或者是手机没有安装支付宝的时候,弹不出来网页版的支付登录框 这个时候也是会提示网络错误 。这时候你要查找你的配置文件看一下是否配置了以下文件:- <activityandroid:name=“com.alipay.sdk.app.H5PayActivity”android:configChanges=“orientation|keyboardHidden|navigation”android:exported=“false”android:screenOrientation=“behind” ></activity>
- <activityandroid:name=”com.alipay.sdk.auth.AuthActivity”android:configChanges=“orientation|keyboardHidden|navigation”android:exported=“false”android:screenOrientation=“behind” ></activity>
- 添加必要权限
- <uses-permissionandroid:name=”android.permission.INTERNET” />
- <uses-permissionandroid:name=”android.permission.ACCESS_NETWORK_STATE” />
- <uses-permissionandroid:name=”android.permission.ACCESS_WIFI_STATE” />
- <uses-permissionandroid:name=”android.permission.READ_PHONE_STATE” />
- <uses-permissionandroid:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<activityandroid:name="com.alipay.sdk.app.H5PayActivity"android:configChanges="orientation|keyboardHidden|navigation"android:exported="false"android:screenOrientation="behind" ></activity>
<activityandroid:name="com.alipay.sdk.auth.AuthActivity"android:configChanges="orientation|keyboardHidden|navigation"android:exported="false"android:screenOrientation="behind" ></activity>
添加必要权限
<uses-permissionandroid:name="android.permission.INTERNET" />
<uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Android快捷支付SDK Demo resultStatus={4001};memo={参数错误};result={}问题分析:填写的支付宝pkcs8编码的私钥 有问题,或者对应的公钥没有上传至支付宝造成的。
后台处理的必须有这个步骤。上传公钥到支付宝
java.lang.NoClassDefFoundError: com.alipay.android.app.lib.ResourceMap
分析:没有加入android_lib 没有加入项目依赖项
resultStatus={7001};memo={商户没有开通移动快捷支付服务,请使用其他支付工具};result={}!
集成的基本流程如下:
第一步:2.1 导入jar包资源
目前最新版支付宝开发jar包下载地址:androidstarjack_支付宝集成过程详解— 运行DEMO.zip
下载后将之拷贝libs目录,Eclipse会自动添加依赖,Android Studio需在app的gradle中添加一行
compilefiles(‘libs/alipaySdk-20160223.jar’)
点击右上角:Sync Now,稍等片刻
第二步:修改AndroidManifest.xml清单
声明必要Activity
<!–支付相关–>
<activity
android:name=”com.alipay.sdk.app.H5PayActivity” android:configChanges=”orientation|keyboardHidden|navigation”
android:exported=”false” android:screenOrientation=”behind” />
<activity
android:name=”com.alipay.sdk.auth.AuthActivity” android:configChanges=”orientation|keyboardHidden|navigation”
android:exported=”false” android:screenOrientation=”behind” />
添加必要权限
<uses-permission android:name=”com.android.launcher.permission.READ_SETTINGS” />
<uses-permission android:name=”android.permission.CHANGE_WIFI_STATE” />
<uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=”android.permission.BROADCAST_STICKY” />
<uses-permission android:name=”android.permission.INTERACT_ACROSS_USERS_FULL” />
第四步:
private void payToOrderService(final String signInfo){
new Thread() {
@Override
public void run() {
super.run();
PayTask payTask = new PayTask(DocPayConunselActivity.this);
// String result = payTask.pay(signInfo, true);
Map<String, String> result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message);
}
}.start();
}
app携带支付信息调用支付接口请求支付宝客户端调起支付界面;
用户操作,输入密码支付,支付成功;直接返回取消支付;出现错误,支付失败;进入支付界面,但输入密码支付,支付待确认;
支付宝客户端将支付结果告诉app客户端,商户服务器通知app服务器支付结果;
app客户端处理支付结果;
app服务器处理支付结果。
注意请求是异步的:x
- <pre name=“code” class=“java”>PayTask payTask = new PayTask(DocPayConunselActivity.this);
- // String result = payTask.pay(signInfo, true);
- Map<String, String> result = payTask.payV2(signInfo, true);
- Message message = mHandler.obtainMessage();
- message.what = SDK_PAY_FLAG;
- message.obj = result;
- mHandler.sendMessage(message)
<pre name="code" class="java">PayTask payTask = new PayTask(DocPayConunselActivity.this);
// String result = payTask.pay(signInfo, true);
Map<String, String> result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message)
返回的结果:
- private Handler mHandler =new Handler(){
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what){
- case SDK_PAY_FLAG:
- PayResult payResult = null;
- try{
- payResult = new PayResult((Map<String, String>) msg.obj);
- }catch (Exception e){
- e.printStackTrace();
- }
- /**
- 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
- */
- String resultInfo = payResult.getResult();// 同步返回需要验证的信息
- String resultStatus = payResult.getResultStatus();
- // 判断resultStatus 为9000则代表支付成功
- if (TextUtils.equals(resultStatus, PAY_OK)) {//———————————–>支付成功
- // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
- GetToast.useString(DocPayConunselActivity.this, “购买服务成功”);
- } else if (TextUtils.equals(resultStatus, PAY_FAILED)) {//————————->支付失败
- // 该笔订单真实的支付结果,需要依赖服务端的异步通知。
- GetToast.useString(DocPayConunselActivity.this, “”+payResult.getMemo());
- } else if (TextUtils.equals(resultStatus, PAY_CANCLE)) {//————————–>交易取消
- GetToast.useString(DocPayConunselActivity.this, “”+payResult.getMemo());
- } else if (TextUtils.equals(resultStatus, PAY_NET_ERR)) {//————————->网络出现错误
- GetToast.useString(DocPayConunselActivity.this, “”+payResult.getMemo());
- } else if (TextUtils.equals(resultStatus, PAY_WAIT_CONFIRM)) {//———————>交替等待
- }
- break;
- }
- }
- };
private Handler mHandler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case SDK_PAY_FLAG:
PayResult payResult = null;
try{
payResult = new PayResult((Map<String, String>) msg.obj);
}catch (Exception e){
e.printStackTrace();
}
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, PAY_OK)) {//----------------------------------->支付成功
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
GetToast.useString(DocPayConunselActivity.this, "购买服务成功");
} else if (TextUtils.equals(resultStatus, PAY_FAILED)) {//------------------------->支付失败
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
} else if (TextUtils.equals(resultStatus, PAY_CANCLE)) {//-------------------------->交易取消
GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
} else if (TextUtils.equals(resultStatus, PAY_NET_ERR)) {//------------------------->网络出现错误
GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
} else if (TextUtils.equals(resultStatus, PAY_WAIT_CONFIRM)) {//--------------------->交替等待
}
break;
}
}
};
- 最后注意的是,有些手机没有安装支付宝客户端,如牵扯到支付功能的时候,我们直接天转到网页版的支付进行去输入密码去支付 。当然你也可以判断利用支付的sdk进行判断,如没有安装支付宝,提示去安装支付宝模块也是可以的。
最后注意的是,有些手机没有安装支付宝客户端,如牵扯到支付功能的时候,我们直接天转到网页版的支付进行去输入密码去支付 。当然你也可以判断利用支付的sdk进行判断,如没有安装支付宝,提示去安装支付宝模块也是可以的。
这样就完美无缺了。