Android多種支付方式的實(shí)現(xiàn)示例
1.場景
App 的支付流程,添加多種支付方式,不同的支付方式,對(duì)應(yīng)的操作不一樣,有的會(huì)跳轉(zhuǎn)到一個(gè)新的webview,有的會(huì)調(diào)用系統(tǒng)瀏覽器,有的會(huì)進(jìn)去一個(gè)新的表單頁面,等等。
并且可以添加的支付方式也是不確定的,由后臺(tái)動(dòng)態(tài)下發(fā)。
如下圖所示:

根據(jù)上圖 ui 理一下執(zhí)行流程:
- 點(diǎn)擊不同的添加支付方式 item。
- 進(jìn)入相對(duì)應(yīng)的添加支付方式流程(表單頁面、webview、彈框之類的)。
- 在第三方回調(diào)里面根據(jù)不同的支付方式執(zhí)行不同的操作。
- 調(diào)用后臺(tái)接口查詢添加是否成功。
- 根據(jù)接口結(jié)果展示不同的成功或者失敗的ui.
2.以前的實(shí)現(xiàn)方式
用一個(gè) Activity 承載,上述所有的流程都在 Activity 中。Activity 包含了列表展示、多種支付方式的實(shí)現(xiàn)和 ui。
偽代碼如下:
class AddPaymentListActivity : AppCompatActivity(R.layout.activity_add_card) {
private val addPaymentViewModel : AddPaymentViewModel = ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPaymentViewModel.checkPaymentStatusLiveData.observer(this) { isSuccess ->
// 從后臺(tái)結(jié)果判斷是否添加成功
if (isSuccess) {
addCardSuccess(paymentType)
} else {
addCardFailed(paymentType)
}
}
}
private fun clickItem(paymentType: PaymentType) {
when (paymentType) {
PaymentType.ADD_GOOGLE_PAY -> //執(zhí)行添加谷歌支付流程
PaymentType.ADD_PAY_PEL-> //執(zhí)行添加PayPel支付流程
PaymentType.ADD_ALI_PAY-> //執(zhí)行添加支付寶支付流程
PaymentType.ADD_STRIPE-> //執(zhí)行添加Stripe支付流程
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (resultCode) {
PaymentType.ADD_GOOGLE_PAY -> {
// 根據(jù)第三方回調(diào)的結(jié)果,拿到key
// 根據(jù)key調(diào)用后臺(tái)的Api接口查詢是否添加成功
}
PaymentType.ADD_PAY_PEL -> // 同上
// ...
}
}
private fun addCardSuccess(paymentType: PaymentType){
when (paymentType) {
PaymentType.ADD_GOOGLE_PAY -> // 添加對(duì)應(yīng)的支付方式成功,展示成功的ui,然后執(zhí)行下一步操作
PaymentType.ADD_PAY_PEL-> // 同上
// ...
}
}
private fun addCardFailed(paymentType: PaymentType){
when (paymentType) {
PaymentType.ADD_GOOGLE_PAY -> // 添加對(duì)應(yīng)的支付方式失敗,展示失敗的ui
PaymentType.ADD_PAY_PEL-> // 同上
// ...
}
}
enum class PaymentType {
ADD_GOOGLE_PAY, ADD_PAY_PEL, ADD_ALI_PAY, ADD_STRIPE
}
}雖然看起來根據(jù) paymentType 來判斷,邏輯條理也還過得去,但是實(shí)際上復(fù)雜度遠(yuǎn)遠(yuǎn)不止如此。
• 不同的支付方式跳轉(zhuǎn)的頁面相差很大。
• 結(jié)果的回調(diào)獲取也相差很大,并不是所有的都在onActivityResult中。
• 成功和失敗實(shí)際上也不能統(tǒng)一來處理,里面包含很多的if…else…判斷。
• 如果支付方式是后臺(tái)動(dòng)態(tài)下發(fā)的,處理起來判斷邏輯就更多了。
此外,最大的問題:擴(kuò)展性問題。
當(dāng)新來一種支付方式,例如微信支付之類的,改動(dòng)代碼就很大了,基本就是將整個(gè)Activity中的代碼都要改動(dòng)。可以說上面這種方式的可擴(kuò)展性為零,就是簡單的將代碼都揉在一起。
3.優(yōu)化后的代碼
要想實(shí)現(xiàn)高內(nèi)聚低耦合,最簡單的就是套用常見的設(shè)計(jì)模式,回想一下,發(fā)現(xiàn)策略模式+簡單工廠模式非常這種適合這種場景。
先看下優(yōu)化后的代碼:
class AddPlatformActivity : BaseActivity() {
private var addPayPlatform: IAddPayPlatform? = null
private fun addPlatform(payPlatform: String) {
// 將后臺(tái)返回的支付平臺(tái)字符串變成枚舉類
val platform: PayPlatform = getPayPlatform(payPlatform) ?: return
addPayPlatform = AddPayPlatformFactory.getCurrentPlatform(this, platform)
addPayPlatform?.getLoadingLiveData()?.observe(this@AddPlatformActivity) { showLoading ->
if (showLoading) startLoading() else stopLoading()
}
addPayPlatform?.addPayPlatform(AddCardParameter(platform))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// 將onActivityResult的回調(diào)轉(zhuǎn)接到需要監(jiān)聽的策略類里面
addPayPlatform?.thirdAuthenticationCallback(requestCode, resultCode, data)
}
}4.策略模式
意圖: 定義一系列的算法,把它們一個(gè)個(gè)封裝起來, 并且使它們可相互替換。
主要解決: 在有多種算法相似的情況下,使用if…else所帶來的復(fù)雜和難以維護(hù)。
何時(shí)使用: 一個(gè)系統(tǒng)有許多許多類,而區(qū)分它們的只是他們直接的行為。
如何解決: 將這些算法封裝成一個(gè)一個(gè)的類,任意地替換。
關(guān)鍵代碼: 實(shí)現(xiàn)同一個(gè)接口。
**優(yōu)點(diǎn): **
1、算法可以自由切換。
2、避免使用多重條件判斷。
3、擴(kuò)展性良好。
缺點(diǎn):
1、策略類會(huì)增多。
2、所有策略類都需要對(duì)外暴露。
**使用場景: **
1、如果在一個(gè)系統(tǒng)里面有許多類,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為。
2、一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。
3、如果一個(gè)對(duì)象有很多的行為,如果不用恰當(dāng)?shù)哪J?,這些行為就只好使用多重的條件選擇語句來實(shí)現(xiàn)。
5.需要實(shí)現(xiàn)的目標(biāo)
5.1 解耦宿主 Activity
現(xiàn)在宿主Activity中代碼太重了,包含多種支付方式實(shí)現(xiàn),還有列表ui的展示,網(wǎng)絡(luò)請(qǐng)求等。
現(xiàn)在目標(biāo)是將 Activity 中的代碼拆分開來,讓宿主 Activity 變得小而輕。
如果產(chǎn)品說新增一種支付方式,只需要改動(dòng)很少的代碼,就可以輕而易舉的實(shí)現(xiàn)。
5.2 抽取成獨(dú)立的模塊
因?yàn)楣局杏锌赡艽嬖诙鄠€(gè)項(xiàng)目,支付模塊的分層應(yīng)該處于可復(fù)用的層級(jí),以后很有可能將其封裝成一個(gè)獨(dú)立的 mouble,給不同的項(xiàng)目使用。
現(xiàn)在代碼全在 Activity 中,以后若是抽取 mouble 的話,相當(dāng)于整個(gè)需求重做。
5.3 組件黑盒
"組件黑盒"這個(gè)名詞是我自己的一個(gè)定義。大致意思:
將一個(gè) View 或者一個(gè)類進(jìn)行高度封裝,盡可能少的暴露public方法給外部使用,自成一體。
業(yè)務(wù)方在使用時(shí),可以直接黑盒使用某個(gè)業(yè)務(wù)組件,不必關(guān)心其中的邏輯。
業(yè)務(wù)方只需要一個(gè)簡單的操作,例如點(diǎn)擊按鈕調(diào)用方法,然后邏輯都在組件內(nèi)部實(shí)現(xiàn),組件內(nèi)處理外部事件的所有操作,例如:Loading、請(qǐng)求網(wǎng)絡(luò)、成功或者失敗。
業(yè)務(wù)方都不需要知道組件內(nèi)部的操作,做到宿主和組件的隔離。
當(dāng)然這種處理也是要分場景考慮的,其中一個(gè)重點(diǎn)就是這個(gè)組件是偏業(yè)務(wù)還是偏功能,也就是是否要將業(yè)務(wù)邏輯統(tǒng)一包進(jìn)組件,想清楚這個(gè)問題后,才能去開發(fā)一個(gè)業(yè)務(wù)組件。
因?yàn)樘砑又Ц斗绞绞且粋€(gè)偏業(yè)務(wù)的功能,我的設(shè)計(jì)思路是:
外部 Activity 點(diǎn)擊添加對(duì)應(yīng)的支付方式,將支付方式的枚舉類型和支付方式有關(guān)的參數(shù)通過傳遞,然后不同的策略類組件執(zhí)行自己的添加邏輯,再通過一層回調(diào)將第三方支付的回調(diào)從 Activity 中轉(zhuǎn)接過來,每個(gè)策略類內(nèi)部處理自己的回調(diào)操作,具體的策略類自己維護(hù)成功或者失敗的ui。摘自https://xuyisheng.top/author/xuyisheng/
6.具體實(shí)現(xiàn)
6.1 定義頂層策略接口
interface IAddPayPlatform {
fun addPayPlatform(param: AddCardParameter)
fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, data: Intent?)
fun addCardFailed(message: String?)
fun addCardSuccess()
}6.2 通用支付參數(shù)類
open class AddCardParameter(val platform: PayPlatform)
class AddStripeParameter(val card: Card, val setPrimaryCard: Boolean, platform: PayPlatform)
: AddCardParameter(platform = PayPlatform.Stripe)因?yàn)橛泻芏喾N添加支付方式,不同的支付方式對(duì)應(yīng)的參數(shù)都不一樣。
所以先創(chuàng)建一個(gè)通用的卡片參數(shù)基類AddCardParameter, 不同的支付方式去實(shí)現(xiàn)不同的具體參數(shù)。這樣的話策略接口就可以只要寫一個(gè)添加卡片的方法addPayPlatform(param: AddCardParameter)。
6.3 Loading 的處理
因?yàn)槲蚁雽?shí)現(xiàn)的是黑盒組件的效果,所有添加卡片的loading也是封裝在每一個(gè)策略實(shí)現(xiàn)類里面的。
Loading的出現(xiàn)和消失這里有幾種常見的實(shí)現(xiàn)方式:
• 傳遞BaseActivity的引用,因?yàn)槲业膌oading有關(guān)的方法是放在BaseActivity中,這種方式簡單但是會(huì)耦合BaseActivity。
• 使用消息事件總線,例如EventBus之類的,這種方式解耦強(qiáng),但是消息事件不好控制,還要添加多余的依賴庫。
• 使用LiveData,在策略的通用接口中添加一個(gè)方法返回Loading的LiveData, 讓宿主Activity自己去實(shí)現(xiàn)。
interface IAddPayPlatform {
// ...
fun getLoadingLiveData(): LiveData<Boolean>?
}6.4 提取BaseAddPayStrategy
因?yàn)槊恳粋€(gè)添加卡的策略會(huì)存在很多相同的代碼,這里我抽取一個(gè)BaseAddPayStrategy來存放模板代碼。
需要實(shí)現(xiàn)黑盒組件的效果,宿主Activity中都不需要去關(guān)注添加支付方式是不是存在網(wǎng)絡(luò)請(qǐng)求這一個(gè)過程,所以網(wǎng)絡(luò)請(qǐng)求也分裝在每一個(gè)策略實(shí)現(xiàn)類里面。
abstract class BaseAddPayStrategy(val activity: AppCompatActivity, val platform: PayPlatform) : IAddPayPlatform {
private val loadingLiveData = SingleLiveData<Boolean>()
protected val startActivityIntentLiveData = SingleLiveData<Intent>()
override fun getLoadingLiveData(): LiveData<Boolean> = loadingLiveData
protected fun startLoading() = loadingLiveData.setValue(true)
protected fun stopLoading() = loadingLiveData.setValue(false)
private fun reloadWallet() {
startLoading()
// 添加卡片完成后,重新刷新錢包數(shù)據(jù)
}
override fun addCardSuccess() {
reloadWallet()
}
override fun addCardFailed(message: String?) {
stopLoading()
if (isEWalletPlatform(platform)) showAddEWalletFailedView() else showAddPhysicalCardFailedView(message)
}
/**
* 添加實(shí)體卡片失敗展示ui
*/
private fun showAddPhysicalCardFailedView(message: String?) {
showSaveErrorDialog(activity, message)
}
/**
* 添加實(shí)體卡片成功展示ui
*/
private fun showAddPhysicalCardSuccessView() {
showCreditCardAdded(activity) {
activity.setResult(Activity.RESULT_OK)
activity.finish()
}
}
private fun showAddEWalletSucceedView() {
// 添加電子錢包成功后的執(zhí)行
activity.setResult(Activity.RESULT_OK)
activity.finish()
}
private fun showAddEWalletFailedView() {
// 添加電子錢包失敗后的執(zhí)行
}
// ---默認(rèn)空實(shí)現(xiàn),有些支付方式不需要這些方法---
override fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, data: Intent?) = Unit
override fun getStartActivityIntent(): LiveData<Intent> = startActivityIntentLiveData
}6.5 具體的策略類實(shí)現(xiàn)
通過傳遞過來的AppCompatActivity引用獲取添加卡片的ViewModel實(shí)例AddPaymentViewModel,然后通過AddPaymentViewModel去調(diào)用網(wǎng)絡(luò)請(qǐng)求查詢添加卡片是否成功。
class AddXXXPayStrategy(activity: AppCompatActivity) : BaseAddPayStrategy(activity, PayPlatform.XXX) {
protected val addPaymentViewModel: AddPaymentViewModel by lazy {
ViewModelProvider(activity).get(AddPaymentViewModel::class.java)
}
init {
addPaymentViewModel.eWalletAuthorizeLiveData.observeState(activity) {
onSuccess { addCardSuccess()}
onError { addCardFailed(it.detailed) }
}
}
override fun thirdAuthenticationCallback(requestCode: Int?, resultCode: Int?, result: Intent?) {
val uri: Uri = result?.data ?: return
if (uri.host == "www.xxx.com") {
uri.getQueryParameter("transactionId")?.let {
addPaymentViewModel.confirmEWalletAuthorize(platform.name, it)
}
}
}
override fun addPayPlatform(param: AddCardParameter) {
startLoading()
addPaymentViewModel.addXXXCard(param)
}
}7.簡單工廠進(jìn)行優(yōu)化
因?yàn)槲也幌朐贏ctivity中去引用每一個(gè)具體的策略類,只想引用抽象接口類IAddPayPlatform, 這里通過一個(gè)簡單工廠來優(yōu)化。
fun setCurrentPlatform(activity: AppCompatActivity, payPlatform: PayPlatform): IAddPayPlatform? {
return when (payPlatform) {
PayPlatform.STRIPE -> AddStripeStrategy(activity)
PayPlatform.PAYPAL -> AddPayPalStrategy(activity)
PayPlatform.LINEPAY -> AddLinePayStrategy(activity)
PayPlatform.GOOGLEPAY -> AddGooglePayStrategy(activity)
PayPlatform.RAPYD -> AddRapydStrategy(activity)
else -> null
}
}8.再增加一種支付方式
如果再增加一種支付方式,宿主Activity中的代碼都可以不要改動(dòng),只需要新建一個(gè)新的策略類,實(shí)現(xiàn)頂層策略接口即可。
這樣,不管是刪除還是新增一種支付方式,維護(hù)起來就很容易了。
策略模式的好處就顯而易見了。
以上就是Android多種支付方式的實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于Android支付方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android動(dòng)畫實(shí)現(xiàn)原理和代碼
這篇文章主要介紹了Android動(dòng)畫實(shí)現(xiàn)原理和代碼分析,如果你對(duì)此感興趣,跟著小編學(xué)習(xí)下吧。2017-12-12
VS Code開發(fā)React-Native及Flutter 開啟無線局域網(wǎng)安卓真機(jī)調(diào)試問題
這篇文章主要介紹了VS Code開發(fā)React-Native,F(xiàn)lutter 開啟無線局域網(wǎng)安卓真機(jī)調(diào)試,需要的朋友可以參考下2020-04-04
Android中3種全屏方法及3種去掉標(biāo)題欄的方法
這篇文章主要介紹了Android中3種全屏方法及3種去掉標(biāo)題欄的方法,二個(gè)問題各給出了3種解決方法,并給出實(shí)例代碼,需要的朋友可以參考下2015-06-06
深入淺析Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密
一般的手機(jī)沒有root權(quán)限,進(jìn)不去data/data目錄,當(dāng)手機(jī)刷機(jī)了后,擁有root權(quán)限,就可以進(jìn)入data/data目錄,查看我們保存的密碼文件,因此我們需要對(duì)存入的密碼進(jìn)行MD5加密,接下來通過本文給大家介紹Android手機(jī)衛(wèi)士保存密碼時(shí)進(jìn)行md5加密,需要的朋友一起學(xué)習(xí)吧2016-04-04
Android自定義VIew實(shí)現(xiàn)衛(wèi)星菜單效果淺析
這篇文章主要介紹了Android自定義VIew實(shí)現(xiàn)衛(wèi)星菜單效果淺析,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11
Android ExpandableListView用法示例詳解
ExpandableListView 是 Android 中一個(gè)非常實(shí)用的列表控件,它可以幫助我們實(shí)現(xiàn)具有分組功能的列表展示,通過本文的介紹,你應(yīng)該已經(jīng)掌握了 ExpandableListView 的基本用法,感興趣的朋友跟隨小編一起看看吧2025-02-02
Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例的相關(guān)資料,這里對(duì)定時(shí)器進(jìn)行詳解,并附實(shí)例代碼,需要的朋友可以參考下2016-12-12
Android開發(fā)之自動(dòng)朗讀TTS用法分析
這篇文章主要介紹了Android開發(fā)之自動(dòng)朗讀TTS用法,較為詳細(xì)的分析了TTS的概念、功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-06-06
Android開發(fā)四大組件之實(shí)現(xiàn)電話攔截和電話錄音
這篇文章給大家介紹Android開發(fā)四大組件之實(shí)現(xiàn)電話攔截和電話錄音,涉及到android四大基本組件在程序中的應(yīng)用,對(duì)android四大基本組件感興趣的朋友可以參考下本篇文章2015-10-10

