相親原始碼中移動支付的實現,沒有想象中那麼難

雲豹科技程式設計師發表於2021-11-09

前言

在相親原始碼中實現移動支付其實是非常簡單的,因為只要按照第三方的文件來就行了,做過支付的人都知道支付的難點其實是在第三方文件和demo上(集中體現文件陳舊、demo容易誤導人、槽點太多),那就不得不先來吐槽下WX的開發文件和示例,我相信大部分人都被坑過,沒有對比就沒有傷害,相對而言,支付寶好很多,下面我先說重點再談支付流程。

開發優化要點

  • 微信回撥返回相親原始碼當前頁面部分機型會產生一閃而過的黑屏現象,測試機型三星S8,解決方案為在微信回撥頁面增加透明主題,如下:
     <!--解決微信支付回撥部分機型黑屏閃爍的問題-->
    <style name="wxPayTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item>
    </style>
    
    <!--回撥頁面WXPayEntryActivity關閉finish的時候增加-->
     overridePendingTransition(0, 0);
    
    <!--回撥頁面WXPayEntryActivity配置-->
     <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:configChanges="orientation|screenSize"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/wxPayTheme"
            android:windowSoftInputMode="adjustPan|stateAlwaysHidden" />
    
     <!--另外一種解決方案-->
     android:launchMode="singleTop"改為android:launchMode="singleInstance"
     建議優先採取第一種方案,該方案作為備選,畢竟微信推薦使用"singleTop"啟動模式。
  • DialogFragment記憶體洩漏問題,google雖然推薦使用DialogFragment替代Dialog,但是記憶體洩漏問題並未解決,試過很多方案,並未完美解決洩漏問題,故更改使用Activity結合動畫實現相親原始碼底部支付彈窗的效果。
 <!--底部彈框支付Activity主題樣式-->
    <style name="PayTranslucentTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item> <!-- 無標題 -->
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">true</item><!-- 半透明 -->
    </style>
    <!-- R.anim.push_bottom_in 進入動畫--><?xml version="1.0" encoding="utf-8"?><set xmlns:android="
    <translate
        android:duration="300"
        android:fromYDelta="100%p"
        android:toYDelta="0" /></set><!-- R.anim.push_bottom_out 淡出動畫--><?xml version="1.0" encoding="utf-8"?><set xmlns:android="
    <translate
        android:duration="300"
        android:fromYDelta="0"
        android:toYDelta="100%p" /></set><!-- R.anim.push_bottom_silent 原點--><?xml version="1.0" encoding="utf-8"?><translate xmlns:android="
    android:duration="300"
    android:fromYDelta="0"
    android:toYDelta="0" />
    <!-- 底部彈框-->startActivity(intent);overridePendingTransition(R.anim.push_bottom_in,R.anim.push_bottom_silent);<!-- 關閉底部彈框-->finish();overridePendingTransition(R.anim.push_bottom_silent,R.anim.push_bottom_out);<!-- 實現透明狀態列-->setContentView(R.layout.activity_dialog_pay_custom);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    getWindow().setStatusBarColor(Color.TRANSPARENT);
    }

微信支付

流程
相親原始碼中移動支付的實現,沒有想象中那麼難
沒錯,這就是官方的業務流程圖,有點糊的感覺,下面我以相親原始碼客戶端開發為主,簡化一下流程:
  • 相親原始碼客戶端選擇購買的商品後,選擇微信支付,介面請求伺服器,伺服器此時需要生成預支付訂單(呼叫微信統一下單介面),其中返回的引數便是我們調起微信支付所需要的引數。(統一下單)
  • 相親原始碼客戶端拿到伺服器返回的預支付訂單引數,通過微信SDK調起微信支付頁面
  • 客戶端收到微信支付的狀態回撥
  • 通過相親原始碼伺服器查詢支付訂單的狀態,注意:以伺服器查詢的結果為準,不要使用微信返回給客戶端的支付狀態作為支付依據。(訂單查詢)
整合
  • 微信開放平臺註冊及配置
