一文带你了解移动支付

2,748 阅读12分钟

前言

相信做app的童鞋都知道,我们app 肯定离不开移动支付的,而我们经常使用的支付一般就是微信支付,支付宝支付这2个。
而题主最近刚好离职,也比较闲,刚好总结了之前做过的支付DEMO,整合了微信支付,支付宝支付,银联支付,贝宝支付,整合成一个demo,也算是一个经验总结吧。

丑丑的界面
丑丑的界面

github地址:github.com/LinHuanTanL…

正文

项目结构介绍:

最基础的项目目录结构
最基础的项目目录结构

其中网络请求我们使用了okhttputils,解析JSON用了gson

配置类介绍:

我们所有需要的配置都写在配置类里面,这个类也在我们项目中扮演着很重要的角色,当然,为了避嫌,我们BASE_URL以及一些配置文件做了xxxxx处理,大家可以替换成你们自己的key然后再运行。代码如下:


/**
 * @author Ly
 * @date 2017/10/24
 * 配置类
 */

public class AppConf {
    /**
     * BaseUrl
     */
    private static final String BASE_URL = "https://app.globalxxx.com";

    /**
     * 微信配置文件
     */
    public interface WechatConf {
        String APP_ID = "xxxxxxxab57ab288";
        String APP_SECRET = "xxxxxxxx1269874371fc75a79a";
    }

    /**
     * 贝宝的配置文件
     */
    public interface PayPalConf {
        /**
         * 沙盒环境
         */
        String CONFIG_CLIENT_ID_SANDBOX = "xxxxlZPMz2PN3C8akROwHZjDnzmRDGdxt965BkkvVfF8cUlzRU8a2AALVYCPMSc9uwqyJY5";
        /**
         * 正式环境
         */
        String CONFIG_CLIENT_ID_LIVE = "xxxxEiCmYlq83H73jHejGw8r-hyaiL0WbueHIUbOLtSEV_Vfh8rkU4aawFknGQZhA";
    }

    /**
     * 银行卡配置环境
     */
    public interface CardConf {
        /**
         * 银联支付 配置信息
         *
         * @return 01 沙盒环境 00 正式环境
         */
        String SANDBOX = "01", FORMAL = "00";

    }

    /**
     * 接口配置文件
     */
    public interface NetConf {
        /**
         * 登录信息
         */
        String LOGIN = BASE_URL + "/user/login.do";
        /**
         * 微信支付信息
         */
        String WECHAT_PAY_INFO = BASE_URL + "/user/pay/weChatRecharge.do";
        /**
         * 支付宝支付信息
         */
        String ALI_PAY_INFO = BASE_URL + "/user/pay/alipayRecharge.do";

        /**
         * 贝宝支付信息
         */
        String PAYPAL_PAY_INFO = BASE_URL + "/user/pay/getPayPalOrderId.do";
        /**
         * 验证paypal支付状态
         */
        String PAYPAL_SYN_ORDER = BASE_URL + "/user/pay/synPaypalOrder.do";
        /**
         * 银联支付 获取tn
         */
        String CARD_PAY_INFO = "http://101.231.204.84:8091/sim/getacptn";
    }
}

微信支付:

微信支付现在已经可以支持依赖导入了。

  1. 在build.gradle 写入依赖:
    compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
  2. 在清单文件中写入权限:
    ``` xml





3. 在后台配置的包名下新建wxapi包,并且新建一个类,命名为*WXPayEntryActivity*,实现*IWXAPIEventHandler*接口,其中我们需要注意的是:假设项目包名为 *com.ly.PayDemo*,那么这个类的路径就应该是*com.ly.PayDemo.wxapi.WXPayEntryActivity*,包名,路径都不可以错,否则无法进入回调页面!并且记得在AndroidManifest.xml进行注册。
``` xml
  <!--微信支付成功回调的页面-->
        <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"/>
        <!--end of 微信支付-->
  1. 真正进行微信支付,首先我们看下我们的支付类,相信大家可以看出逻辑:

微信支付页面
微信支付页面

/**
 * @author Ly
 * @date 2017/10/24
 * 微信支付界面
 */

public class WeChatPayActivity extends AppCompatActivity implements View.OnClickListener {


    private TextView mTvWechatPay, mTvWechatIsSupport;


    /**
     * 微信支付
     */
    private IWXAPI api;

