Android 集成PayPal支付

作者: Moosen | 来源:发表于2016-11-12 18:02 被阅读4537次

    由于最近公司业务需求,为了提升用户体验,产品决定把原本直接加载M版的支付方式,直接改成调起PayPal SDK的方式进行支付,从而可以大大提升加载速度,改善体验。虽然后来出于支付安全考虑否决了这个决定,但是在这里还是跟大家来分享一下集成Android的集成PayPal支付,同时简单封装了一下支付的帮助类,希望能帮到大家。
    <h4>
    1.注册PayPal开发者账号,并且添加你的APP
    </h4>
    首先我们得去到PayPal的开发者平台去注册自己的账号 https://developer.paypal.com ,同时创建自己的APP,获取APP的CLient ID.


    <h4>
    2.在自己的工程里添加相应的SDK依赖
    </h4>

    把下面一句代码添加到你工程的gradle.bulid里面

    compile('com.paypal.sdk:paypal-android-sdk:2.15.1') 
    { exclude group: 'io.card' }//禁止通过信用卡直接支付,如果不禁止可以直接去掉这一句
    

    <h4>
    2.强制在你的编译版本上执行编译操作(编译不过的时候才建议添加)
    </h4>

    由于PayPal sdk 现在已经升级到了默认最低是minSDKVersion 16 ,所以如果你的编译版本低于这个版本的时候,AS就会提示你编译不通过,并且报错

    Error:Execution failed for task ':app:processDebugManifest'.
    > Manifest merger failed : uses-sdk:minSdkVersion 14 cannot be smaller than version 16 declared in library [com.paypal.sdk:paypal-android-sdk:2.15.1] /home/moosen/Documents/GearBest/app/build/intermediates/exploded-aar/com.paypal.sdk/paypal-android-sdk/2.15.1/AndroidManifest.xml
    Suggestion: use tools:overrideLibrary="com.paypal.android.sdk.payments" to force usage
    

    这时你需要在清单文件AndroidManifest.xml里面添加一下代码强制它在你需要的版本下编译

    <uses-sdk    android:minSdkVersion="这里填写你需要的编译版本"    tools:overrideLibrary="com.paypal.android.sdk.payments" />
    

    当然你也可以把你的minSDKVersion改到16或者更大

    <h4>
    3.在你需要调起支付的页面配置支付环境(或者在基类配置相应的支付环境)
    </h4>

    //配置何种支付环境,一般沙盒,正式    
    private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_SANDBOX;    
    // note that these credentials will differ between live & sandbox environments.    
    //你所注册的APP Id    private static final String CONFIG_CLIENT_ID = "你所注册的CLient Id";   
    private static final int REQUEST_CODE_PAYMENT = 1;    
    private static final int REQUEST_CODE_FUTURE_PAYMENT = 2;    
    private static final int REQUEST_CODE_PROFILE_SHARING = 3;    
    private static PayPalConfiguration config = new PayPalConfiguration()            .environment(CONFIG_ENVIRONMENT)            
    .clientId(CONFIG_CLIENT_ID);    
    //以下配置是授权支付的时候用到的
    //.merchantName("Example Merchant")
    // .merchantPrivacyPolicyUri(Uri.parse("https://www.example.com/privacy"))
    //.merchantUserAgreementUri(Uri.parse("https://www.example.com/legal"));
    
    

    <h4>
    4.在类的onCreate方法里面调起支付服务
    </h4>

    Intent intent = new Intent(this, PayPalService.class);
    intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    startService(intent);
    

    <h4>
    5.创建支付实体,在需要调起支付的地方调起支付
    </h4>

    public void onBuyPressed(View pressed) {
    //创建支付对象,用于传过去给PayPal服务器进行收款
    PayPalPayment thingToBuy = getThingToBuy(PayPalPayment.PAYMENT_INTENT_SALE);
    Intent intent = new Intent(SampleActivity.this, PaymentActivity.class);
    intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
    //这里直接调起PayPal的sdk进行付款操作
    startActivityForResult(intent, REQUEST_CODE_PAYMENT);
    }
    //这里只传一个总价格或者单个产品的信息收款情况
    private PayPalPayment getThingToBuy(String paymentIntent) {
    return new PayPalPayment(new BigDecimal("0.01"), "USD", "sample item",
    paymentIntent);
    
    }
    //这里是购买一系列产品创建购买对象
    private PayPalPayment getStuffToBuy(String paymentIntent) {
    PayPalItem[] items =
    {
    new PayPalItem("sample item #1", 2, new BigDecimal("87.50"), "USD",
    "sku-12345678"),
    new PayPalItem("free sample item #2", 1, new BigDecimal("0.00"),
    "USD", "sku-zero-price"),
    new PayPalItem("sample item #3 with a longer name", 6, new BigDecimal("37.99"),
    "USD", "sku-33333")
    };
    BigDecimal subtotal = PayPalItem.getItemTotal(items);
    BigDecimal shipping = new BigDecimal("7.21");
    BigDecimal tax = new BigDecimal("4.67");
    PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails(shipping, subtotal, tax);
    BigDecimal amount = subtotal.add(shipping).add(tax);
    PayPalPayment payment = new PayPalPayment(amount, "USD", "sample item", paymentIntent);
    payment.items(items).paymentDetails(paymentDetails);
    //--- set other optional fields like invoice_number, custom field, and soft_descriptor
    payment.custom("This is text that will be associated with the payment that the app can use.");
    return payment;
    }
    

    <h4>
    6.在类的onActivityResult 里进行回调结果的处理
    </h4>

    if (resultCode == Activity.RESULT_OK) {
    PaymentConfirmation confirm =
    data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
    if (confirm != null) {
    try {
    Log.i(TAG, confirm.toJSONObject().toString(4));
    Log.i(TAG, confirm.getPayment().toJSONObject().toString(4));
    //这里可以把PayPal带回来的json数据传给服务器以确认你的款项是否收到或者收全
    //可以直接把 confirm.toJSONObject() 这个带给服务器,
    //得到服务器返回的结果,你就可以跳转成功页面或者做相应的处理了
    } catch (JSONException e) {
    Log.e(TAG, "an extremely unlikely failure occurred: ", e);
    }
    }
    } else if (resultCode == Activity.RESULT_CANCELED) {
    Log.i(TAG, "The user canceled.");
    } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
    Log.i(
    TAG,
    "An invalid Payment or PayPalConfiguration was submitted. Please see the docs.");
    }
    } 
    

    这里授权支付就不做解析和分析了

    <h4>
    7.在类的onDestroy 注销服务
    </h4>

    stopService(new Intent(this, PayPalService.class));
    

    <h4>
    7.最后,这里简单的封装了一个PayPalHelper帮助类
    </h4>
    你只需要在相应的生命周期里面调用PayPalHelper里面的方法,就可以做相应的处理

    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    
    import com.globalegrow.app.gearbest.network.HttpCallBack;
    import com.globalegrow.app.gearbest.widget.CustomToast;
    import com.paypal.android.sdk.payments.PayPalAuthorization;
    import com.paypal.android.sdk.payments.PayPalConfiguration;
    import com.paypal.android.sdk.payments.PayPalFuturePaymentActivity;
    import com.paypal.android.sdk.payments.PayPalItem;
    import com.paypal.android.sdk.payments.PayPalPayment;
    import com.paypal.android.sdk.payments.PayPalPaymentDetails;
    import com.paypal.android.sdk.payments.PayPalProfileSharingActivity;
    import com.paypal.android.sdk.payments.PayPalService;
    import com.paypal.android.sdk.payments.PaymentActivity;
    import com.paypal.android.sdk.payments.PaymentConfirmation;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import java.io.IOException;
    import java.math.BigDecimal;
    
    /**
     * Create by Moosen on 09/11/2016
     */
    public class PayPalHelper {
    
        private static final String TAG = "PayPalHelper";
        //配置何种支付环境,一般沙盒,正式
        private static final String CONFIG_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_SANDBOX;
    
        // note that these credentials will differ between live & sandbox environments.
        //你所注册的APP Id
        private static final String CONFIG_CLIENT_ID = "";
    
        private static final int REQUEST_CODE_PAYMENT = 1;
        private static final int REQUEST_CODE_FUTURE_PAYMENT = 2;
        private static final int REQUEST_CODE_PROFILE_SHARING = 3;
    
        private static PayPalConfiguration config = new PayPalConfiguration()
                .environment(CONFIG_ENVIRONMENT)
                .clientId(CONFIG_CLIENT_ID);
        //以下配置是授权支付的时候用到的
    //            .merchantName("Example Merchant")
    //            .merchantPrivacyPolicyUri(Uri.parse("https://www.example.com/privacy"))
    //            .merchantUserAgreementUri(Uri.parse("https://www.example.com/legal"));
        private static PayPalHelper payPalHelper;
    
        private PayPalHelper() {
        }
    
        public static PayPalHelper getInstance() {
            if (payPalHelper == null) {
                synchronized (PayPalHelper.class) {
                    payPalHelper = new PayPalHelper();
                }
            }
            return payPalHelper;
        }
    
        /**
         * 启动PayPal服务
         *
         * @param context
         */
        public void startPayPalService(Context context) {
            Intent intent = new Intent(context, PayPalService.class);
            intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
            context.startService(intent);
        }
    
        /**
         * 停止PayPal服务  sdfsdfsdssaaass
         *
         * @param context
         */
        public void stopPayPalService(Context context) {
            context.stopService(new Intent(context, PayPalService.class));
        }
    
        /**
         * 开始执行支付操作
         *
         * @param context
         */
        public void doPayPalPay(Context context) {
            /*
             * PAYMENT_INTENT_SALE will cause the payment to complete immediately.
             * Change PAYMENT_INTENT_SALE to
             *   - PAYMENT_INTENT_AUTHORIZE to only authorize payment and capture funds later.
             *   - PAYMENT_INTENT_ORDER to create a payment for authorization and capture
             *     later via calls from your server.
             *
             * Also, to include additional payment details and an item list, see getStuffToBuy() below.
             */
            PayPalPayment thingToBuy = getStuffToBuy(PayPalPayment.PAYMENT_INTENT_SALE);
            /*
             * See getStuffToBuy(..) for examples of some available payment options.
             */
            Intent intent = new Intent(context, PaymentActivity.class);
    
            // send the same configuration for restart resiliency
            intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    
            intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
    
            ((Activity) context).startActivityForResult(intent, REQUEST_CODE_PAYMENT);
        }
    
        /*
             * This method shows use of optional payment details and item list.
             *
             * 直接给PP创建支付的信息,支付对象实体信息
             */
        private PayPalPayment getStuffToBuy(String paymentIntent) {
            //--- include an item list, payment amount details
            //具体的产品信息列表
            PayPalItem[] items =
                    {
                            new PayPalItem("sample item #1", 2, new BigDecimal("0.50"), "USD",
                                    "sku-12345678"),
                            new PayPalItem("free sample item #2", 1, new BigDecimal("0.00"),
                                    "USD", "sku-zero-price"),
                            new PayPalItem("sample item #3 with a longer name", 6, new BigDecimal("0.99"),
                                    "USD", "sku-33333")
                    };
            BigDecimal subtotal = PayPalItem.getItemTotal(items);
            BigDecimal shipping = new BigDecimal("0.21");
            BigDecimal tax = new BigDecimal("0.67");
            PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails(shipping, subtotal, tax);
            BigDecimal amount = subtotal.add(shipping).add(tax);
            PayPalPayment payment = new PayPalPayment(amount, "USD", "sample item", paymentIntent);
            payment.items(items).paymentDetails(paymentDetails);
            //--- set other optional fields like invoice_number, custom field, and soft_descriptor
            payment.custom("This is text that will be associated with the payment that the app can use.");
            return payment;
        }
    
        /**
         * 处理支付之后的结果
         *
         * @param context
         * @param requestCode
         * @param resultCode
         * @param data
         */
        public void confirmPayResult(final Context context, int requestCode, int resultCode, Intent data, final DoResult doResult) {
            if (requestCode == REQUEST_CODE_PAYMENT) {
                if (resultCode == Activity.RESULT_OK) {
                    PaymentConfirmation confirm =
                            data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
                    if (confirm != null) {
                        try {
                            Log.i(TAG, confirm.toJSONObject().toString(4));
                            Log.i(TAG, confirm.getPayment().toJSONObject().toString(4));
    
                            /**
                             *  TODO: send 'confirm' (and possibly confirm.getPayment() to your server for verification
                             * or consent completion.
                             * See https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
                             * for more details.
                             *
                             * For sample mobile backend interactions, see
                             * https://github.com/paypal/rest-api-sdk-python/tree/master/samples/mobile_backend
                             */
    //                        displayResultText("PaymentConfirmation info received from PayPal");
                            // 这里直接跟服务器确认支付结果,支付结果确认后回调处理结果
                            JSONObject jsonObject = confirm.toJSONObject();
                            if (jsonObject != null) {
                                JSONObject response = jsonObject.optJSONObject("response");
                                if (response != null) {
                                    String id = response.optString("id");
                                    try {
                                        CartManager.getInstance().confirmPayPalPayPrice(context, id, new HttpCallBack<String>() {
                                            @Override
                                            public void onSuccess(String responseString) {
                                                if (responseString != null) {
                                                    try {
                                                        JSONObject jsonObject = new JSONObject(responseString);
                                                        if (jsonObject != null) {
                                                            int resultcode = jsonObject.optInt("_resultcode");
                                                            String msg = jsonObject.optString("_msg");
                                                            if (200 == resultcode) {
                                                                doResult.confirmSuccess();
                                                                Log.i(TAG, "dddddddd");
                                                            } else {
                                                                Log.i(TAG, "ssssssss");
                                                                CustomToast.getInstance(context).showToast(msg);
                                                                doResult.confirmNetWorkError();
                                                            }
                                                            CustomToast.getInstance(context).showToast(msg);
                                                        }
                                                    } catch (JSONException e) {
                                                        e.printStackTrace();
                                                        doResult.confirmNetWorkError();
                                                    }
                                                }
                                            }
    
                                            @Override
                                            public void onFailure(IOException e) {
                                                Log.i(TAG, "aaaaaaaa");
                                                doResult.confirmNetWorkError();
                                            }
                                        });
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        doResult.confirmNetWorkError();
                                    }
                                }
                            }
                        } catch (JSONException e) {
                            Log.e(TAG, "an extremely unlikely failure occurred: ", e);
                            doResult.confirmNetWorkError();
                        }
                    }
                } else if (resultCode == Activity.RESULT_CANCELED) {
                    Log.i(TAG, "The user canceled.");
                    doResult.customerCanceled();
                } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
                    doResult.invalidPaymentConfiguration();
                    Log.i(
                            TAG,
                            "An invalid Payment or PayPalConfiguration was submitted. Please see the docs.");
                }
            } else if (requestCode == REQUEST_CODE_FUTURE_PAYMENT) {
                if (resultCode == Activity.RESULT_OK) {
                    PayPalAuthorization auth =
                            data.getParcelableExtra(PayPalFuturePaymentActivity.EXTRA_RESULT_AUTHORIZATION);
                    if (auth != null) {
                        try {
                            doResult.confirmFuturePayment();
                            Log.i("FuturePaymentExample", auth.toJSONObject().toString(4));
    
                            String authorization_code = auth.getAuthorizationCode();
                            Log.i("FuturePaymentExample", authorization_code);
    
    //                        sendAuthorizationToServer(auth);
    //                        displayResultText("Future Payment code received from PayPal");
    
                        } catch (JSONException e) {
                            doResult.confirmNetWorkError();
                            Log.e("FuturePaymentExample", "an extremely unlikely failure occurred: ", e);
                        }
                    }
                } else if (resultCode == Activity.RESULT_CANCELED) {
                    Log.i("FuturePaymentExample", "The user canceled.");
                    doResult.customerCanceled();
                } else if (resultCode == PayPalFuturePaymentActivity.RESULT_EXTRAS_INVALID) {
                    doResult.invalidPaymentConfiguration();
                    Log.i(
                            "FuturePaymentExample",
                            "Probably the attempt to previously start the PayPalService had an invalid PayPalConfiguration. Please see the docs.");
                }
            } else if (requestCode == REQUEST_CODE_PROFILE_SHARING) {
                if (resultCode == Activity.RESULT_OK) {
                    PayPalAuthorization auth =
                            data.getParcelableExtra(PayPalProfileSharingActivity.EXTRA_RESULT_AUTHORIZATION);
                    if (auth != null) {
                        try {
                            Log.i("ProfileSharingExample", auth.toJSONObject().toString(4));
    
                            String authorization_code = auth.getAuthorizationCode();
                            Log.i("ProfileSharingExample", authorization_code);
    
    //                        sendAuthorizationToServer(auth);
    //                        displayResultText("Profile Sharing code received from PayPal");
    
                        } catch (JSONException e) {
                            Log.e("ProfileSharingExample", "an extremely unlikely failure occurred: ", e);
                        }
                    }
                } else if (resultCode == Activity.RESULT_CANCELED) {
                    Log.i("ProfileSharingExample", "The user canceled.");
                } else if (resultCode == PayPalFuturePaymentActivity.RESULT_EXTRAS_INVALID) {
                    Log.i(
                            "ProfileSharingExample",
                            "Probably the attempt to previously start the PayPalService had an invalid PayPalConfiguration. Please see the docs.");
                }
            }
        }
    
        /**
         * c处理完结果之后回调
         */
        public interface DoResult {
            //与服务确认支付成功
            void confirmSuccess();
    
            //网络异常或者json返回有问题
            void confirmNetWorkError();
    
            //用户取消支付
            void customerCanceled();
    
            //授权支付
            void confirmFuturePayment();
    
            //订单支付验证无效
            void invalidPaymentConfiguration();
        }
    
    }
    

    相关文章

      网友评论

      • ab72c065186a:点个赞,直接拿来用了。谢谢楼主。

        虽然是16年底的,不过还是可以用的。
      • 吴蜀黍:给个源码连接
      • 8f959b52e515:现在好像通过paypal-android-sdk这种方式接入被被弃用了,不知道楼主对其他方式接入有没有了解
      • __missing:您好,请问支付回调中的resultCode是多少呀,我没有找到呢
      • 你好_ddb0:这里调用支付是不是必须得在activity里面执行?我现在是游戏道具调用,前人支付是用反射来调用的,请问在不进入游戏代码里面能执行吗?(游戏代码看不懂)
      • 水_8d4c:PayPalHelper类中的CartManager是在那里生成的?
        Nur__:我也找不到 PayPalHelper class
        191f1936a693:这个是什么东西哦.
      • 391c813fc64f:我想问一下,现在paypal在android端支持使用银行卡支付吗?
      • mike_tang:您好,paypal没有类似S2S的回调地址吗?这样如果客户端支付成功后刚好网络断了,这时候没有向我们服务器发送查询请求,那这笔单不就变死单了?
      • 为梦而飞:能不能加一下你的QQ,向你请教一下,也可以加一下我的Q,784213509
        30e023a6a9e3:@为梦而飞 同样的问题.请问这个问题解决了吗?
        为梦而飞:@Moosen 我移动端的流程弄清楚了,现在就是服务器那边不清楚怎么验证
        Moosen:还是有挺多朋友理不清这个流程的,迟点我把流程图补上来在这个文章上,我们在简书上交流就可以了,如果我懂的话我会尽快给你我的想法和处理方法。
      • 为梦而飞:你好,我向请教一下,“”这里直接跟服务器确认支付结果,支付结果确认后回调处理结果“,这个服务器是PayPal的服务器还是自己公司的服务器,确认支付结果是自己服务器那边确认还是APP端确认?谢谢
        汤圆_9a37:@为梦而飞 别闹, 你post给服务器结果服务器判断不就行了 , 你还让人家手把手给你写个接口啊
        为梦而飞:@Moosen 谢谢,现在就是服务器那边不知道怎么确认支付结果,能否说一下流程
        Moosen:App post Json 数据给自己服务器确认支付结果。
      • 一只想养猫的鱼:请问楼主,您说的支付安全考虑是指啥,paypal SDK不太安全么?
        skyshowshow:@Moosen 同上,一样实现了网页付款。但是总感觉不是最有实现方式
        Moosen:@一只想养猫的鱼 订单金额和数量都是在客户端Po给PayPal 服务器的,如果app被破解,就可以直接调接口来修改订单信息和金额,我们是这么认为的,但PayPal 公司的工程师来过我们公司给我们说基本都不会发生这样的情况,是安全的,但是他们公司还是没有推荐直接集成sdk的方式,都是希望直接调网页付款,因为sdk还不可以直接用信用卡直接付款。
      • skyshowshow:请问支付成功前不用和服务器打交道吗?服务器端主要做的什么,怎么集成的呢
        30e023a6a9e3:请问解决了吗?
      • 寒冬_腊月:好的开始 哈哈 :clap:

      本文标题:Android 集成PayPal支付

      本文链接:https://www.haomeiwen.com/subject/hyyqpttx.html