相親原始碼中移動支付的實現,沒有想象中那麼難
1.申請相親原始碼獲取微信平臺生成的唯一APPID(管理中心-建立應用) 2.配置簽名,獲取相親原始碼的簽名(簽名工具) 3.配置相親原始碼包名,此處文件太老舊,應該為buile.gradle中的applicationId
  • 註冊APPID
 IWXAPI api = WXAPIFactory.createWXAPI(this, APP_ID);
  • 呼叫SDK發起支付
  /**
     * 微信支付
     *
     * @param payInfo 預支付資訊
     */
    private void wechatPay(final String payInfo) {
        try {
            JSONObject json = new JSONObject(payInfo);
            if (!json.has("retcode")) {
                PayReq req = new PayReq();
                // 測試用appId
                req.appId = APP_ID;//                req.appId = json.getString("appid");
                req.partnerId = json.getString("partnerid");
                req.prepayId = json.getString("prepayid");
                req.nonceStr = json.getString("noncestr");
                req.timeStamp = json.getString("timestamp");
                req.packageValue = json.getString("package");
                req.sign = json.getString("sign");
                req.extData = "app data";
                Toast.makeText(PayDialogActivity.this, "正常調起支付", Toast.LENGTH_SHORT).show();
                // 在支付之前,如果應用沒有註冊到微信,應該先呼叫IWXMsg.registerApp將應用註冊到微信
                api.sendReq(req);
            }
        } catch (JSONException e) {
            e.printStackTrace();
            showToast(this, "異常:" + e.getMessage());
        }
    }
  • 微信回撥介面
1.目錄結構配置,需要在包名下新建wxapi目錄,並增加回撥介面WXPayEntryActivity,如下圖:
相親原始碼中移動支付的實現,沒有想象中那麼難
2.回撥介面示例
/**
 * @author hule
 * @date 2019/7/29 15:58
 * description: 微信支付回撥
 */
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
    private IWXAPI api;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //此處如果需要顯示介面需要設定setContentView();
        //一般情況下會都不會去設定介面,拿到回撥後直接關閉介面,傳送通知處理
        api = WXAPIFactory.createWXAPI(this, PayDialogActivity.APP_ID);
        api.handleIntent(getIntent(), this);
    }
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }
    @Override
    public void onReq(BaseReq req) {
    }
    @Override
    public void onResp(BaseResp resp) {
        if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            //通知我們回撥,我們拿來查詢訂單的狀態
            EventBus.getDefault().post(new WXPayEntryEntity(resp.errCode));
        }
        // 清除動畫,有助於防止黑屏閃爍
        overridePendingTransition(0, 0);
        finish();
    }
}
3.回撥頁面配置
 <!--解決微信支付回撥部分機型黑屏閃爍的問題-->
    <style name="wxPayTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item>
    </style>
 
    <!--回撥頁面WXPayEntryActivity關閉finish的時候增加-->
     overridePendingTransition(0, 0);
 <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:configChanges="orientation|screenSize"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/wxPayTheme"
            android:windowSoftInputMode="adjustPan|stateAlwaysHidden" />
  • 查詢訂單支付結果,並提示給使用者
  @Subscribe(threadMode = ThreadMode.MAIN)
    public void payment(WXPayEntryEntity wxPayEntryEntity) {
        //TODO 當客戶端收到微信支付成功的回撥後,繼續向後臺伺服器進行驗證為最終的結果
        // .......此處省略呼叫伺服器介面,查詢結果邏輯......
        // 此處以下程式碼只是作為測試使用,這裡需要去伺服器非同步查詢結果
        switch (wxPayEntryEntity.getPayStatus()) {
            case BaseResp.ErrCode.ERR_OK:
                showToast(this, "支付成功");
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                showToast(this, "微信授權失敗");
                break;
            case BaseResp.ErrCode.ERR_COMM:
                showToast(this, "訂單支付失敗!");
                break;
            case BaseResp.ErrCode.ERR_SENT_FAILED:
                showToast(this, "微信傳送失敗");
                break;
            case BaseResp.ErrCode.ERR_UNSUPPORT:
                showToast(this, "微信不支援");
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                showToast(this, "使用者點選取消並返回");
                break;
            default:
                showToast(this, "訂單支付失敗!");
                break;
        }
    }
  • 混淆配置
# 微信混淆
-keep class com.tencent.mm.opensdk.** { *; }
-keep class com.tencent.wxop.** { *; }
-keep class com.tencent.mm.sdk.** { *; }

支付寶支付

流程
相親原始碼中移動支付的實現,沒有想象中那麼難

其實流程和微信差不多,對於相親原始碼只需要簡單的幾個流程就能完成支付寶支付
  • 下單後,選擇支付寶支付,相親原始碼客戶端向伺服器傳送請求,伺服器產生預支付訂單,並返回給客戶端
  • 客戶端拿到預支付訂單的相關引數,通過支付寶SDK喚起支付
  • 相親原始碼客戶端拿到支付寶返回的支付結果,向商戶後臺伺服器查詢最終的訂單完成資訊。
整合
  • 相親原始碼接入支付寶SDK