    private String token;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wechat_pay);
        Bundle bundle = getIntent().getBundleExtra("extra");
        if (bundle != null) {
            token = bundle.getString("token");
        }
        initView();
    }

    private void initView() {
        mTvWechatPay = (TextView) findViewById(R.id.tv_wechat_pay);
        mTvWechatIsSupport = (TextView) findViewById(R.id.tv_wechat_is_support);
        mTvWechatPay.setOnClickListener(this);
        mTvWechatIsSupport.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_wechat_pay:
                doGetWechatPayInfo();
                break;
            case R.id.tv_wechat_is_support:
                isPaySupported();
                break;
            default:
                break;
        }
    }

    /**
     * 获取微信订单
     */
    private void doGetWechatPayInfo() {
        OkHttpUtils.post()
                .url(AppConf.NetConf.WECHAT_PAY_INFO)
                .addParams("accessToken", token)
                .addParams("wRechargeMoney", "0.01")
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        WechatPayInfo wechatPayInfo = new Gson().fromJson(response, WechatPayInfo.class);
                        Log.e("xxx", wechatPayInfo.toString());
                        WXPay(wechatPayInfo.getData().getAppid(),
                                wechatPayInfo.getData().getPartnerid(),
                                wechatPayInfo.getData().getPrepayid(),
                                wechatPayInfo.getData().getTimestamp(),
                                wechatPayInfo.getData().getNoncestr(),
                                wechatPayInfo.getData().getPaySign());
                    }
                });
    }

    /**
     * 微信支付
     */
    private void WXPay(String appId, String partnerId, String prepayId, String timeStamp, String nonceStr, String paySign) {
        api = WXAPIFactory.createWXAPI(this, null);
        api.registerApp(AppConf.WechatConf.APP_ID);
        PayReq req = new PayReq();
        req.appId = appId;
        req.partnerId = partnerId;
        req.prepayId = prepayId;
        req.nonceStr = nonceStr;
        req.timeStamp = timeStamp;
        req.packageValue = "Sign=WXPay";
        req.sign = paySign;
        api.sendReq(req);
    }

    /**
     * 检测微信版本是否支持支付
     */
    private boolean isPaySupported() {
        if (api == null) {
            api = WXAPIFactory.createWXAPI(this, null);
            api.registerApp(AppConf.WechatConf.APP_ID);
        }
        boolean isPaySupported;
        isPaySupported = api.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT;
        if (!isPaySupported) {
            Toast.makeText(this, "您的微信版本不支持支付", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "您的微信版本支持支付", Toast.LENGTH_SHORT).show();
        }
        return isPaySupported;
    }

    public static void toWechatActivity(Activity activity, String token) {
        Intent intent = new Intent(activity, WeChatPayActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("token", token);
        intent.putExtra("extra", bundle);
        activity.startActivity(intent);
    }
}

我们可以看到,其实就分为2个方法:

  • isPaySupported 检测是否有微信客户端以及是否该客户端支持微信支付
  • doGetWechatPayInfo 从服务器获取订单信息,在callback里面吊起微信支付。
  1. 值得一提的是,我们要如何接受支付的回调,那就是要靠我们之前大费周章写的WXPayEntryActivity:
    ``` java
    @Override
    public void onResp(BaseResp resp) {
     Log.e("", "onPayFinish, errCode = " + resp.errCode);
     int code = resp.errCode;
     switch (code) {
         case 0://支付成功后的界面
             Toast.makeText(this, "支付成功", Toast.LENGTH_SHORT).show();
             finish();
             break;
         case -1:
             Toast.makeText(this, "签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、您的微信账号异常等", Toast.LENGTH_SHORT).show();
             finish();
             break;
         case -2://用户取消支付后的界面
             Toast.makeText(this, "用户取消", Toast.LENGTH_SHORT).show();
             finish();
             break;
         default:
             break;
     }
    }
在这里我们可以处理下这个页面,而如果我们不需要这个页面而又必须靠这个页面去接受回调,有个小技巧,我们可以把这个页面1dp,或者是修改theme为dialog。


### 支付宝支付:
1. 导入JAR:
支付宝的话暂时没有依赖方法,我们需要手动导入jar包:
![支付宝的jar包](http://upload-images.jianshu.io/upload_images/1924616-7a1a9ad258b7c0f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2. 配置清单文件:
 需要配置的权限为:
``` xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

