2017年7月5日 更新了, 总体该说的都说了, 后面再看看还有啥细节补充吧.
项目是跨境电商,国外的支付需要集成paypal支付,在网上搜了好久,教程都是断断续续,对开发者来说不太友好! 好在现在总算搞出来了,分享出来给大家参考下,与君共勉!
1.这个SDK是我找paypal的技术支持要来的,他们最新的包都是Android studio的了,所以找他们要的旧的支持eclipse的包..(更新: 这个项目后来也是转到android studio上开发了, 所以下面的代码风格就是as的style! XD!)
链接: http://pan.baidu.com/s/1pLGfWa3 密码: fj67
2.使用公司给你的开发帐号登录paypal的开发者网站 https://developer.paypal.com
按照步骤点击创建APP
在弹出的界面填写app name就好了,下面的帐号是自动填的.
3.创建完成之后在上图第三步的下面就会出现你命名的app,点击进入之后如下图.
4.然后点击左边侧边栏的Accounts创建一个沙盒帐号测试用.创建页面我就不演示了,那个页面你随便填.只要你记住帐号密码就成.忘了就修改,不然就删掉重建.
5.准备工作完成,开始代码环节.
1)新建类继承Activity,例如PaymentActivity
在成员变量中定义调用paypal支付所需的各种数据.
// 真实环境
private static final String CONFIG_ENVIRONMENT =
PayPalConfiguration.ENVIRONMENT_PRODUCTION;
// paypal申请到的设备ID
private static final String CONFIG_CLIENT_ID = "paypal官方申请的设备ID";
// 沙盒测试
// private static final String CONFIG_ENVIRONMENT =
PayPalConfiguration.ENVIRONMENT_SANDBOX;
// 沙盒测试的设备ID
// private static final String CONFIG_CLIENT_ID = "paypal官方申请的沙盒设备ID";
private static PayPalConfiguration paypalConfig = new
PayPalConfiguration().environment(CONFIG_ENVIRONMENT).clientId(CONFIG_CLIENT_ID).acceptCreditCards(true);
因为业务上有些特殊需求,正常的把商品一条条封装再调用paypal不能完成需求,所以把所有商品名字分隔串联在一起,再把总价算一起,合并作为一件单独的商品来传递并调用paypal支付.下面是详细的代码.事件触发支付时的逻辑
// 开启PayPal服务
Intent intent = new Intent(this, PayPalService.class);
intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig);
startService(intent);
// PayPalItem的四个参数. 1.商品名称 2.商品数量 3.商品单价 4.货币 5.商品描述
PayPalItem item = new PayPalItem(ProductNames.toString(), 1, mBigDecimal, exchname, description);
// 添加进集合
productsInCart.add(item);
// 把集合数据加入paypal的参数
PayPalPayment thingsToBuy = getPayment();
// 跳转到Paypal
Intent i = new Intent(mContext, PaymentActivity.class);
i.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig);
i.putExtra(PaymentActivity.EXTRA_PAYMENT, thingsToBuy);
startActivityForResult(i, REQUEST_CODE_PAYMENT);
productsInCart.clear();
/**
* 获取PayMent对象
*
* @return
*/
private PayPalPayment getPayment() {
// 以商品集合的长度作为数组长度创建数组.
PayPalItem[] items = new PayPalItem[productsInCart.size()];
// 把集合的数据转为数组储存.
items = productsInCart.toArray(items);
// 订单的商品总金额,四舍五入保留2位小数
BigDecimal subtotal = PayPalItem.getItemTotal(items).setScale(2, BigDecimal.ROUND_HALF_UP);
// 如果订单有运费跟税,在这里添加
BigDecimal shipping = new BigDecimal(0);
BigDecimal tax = new BigDecimal(0);
PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails(shipping, subtotal, tax);
mAmount = subtotal.add(shipping).setScale(2, BigDecimal.ROUND_HALF_UP);
String description = "描述";
PayPalPayment payment = new PayPalPayment(mAmount, Currencies, description, PayPalPayment.PAYMENT_INTENT_SALE);
payment.items(items).paymentDetails(paymentDetails);
// payment.custom("测试文本");
return payment;
}
到这就跑到Paypal封装的界面去了, 那界面我们不需要再管, 接下来我们要关注的是支付的回调了.\\
/** 接收支付结果的回调. */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm = data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
LogUtils.print(confirm.toString());
if (confirm != null) {
try {
/*
* Log.i("paymentExample",
* confirm.toJSONObject().toString(4));
*/
// send 'confirm' to your server for verification.
// see
// https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
// for more details.
// 得到回传的交易流水号
mPaymentId = confirm.toJSONObject().getJSONObject("response").getString("id");
// 交易服务端是什么鬼
@SuppressWarnings("unused")
String payment_client = confirm.getPayment().toJSONObject().toString();
// LogUtils.print("LOG", "paymentId: " + paymentId +
// ", payment_json: "
// + payment_client);
// 保留订单付款信息
savePaymentInfo();
showSuccessful();
} catch (Exception e) {
Log.e(TAG, "an extremely unlikely failure occurred: ", e);
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// Log.i(TAG, "The user canceled.");
Toast.makeText(mContext, getString(R.string.wcpay_status), Toast.LENGTH_SHORT).show();
} else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
Log.i(TAG, "An invalid Payment or PayPalConfiguration was submitted. Please see the docs.");
}
}
这里的保存订单付款信息方法只是一个网络请求把数据回传到服务器而已. 不用多说.
要注意的一点是, 这个数据我们不要作为订单状态的最终确认数据来看待, 跟你们后台人员确认下, 每个支付平台都有一个支付回调, 会在客户端这边进行支付动作完成后异步回传支付信息到你指定的后台地址过去, 咱们订单的最终状态要以那个数据为准, 当然你在客户端这里可以先把这个订单的状态作为成功支付的状态展示, 等再次有查询或者刷新动作时再以后台状态为准就好了.
(说到这我就讲下原因吧, 我们就碰见了一个问题就是, 有人用了某种手段在前端这边把支付金额改为了0.1元, 但是实际商品的价格为200, 而后台人员以客户端回传的支付信息为准, 导致该订单差点被运营人员发货, 所以才有了上面的这个经验. 各位同学要多注意)
最后注意一下在支付页面Activity关闭时要关闭Paypal的服务
/**
* 关闭PayPal服务
*
* @see android.app.Activity#onDestroy()
*/
@Override
protected void onDestroy() {
stopService(new Intent(this, PayPalService.class));
super.onDestroy();
}