1.下載SDK 2.將alipaySdk-15.6.5-20190718211148.aar複製到libs目錄下 3.工程目錄的build.gradle新增
allprojects {
    repositories {
        // 支付寶 SDK AAR 包所需的配置
        flatDir {
            dirs 'libs'
        }
        google()
        jcenter()
    }}
4.Module專案的build.gradle增加依賴
// 支付寶 SDK AAR 包所需的配置
implementation (name: 'alipaySdk-15.6.5-20190718211148', ext: 'aar')
  • 新增許可權
 <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" />
  • 呼叫支付
  /**
     * 支付寶支付
     *
     * @param payInfo 預支付資訊
     */
    private void aliPay(final String payInfo) {
        // 1.去伺服器拿支付訂單
        final Runnable payRunnable = new Runnable() {
            @Override            public void run() {
                PayTask aliPay = new PayTask(PayDialogActivity.this);
                Map<String, String> result = aliPay.payV2(payInfo, true);
                Log.d(TAG, result.toString());
                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                payHandler.sendMessage(msg);
            }
        };
        // 必須非同步呼叫
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }
  • 支付寶回撥
/**
     * 支付寶回撥
     */
    static class PayHandler extends Handler {
        private final WeakReference<PayDialogActivity> payDialogActivityWrf;
        private PayHandler(PayDialogActivity payDialogActivityWrf) {
            this.payDialogActivityWrf = new WeakReference<>(payDialogActivityWrf);
        }
        @Override        public void handleMessage(Message msg) {
            if (SDK_PAY_FLAG == msg.what) {
                @SuppressWarnings("unchecked")
                PayResult payResult = new PayResult((Map<String, String>) msg.obj);
                //對於支付結果,請商戶依賴服務端的非同步通知結果。同步通知結果,僅作為支付結束的通知。
                String resultStatus = payResult.getResultStatus();
                // 判斷resultStatus 為9000則代表支付成功
                if (TextUtils.equals(resultStatus, CODE_9000)) {
                    // TODO 該筆訂單是否真實支付成功,需要依賴[服務端的非同步通知]。
                    // 該筆訂單是否真實支付成功,需要依賴服務端的非同步通知。
                    if (payDialogActivityWrf.get() != null) {
                        payDialogActivityWrf.get().showAlert(payDialogActivityWrf.get(), "支付成功!");
                    }
                } else {
                    // TODO 該筆訂單是否真實支付成功,需要依賴[服務端的非同步通知]。
                    if (payDialogActivityWrf.get() != null) {
                        payDialogActivityWrf.get().showAlert(payDialogActivityWrf.get(), "支付失敗!");
                    }
                }
            }
        }
    }
  • 關於混淆
由於新版的支付寶SDK採用的是aar替換了原來舊版的jar包,預設aar中已經幫你做出了混淆,故新版的支付寶無需手動混淆 ,以下是aar中解壓出來的混淆說明
# 這個 ProGuard 檔案被指定為 consumerProguardFiles。
# 如此一來,AAR 包的使用者在其應用進行 ProGuard 混淆時,將自動附加下列規則,
# 省去了接入 JAR 時手動在 ProGuard 規則檔案中加入支付寶 SDK 規則的步驟。
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.alipay.sdk.app.H5PayCallback {
    <fields>;
    <methods>;
}
-keep class com.alipay.android.phone.mrpc.core.** { *; }
-keep class com.alipay.apmobilesecuritysdk.** { *; }
-keep class com.alipay.mobile.framework.service.annotation.** { *; }
-keep class com.alipay.mobilesecuritysdk.face.** { *; }
-keep class com.alipay.tscenter.biz.rpc.** { *; }
-keep class org.json.alipay.** { *; }
-keep class com.alipay.tscenter.** { *; }
-keep class com.ta.utdid2.** { *;}
-keep class com.ut.device.** { *;}
# SDK 包可能不包含 utdid
-dontwarn com.ta.utdid2.**
-dontwarn com.ut.device.**
# SDK 包可能不包含 securitysdk
-dontwarn com.alipay.mobilesecuritysdk.**

總結

關於相親原始碼實現移動支付大概就是這麼多了,總而言之,對於移動支付,相親原始碼客戶端流程只需要做到以下幾點就能完成支付:
  • 商戶伺服器產生預支付訂單
  • 相親原始碼客戶端通過預訂單引數呼叫支付SDK客戶端
  • 拿到支付客戶端返回的訂單資訊並以商戶後臺伺服器查詢的訂單為最終結果
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2841355/,如需轉載,請註明出處,否則將追究法律責任。

相關文章