其实与微信支付是一样的,所以我们不赘述。
但是我们要配置2个activity:

 <!--支付宝支付-->
        <activity
            android:name="com.alipay.sdk.app.H5PayActivity"
            android:configChanges="orientation|keyboardHidden|navigation|screenSize"
            android:exported="false"
            android:screenOrientation="behind"
            android:windowSoftInputMode="adjustResize|stateHidden">
        </activity>
        <activity
            android:name="com.alipay.sdk.app.H5AuthActivity"
            android:configChanges="orientation|keyboardHidden|navigation"
            android:exported="false"
            android:screenOrientation="behind"
            android:windowSoftInputMode="adjustResize|stateHidden">
        </activity>

        <!--end of  支付宝支付-->
  1. 我们看下支付宝支付的类:
    ``` java

/**

  • @author Ly
  • @date 2017/10/24
  • 支付宝支付
    */

public class AliPayActivity extends AppCompatActivity {
private Button mBtAliPay;

private String token;
/**
 * 支付宝支付
 */
private static final int SDK_PAY_FLAG = 1;


@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
    @Override
    @SuppressWarnings("unused")
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SDK_PAY_FLAG: {
                AliPayResult payResult = new AliPayResult((String) msg.obj);
                /**
                 * 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/
                 * detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665&
                 * docType=1) 建议商户依赖异步通知
                 */
                String resultInfo = payResult.getResult();// 同步返回需要验证的信息
                String resultStatus = payResult.getResultStatus();
                // 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
                if (TextUtils.equals(resultStatus, "9000")) {
                    Toast.makeText(AliPayActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
                } else {
                    // 判断resultStatus 为非"9000"则代表可能支付失败
                    // "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)
                    if (TextUtils.equals(resultStatus, "8000")) {
                        Toast.makeText(AliPayActivity.this, "支付结果确认中", Toast.LENGTH_SHORT).show();

                    } else {
                        // 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误
                        Toast.makeText(AliPayActivity.this, "支付失败", Toast.LENGTH_SHORT).show();

                    }
                }
                break;
            }
            default:
                break;
        }
    }
};

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ali_pay);
    Bundle bundle = getIntent().getBundleExtra("extra");
    if (bundle != null) {
        token = bundle.getString("token");
    }
    initView();
}

private void initView() {
    mBtAliPay = (Button) findViewById(R.id.bt_ali_pay);
    mBtAliPay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            doGetAliPayInfo();
        }
    });
}


/**
 * 获取支付宝信息
 */
private void doGetAliPayInfo() {
    OkHttpUtils.post().url(AppConf.NetConf.ALI_PAY_INFO)
            .addParams("accessToken", token)
            .addParams("aRechargeMoney", "0.01")
            .build()
            .execute(new StringCallback() {
                @Override
                public void onError(Call call, Exception e, int id) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(String response, int id) {
                    AliPayInfo aliPayInfo = new Gson().fromJson(response, AliPayInfo.class);
                    aliPay(aliPayInfo.getData().getOrderStr());
                }
            });
}

/**
 * 调用SDK支付
 */
public void aliPay(final String payInfo) {
    Runnable payRunnable = new Runnable() {
        @Override
        public void run() {
            // 构造PayTask 对象
            PayTask alipay = new PayTask(AliPayActivity.this);
            // 调用支付接口,获取支付结果
            String result = alipay.pay(payInfo, true);
            Message msg = new Message();
            msg.what = SDK_PAY_FLAG;
            msg.obj = result;
            mHandler.sendMessage(msg);
        }
    };
    // 必须异步调用
    Thread payThread = new Thread(payRunnable);
    payThread.start();
}

public static void toAliPayAcitivity(Activity activity, String token) {
    Intent intent = new Intent(activity, AliPayActivity.class);
    Bundle bundle = new Bundle();
    bundle.putString("token", token);
    intent.putExtra("extra", bundle);
    activity.startActivity(intent);
}

}


其实我们这个类中只有一个重要的方法:
* **doGetAliPayInfo** 从服务器获取我们的订单信息。
获取到了信息后,我们通过调用支付宝的支付api吊起支付:
```java
 /**
     * 调用SDK支付
     */
    public void aliPay(final String payInfo) {
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                // 构造PayTask 对象
                PayTask alipay = new PayTask(AliPayActivity.this);
                // 调用支付接口,获取支付结果
                String result = alipay.pay(payInfo, true);
                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };
        // 必须异步调用
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }

而吊起了支付后,支付结果我们可以在handler中看到,当然!涉及到支付的,我们app本地所谓“支付成功”,"支付失败"都是不靠谱的,最靠谱的还是得靠服务器那边的回调。

银联支付

  1. 导入JAR以及SO
    银联的导入相对比较麻烦,需要导入JAR,SO,还有BIN文件
    银联支付的配置
    银联支付的配置

    因为我们的so是放在libs下面的,并且我们只导入3个cpu类型,所以我们需要在build.gradle文件做如下配置:
    defaultConfig下配置ndk:
    ``` xml
    ndk {
         //选择要添加的对应cpu类型的.so库。
         abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
         // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
     }
在*android*下配置:
```xml
  sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

至此导入完成。

  1. 我们仍旧需要在清单文件进行配置:
    ``` xml

    <uses-library
        android:name="org.simalliance.openmobileapi"
        android:required="false"/>
    
    <activity
        android:name="com.unionpay.uppay.PayActivity"
        android:configChanges="orientation|keyboardHidden"
        android:excludeFromRecents="true"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustResize"/>
    
    <activity
        android:name="com.unionpay.UPPayWapActivity"
        android:configChanges="orientation|keyboardHidden"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustResize"/>
    <!--end of 银联支付-->

3. 我们照旧看下银联支付的类;
```java

/**
 * @author Ly
 * @date 2017/10/24
 * 银行卡支付界面
 */

public class CardPayActivity extends AppCompatActivity {

    private Button mBtCardPay;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_card);
        initView();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (data == null) {
            return;
        }

        String msg = "";
        /*
         * 支付控件返回字符串:success、fail、cancel 分别代表支付成功,支付失败,支付取消
         */
        String str = data.getExtras().getString("pay_result");
        if (str.equalsIgnoreCase("success")) {

            // 如果想对结果数据验签,可使用下面这段代码,但建议不验签,直接去商户后台查询交易结果
            // result_data结构见c)result_data参数说明
            if (data.hasExtra("result_data")) {
                String result = data.getExtras().getString("result_data");
                try {
                    JSONObject resultJson = new JSONObject(result);
                    String sign = resultJson.getString("sign");
                    String dataOrg = resultJson.getString("data");
                    // 此处的verify建议送去商户后台做验签
                    // 如要放在手机端验,则代码必须支持更新证书
                    boolean ret = verify(dataOrg, sign, AppConf.CardConf.SANDBOX);
                    if (ret) {
                        // 验签成功,显示支付结果
                        msg = "支付成功!";
                    } else {
                        // 验签失败
                        msg = "支付失败!";
                    }
                } catch (JSONException e) {
                }
            }
            // 结果result_data为成功时,去商户后台查询一下再展示成功
            msg = "支付成功!";
        } else if (str.equalsIgnoreCase("fail")) {
            msg = "支付失败!";
        } else if (str.equalsIgnoreCase("cancel")) {
            msg = "用户取消了支付";
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("支付结果通知");
        builder.setMessage(msg);
        builder.setInverseBackgroundForced(true);
        builder.setNegativeButton("确定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
    }

    private boolean verify(String dataOrg, String sign, String sandbox) {
        return true;
    }

    private void initView() {
        mBtCardPay = (Button) findViewById(R.id.bt_card_pay);
        mBtCardPay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                doGetCardPayInfo();
            }
        });
    }

    /**
     * 获取银联支付的信息
     */
    private void doGetCardPayInfo() {
        OkHttpUtils.get()
                .url(AppConf.NetConf.CARD_PAY_INFO)
                .build().execute(new StringCallback() {
            @Override
            public void onError(Call call, Exception e, int id) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(String response, int id) {
                Log.e("xxxx", response);
                UPPayAssistEx.startPay(CardPayActivity.this, null, null, response, AppConf.CardConf.SANDBOX);
            }
        });
    }


    public static void toCardPayActivity(Activity activity) {
        Intent intent = new Intent(activity, CardPayActivity.class);
        activity.startActivity(intent);
    }
}

其实我不说各位看官也知道了,这个类里面的方法也不多,就一个:

  • doGetCardPayInfo 获取服务器上的订单信息

获取到了订单信息后,我们调用支付的方法:

UPPayAssistEx.startPay(CardPayActivity.this, null, null, response, AppConf.CardConf.SANDBOX);

这里我们注意AppConf.CardConf.SANDBOX,这里使用的是沙盒模式,对前文的配置类还有印象的话,应该记得我使用的是沙盒的模式,包括获取tn订单信息,也都是沙盒的;当然,这个以后可以替换成app自己的服务器接口。

paypal支付

相信各位看官对这个支付应该是陌生的吧,
可以查看下:www.paypal-biz.com/,这个是用在之前的某个…

  1. 导入

贝宝导入
贝宝导入

  1. 配置
    ``` xml

     <service
         android:name="com.paypal.android.sdk.payments.PayPalService"
         android:exported="false" />
    
     <activity android:name="com.paypal.android.sdk.payments.PaymentActivity" />
     <activity android:name="com.paypal.android.sdk.payments.LoginActivity" />
     <activity android:name="com.paypal.android.sdk.payments.PaymentMethodActivity" />
     <activity android:name="com.paypal.android.sdk.payments.PaymentConfirmActivity" />
     <activity
         android:name="io.card.payment.CardIOActivity"
         android:configChanges="keyboardHidden|orientation" />
     <activity android:name="io.card.payment.DataEntryActivity" />
    
     <!--end of paypal-->
贝宝的支付确实是比较麻烦,不止需要导入6个activity,还需要我们导入一个service。
3. 看下我们的支付类:
``` java

/**
 * @author Ly
 * @date 2017/10/24
 */

public class PayPalPayActivity extends AppCompatActivity {

    private Button mBtPaypalPay;


    private String token;

    /**
     * 你在PalPay创建的测试应用客户端ID
     */
    private static final String CONFIG_CLIENT_ID = AppConf.PayPalConf.CONFIG_CLIENT_ID_LIVE;
    /**
     * 沙盒测试(ENVIRONMENT_SANDBOX),生产环境(ENVIRONMENT_PRODUCTION)
     */
    private static PayPalConfiguration config = new PayPalConfiguration()
            .environment(PayPalConfiguration.ENVIRONMENT_PRODUCTION)
            .clientId(CONFIG_CLIENT_ID);
    /**
     * 用于后台检验的paymentId
     */
    private String paymentId = null;

    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_paypal);
        startPayPalSer();
        Bundle bundle = getIntent().getBundleExtra("extra");
        if (bundle != null) {
            token = bundle.getString("token");
        }
        initView();
    }

    private void initView() {
        mBtPaypalPay = (Button) findViewById(R.id.bt_paypal_pay);
        mBtPaypalPay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                doGetPaypalPayInfo();
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //停止PayPalService服务
        stopService(new Intent(this, PayPalService.class));
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            PaymentConfirmation confirm1 = data
                    .getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
            String paymentId;
            try {
                paymentId = confirm1.toJSONObject().getJSONObject("response")
                        .getString("id");
                String paymentClient = confirm1.getPayment().toJSONObject()
                        .toString();
                doSynPaypalOrderStatus(paymentId);
                Log.e("onActivityResult-----", "paymentId: " + paymentId + ", payment_json: "
                        + paymentClient);
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else if (resultCode == Activity.RESULT_CANCELED) {
            Log.i("paymentExample", "The user canceled.");
        } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
            Log.i("paymentExample", "An invalid Payment or PayPalConfiguration was submitted. Please see the docs.");
        }
    }

    /**
     * 启动paypal服务
     */
    private void startPayPalSer() {
        //启动PayPalService服务
        Intent intent = new Intent(this, PayPalService.class);
        intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
        startService(intent);
    }

    /**
     * 获取贝宝的支付信息
     */
    private void doGetPaypalPayInfo() {
        OkHttpUtils.post()
                .url(AppConf.NetConf.PAYPAL_PAY_INFO)
                .addParams("accessToken", token)
                .addParams("rechangeUSD", "0.01")
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        PaypalInfoBean paypalInfoBean = new Gson().fromJson(response, PaypalInfoBean.class);
                        Log.e("xxx", paypalInfoBean.toString());
                        paymentId = paypalInfoBean.getData().getOrderId();
                        // PAYMENT_INTENT_SALE 意思是支付立即完成
                        // 修改 PAYMENT_INTENT_SALE 为 PAYMENT_INTENT_AUTHORIZE to only authorize payment and
                        // capture funds later.
                        PayPalPayment payment = new PayPalPayment(new BigDecimal(paypalInfoBean.getData().getRechangeUSD()), "USD", "充值支付",
                                PayPalPayment.PAYMENT_INTENT_SALE);
                        com.paypal.android.sdk.payments.PayPalItem[] payPalItems =
                                {new PayPalItem(paymentId,
                                        1,
                                        new BigDecimal(paypalInfoBean.getData().getRechangeUSD()),
                                        "USD",
                                        paymentId)};
                        // Total amount
                        BigDecimal subtotal = PayPalItem.getItemTotal(payPalItems);
                        // If you have shipping cost, add it here
                        BigDecimal shipping = new BigDecimal("0.0");
                        // If you have tax, add it here
                        BigDecimal tax = new BigDecimal("0.0");
                        PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails(
                                shipping, subtotal, tax);
                        payment.items(payPalItems).paymentDetails(paymentDetails);
                        Intent intent = new Intent(PayPalPayActivity.this, PaymentActivity.class);
                        intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);
                        startActivityForResult(intent, 0);
                    }
                });
    }

    /**
     * 校验贝宝
     *
     * @param paymentId
     */
    private void doSynPaypalOrderStatus(String paymentId) {
        OkHttpUtils.post()
                .url(AppConf.NetConf.PAYPAL_SYN_ORDER)
                .addParams("accessToken", token)
                .addParams("paymentId", paymentId)
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        Log.e("贝宝校验---", response);
                    }
                });
    }

    public static void toPayPalPayActivity(Activity activity, String token) {
        Intent intent = new Intent(activity, PayPalPayActivity.class);
        Bundle bundle = new Bundle();
        bundle.putString("token", token);
        intent.putExtra("extra", bundle);
        activity.startActivity(intent);
    }
}

