前言
相信做app的童鞋都知道雅潭,我們app 肯定離不開移動支付的均蜜,而我們經(jīng)常使用的支付一般就是微信支付,支付寶支付這2個示绊。
而題主最近剛好離職锭部,也比較閑,剛好總結(jié)了之前做過的支付DEMO面褐,整合了微信支付拌禾,支付寶支付,銀聯(lián)支付展哭,貝寶支付湃窍,整合成一個demo,也算是一個經(jīng)驗總結(jié)吧匪傍。
github地址:https://github.com/LinHuanTanLy/Pay_Master
正文
項目結(jié)構(gòu)介紹:
其中網(wǎng)絡請求我們使用了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 {
/**
* 沙盒環(huán)境
*/
String CONFIG_CLIENT_ID_SANDBOX = "xxxxlZPMz2PN3C8akROwHZjDnzmRDGdxt965BkkvVfF8cUlzRU8a2AALVYCPMSc9uwqyJY5";
/**
* 正式環(huán)境
*/
String CONFIG_CLIENT_ID_LIVE = "xxxxEiCmYlq83H73jHejGw8r-hyaiL0WbueHIUbOLtSEV_Vfh8rkU4aawFknGQZhA";
}
/**
* 銀行卡配置環(huán)境
*/
public interface CardConf {
/**
* 銀聯(lián)支付 配置信息
*
* @return 01 沙盒環(huán)境 00 正式環(huán)境
*/
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支付狀態(tài)
*/
String PAYPAL_SYN_ORDER = BASE_URL + "/user/pay/synPaypalOrder.do";
/**
* 銀聯(lián)支付 獲取tn
*/
String CARD_PAY_INFO = "http://101.231.204.84:8091/sim/getacptn";
}
}
微信支付:
微信支付現(xiàn)在已經(jīng)可以支持依賴導入了。
- 在build.gradle 寫入依賴:
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
- 在清單文件中寫入權限:
<!--for wechat pay-->
<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"/>
- 在后臺配置的包名下新建wxapi包棵介,并且新建一個類钉鸯,命名為WXPayEntryActivity,實現(xiàn)IWXAPIEventHandler接口邮辽,其中我們需要注意的是:假設項目包名為 com.ly.PayDemo唠雕,那么這個類的路徑就應該是com.ly.PayDemo.wxapi.WXPayEntryActivity扣蜻,包名,路徑都不可以錯及塘,否則無法進入回調(diào)頁面!并且記得在AndroidManifest.xml進行注冊锐极。
<!--微信支付成功回調(diào)的頁面-->
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop"/>
<!--end of 微信支付-->
- 真正進行微信支付笙僚,首先我們看下我們的支付類,相信大家可以看出邏輯:
/**
* @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里面吊起微信支付。
- 值得一提的是翎迁,我們要如何接受支付的回調(diào)栋猖,那就是要靠我們之前大費周章寫的WXPayEntryActivity:
@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;
}
}
在這里我們可以處理下這個頁面痴腌,而如果我們不需要這個頁面而又必須靠這個頁面去接受回調(diào)雌团,有個小技巧,我們可以把這個頁面1dp士聪,或者是修改theme為dialog锦援。
支付寶支付:
-
導入JAR:
支付寶的話暫時沒有依賴方法,我們需要手動導入jar包:
支付寶的jar包 - 配置清單文件:
需要配置的權限為:
<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 支付寶支付-->
- 我們看下支付寶支付的類:
/**
* @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);
/**
* 同步返回的結(jié)果必須放置到服務端進行驗證(驗證的規(guī)則請看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”則代表支付成功,具體狀態(tài)碼代表含義可參考接口文檔
if (TextUtils.equals(resultStatus, "9000")) {
Toast.makeText(AliPayActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
} else {
// 判斷resultStatus 為非"9000"則代表可能支付失敗
// "8000"代表支付結(jié)果因為支付渠道原因或者系統(tǒng)原因還在等待支付結(jié)果確認区岗,最終交易是否成功以服務端異步通知為準(小概率狀態(tài))
if (TextUtils.equals(resultStatus, "8000")) {
Toast.makeText(AliPayActivity.this, "支付結(jié)果確認中", Toast.LENGTH_SHORT).show();
} else {
// 其他值就可以判斷為支付失敗略板,包括用戶主動取消支付,或者系統(tǒng)返回的錯誤
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());
}
});
}
/**
* 調(diào)用SDK支付
*/
public void aliPay(final String payInfo) {
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 構(gòu)造PayTask 對象
PayTask alipay = new PayTask(AliPayActivity.this);
// 調(diào)用支付接口慈缔,獲取支付結(jié)果
String result = alipay.pay(payInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必須異步調(diào)用
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 從服務器獲取我們的訂單信息蚯根。
獲取到了信息后,我們通過調(diào)用支付寶的支付api吊起支付:
/**
* 調(diào)用SDK支付
*/
public void aliPay(final String payInfo) {
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 構(gòu)造PayTask 對象
PayTask alipay = new PayTask(AliPayActivity.this);
// 調(diào)用支付接口胀糜,獲取支付結(jié)果
String result = alipay.pay(payInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必須異步調(diào)用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
而吊起了支付后颅拦,支付結(jié)果我們可以在handler中看到,當然教藻!涉及到支付的距帅,我們app本地所謂“支付成功”,"支付失敗"都是不靠譜的,最靠譜的還是得靠服務器那邊的回調(diào)括堤。
銀聯(lián)支付
- 導入JAR以及SO
銀聯(lián)的導入相對比較麻煩碌秸,需要導入JAR,SO,還有BIN文件
銀聯(lián)支付的配置
因為我們的so是放在libs下面的绍移,并且我們只導入3個cpu類型,所以我們需要在build.gradle文件做如下配置:
在defaultConfig下配置ndk:
ndk {
//選擇要添加的對應cpu類型的.so庫讥电。
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a'
// 還可以添加 'x86', 'x86_64', 'mips', 'mips64'
}
在android下配置:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
至此導入完成蹂窖。
- 我們?nèi)耘f需要在清單文件進行配置:
<!--銀聯(lián)支付-->
<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 銀聯(lián)支付-->
- 我們照舊看下銀聯(lián)支付的類;
/**
* @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")) {
// 如果想對結(jié)果數(shù)據(jù)驗簽纠炮,可使用下面這段代碼月趟,但建議不驗簽,直接去商戶后臺查詢交易結(jié)果
// result_data結(jié)構(gòu)見c)result_data參數(shù)說明
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) {
// 驗簽成功孝宗,顯示支付結(jié)果
msg = "支付成功!";
} else {
// 驗簽失敗
msg = "支付失敻纭因妇!";
}
} catch (JSONException e) {
}
}
// 結(jié)果result_data為成功時,去商戶后臺查詢一下再展示成功
msg = "支付成功猿诸!";
} else if (str.equalsIgnoreCase("fail")) {
msg = "支付失斏尘!";
} else if (str.equalsIgnoreCase("cancel")) {
msg = "用戶取消了支付";
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("支付結(jié)果通知");
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();
}
});
}
/**
* 獲取銀聯(lián)支付的信息
*/
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 獲取服務器上的訂單信息
獲取到了訂單信息后,我們調(diào)用支付的方法:
UPPayAssistEx.startPay(CardPayActivity.this, null, null, response, AppConf.CardConf.SANDBOX);
這里我們注意AppConf.CardConf.SANDBOX怖辆,這里使用的是沙盒模式是复,對前文的配置類還有印象的話,應該記得我使用的是沙盒的模式竖螃,包括獲取tn訂單信息淑廊,也都是沙盒的;當然特咆,這個以后可以替換成app自己的服務器接口季惩。
paypal支付
相信各位看官對這個支付應該是陌生的吧,
可以查看下:https://www.paypal-biz.com/腻格,這個是用在之前的某個海外項目上的画拾,貝寶有2種接入方式,我們這邊使用的是比較老的支付方法
- 導入
- 配置
<!--for paypal-->
<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。
- 看下我們的支付類:
/**
* @author Ly
* @date 2017/10/24
*/
public class PayPalPayActivity extends AppCompatActivity {
private Button mBtPaypalPay;
private String token;
/**
* 你在PalPay創(chuàng)建的測試應用客戶端ID
*/
private static final String CONFIG_CLIENT_ID = AppConf.PayPalConf.CONFIG_CLIENT_ID_LIVE;
/**
* 沙盒測試(ENVIRONMENT_SANDBOX)酬核,生產(chǎn)環(huán)境(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
- 為了區(qū)分訂單信息,我們拿到后臺返回的信息后此迅,還需要自己憑借一段標識信息傳遞給服務器(這個是我們服務器自己的需求汽畴,不是每個app都需要)
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);
- 拿到支付結(jié)果后,我們需要請求服務器接口進行校驗邮屁,其實相當于驗簽(這個也是我們服務器的需求,不是每個app都需要的)
參考方法: doSynPaypalOrderStatus
結(jié)尾
其實我們看了4個支付方案菠齿,有沒有覺得有什么共同點呢:
拿取訂單信息 ---> 吊起支付 ----> 支付后接受callback(視具體情況是否需要驗簽)
總結(jié)
額佑吝,好像也沒什么好說的,上著班偷偷摸摸寫的绳匀,算了芋忿,繼續(xù)打代碼去。
AND
各位程序猿/媛 節(jié)日快樂
AND 毒奶一波
祝:諸君與我早日成為程序員