相信各位看官也会觉得,这个类...繁琐了多!行,我们慢慢解释,有一些注意事项:

  • 在oncreate()需要启动一个service,而在ondestory()我们需要stop
  • 为了区分订单信息,我们拿到后台返回的信息后,还需要自己凭借一段标识信息传递给服务器(这个是我们服务器自己的需求,不是每个app都需要)
    ``` java
    PaypalInfoBean paypalInfoBean = new Gson().fromJson(response, PaypalInfoBean.class);
                      Log.e("xxx", paypalInfoBean.toString());
                      paymentId = paypalInfoBean.getData().getOrderId();
                      // PAYMENT_INTENT_SALE 意思是支付立即完成
                      // 修改 PAYMENT_INTENT_SALE 为 PAYMENT_INTENT_AUTHORIZE to only authorize payment and
                      // capture funds later.
                      PayPalPayment payment = new PayPalPayment(new BigDecimal(paypalInfoBean.getData().getRechangeUSD()), "USD", "充值支付",
                              PayPalPayment.PAYMENT_INTENT_SALE);
                      com.paypal.android.sdk.payments.PayPalItem[] payPalItems =
                              {new PayPalItem(paymentId,
                                      1,
                                      new BigDecimal(paypalInfoBean.getData().getRechangeUSD()),
                                      "USD",
                                      paymentId)};
                      // Total amount
                      BigDecimal subtotal = PayPalItem.getItemTotal(payPalItems);
                      // If you have shipping cost, add it here
                      BigDecimal shipping = new BigDecimal("0.0");
                      // If you have tax, add it here
                      BigDecimal tax = new BigDecimal("0.0");
                      PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails(
                              shipping, subtotal, tax);
                      payment.items(payPalItems).paymentDetails(paymentDetails);
                      Intent intent = new Intent(PayPalPayActivity.this, PaymentActivity.class);
                      intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);
                      startActivityForResult(intent, 0);

```

  • 拿到支付结果后,我们需要请求服务器接口进行校验,其实相当于验签(这个也是我们服务器的需求,不是每个app都需要的)
    参考方法: doSynPaypalOrderStatus

结尾

其实我们看了4个支付方案,有没有觉得有什么共同点呢:
拿取订单信息 ---> 吊起支付 ----> 支付后接受callback(视具体情况是否需要验签)

总结

额,好像也没什么好说的,上着班偷偷摸摸写的,算了,继续打代码去。
AND
各位程序猿/媛 节日快乐

AND 毒奶一波

眼泪哗啦啦地流
眼泪哗啦啦地流

祝:诸君与我早日成为程序员