純手工打造Easy支付庫

純手工打造Easy支付庫

前言

接觸微信支付的開發者都知道,微信支付的所有處理都是在WXPayEntryActivity類裏面,按一般開發流程走的話,我們在訂單頁面發起PayReq支付,微信調起支付頁面,支付的結果處理會調用WXPayEntryActivity的onResp方法,根據BaseResp返回的結果碼來判斷當前的支付結果,整個思路是沒錯的,關鍵是有一點,WXPayEntryActivity是一個Activity,雖然我拿到了結果,但是我怎麼將這個結果帶到我的訂單頁面呢,因爲我的訂單在支付成功後是要跳到訂單完成頁面,有一個笨辦法是,直接在WXPayEntryActivity裏面跳轉訂單完成頁面,但是,如果業務有10個不同的訂單完成頁面,那這樣處理肯定是不行,那就想第二個辦法,一下就想到了,我們可以在每次支付的時候,提前存儲一個標記值,然後在WXPayEntryActivity裏面根據這個標記值來判斷跳轉不同的訂單完成頁面,大功告成,這時候,產品來了說,你這訂單完成頁面就顯示個訂單完成,我需要你顯示用戶支付訂單的所有信息,這時候,之前的辦法就gg了,因爲在WXPayEntryActivity的結果處理裏面,我只能拿到微信的結果,但拿不到訂單的信息,那隻能再想一個辦法了,這一下又想到了,用EventBus,我們可以在訂單頁面進行註冊EventBus,然後訂閱一個支付結果處理的方法,我們在支付完成的時候用Eventbus post到訂單頁面來,因爲訂單信息在訂單頁面,這時候支付結果和訂單信息都有了,那我們可以直接在訂單頁面的訂閱方法裏面處理跳轉了,但是,還是有缺點,每次增加訂單頁我都需要在WXPayEntryActivity類裏面增加判斷和post,感覺有點違背封裝。

這麼多的思路都是筆者一路踩着坑過來的,雖然都能實現業務,但是代碼結構一團糟,就區區支付這方面就動用了一個庫,實在是有點浪費,難道就沒有一種不用庫, 支付又簡單,結果處理也簡單的辦法嗎,苦思冥想,終於打造了這款Easy庫

知識儲備

在瞭解Easy庫的時候,我們首先來認識一個類“ResultReceiver”,來看看官網的解釋:第一句就告訴了我們,他是專門接收回調處理結果的一個接口,關鍵的一點是他實現了Parcelable接口,這也就意味着他能在Intent組件間任意行走

那這個類怎麼用呢?我先寫個簡單點的代碼

/**
 * A類
 */
public class A extends Activity {

    public static final int RESULT_REQUEST_CODE = 0x9429;
    ResultBackData backData;
    TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        backData = new ResultBackData();
        textView = new TextView(this);
    }

    public void onClick(View v) {
        Intent intent = new Intent(this, B.class);
        intent.putExtra("resultReceiver", backData);
    }

    class ResultBackData extends ResultReceiver {

        public ResultBackData() {
            super(null);
        }

        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            if (resultCode == RESULT_REQUEST_CODE) {
                String result = resultData.getString("result");
                textView.setText(result);
            }
        }
    }
}
/**
 *   B類
 */
public class B extends Activity {
    ResultReceiver receiver;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        receiver = getIntent().getParcelableExtra("resultReceiver");
    }

    public void onClick(View v){
        Bundle b=new Bundle();
        b.putString("result","我是B處理的數據,帶給你A來了");
        receiver.send(A.RESULT_REQUEST_CODE,b);
    }
}

從這段簡短的代碼中可以看到,繼承ResultReceiver的ResultBackData類,就好比一箇中間件,實現了A與B的數據傳輸,傳輸最主要的兩個點是實現ResultReceiver的onReceiveResult方法來處理接收,通過ResultReceiver的send實現發送數據,兩個毫不相干的Activity由於一個ResultReceiver實現了數據返回,這時候我們可以思考,A類就好比我們的訂單類,B類就好比微信的WXPayEntryActivity類,我們完全可以通過ResultReceiver這個紐帶從訂單類中將ResultReceiver實例傳輸給WXPayEntryActivity類,待結果處理結束後通過ResultReceiver的send方法返回給訂單類,訂單類去判斷接下來的處理,這完全可以擯棄Eventbus帶來的臃腫,有了想法那就開始幹。

思路實現

上面的ResultReceiver示例代碼是寫在Avtivity裏面的,如果有10個訂單支付頁面,難道我還要寫10個ResultReceiver?這未免有點太臃腫,讓程序員去幹重複性的代碼,那還不如讓去打醜豆,在實施前我們先畫一個思維圖

畫好了思維圖,對整個結構一目瞭然,看看我們的訂單頁,是多麼的清晰,即使來幾百個訂單頁,我們的支付處理也只需要注重發起和接收,然後來看看代碼的實現。

代碼實現

訂單頁處理

在開始講解前,我把最終的效果先貼出來,然後跟着結果一步步去解說

      PayWeixin pay=new PayWeixin();
      pay.setAppid("")
      pay.setNoncestr("")
      pay.setOrdercode("")
      pay.setPackag("")
      pay.setPrepayid("")
      pay.setSign("")
      pay.setTimestamp("")
 EasyPayShare.getInstance().doPayWx(this, pay, new ShareCallBack() {
            @Override
            public void onSuccess(String result) {
                Toast.makeText(PayActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onCanceled(String result) {
                Toast.makeText(PayActivity.this, "支付取消", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailed(String result) {
                Toast.makeText(PayActivity.this, "支付失敗", Toast.LENGTH_SHORT).show();
            }
        });

初始化微信

寫一個管理類EasyPayShare,專門處理微信的初始化和支付(因爲該庫還有支付寶支付、微信分享和微信登錄,該文章就拿一個點來講,其他思路都是一樣實現),

public class EasyPayShare {

private static IWXAPI wxApi;


    private EasyPayShare() {
    }

    private static class InnerClass {
        static EasyPayShare Instance = new EasyPayShare();
    }

    public static EasyPayShare getInstance() {
        return InnerClass.Instance;
    }

    public void registWeixin(Context context, @NonNull String appId) {
        wxApi = WXAPIFactory.createWXAPI(context, appId, true);
        wxApi.registerApp(appId);
    }


    public IWXAPI getWxApi() {
        return wxApi;
    }
    /**
     * 
     * @param context  上下文
     * @param payWeixin  預支付訂單
     * @param callBack  回調的引用
     */
  public void doPayWx(Context context,PayWeixin.JsonDataBean payWeixin, ShareCallBack callBack) {
        IWeixin share = new WxShare(context);
        share.pay(payWeixin, callBack);
    }
}

我們只需要在Application裏面去初始化

    @Override
    public void onCreate() {
        super.onCreate();
    EasyPayShare.getInstance().registWeixin(this, "微信AppId");
    }

回調的接口

該接口是訂單頁與ReceiverResult通訊的紐帶,因爲支付的結果只有三種,所以我們定義了三個方法

/**
 * @author wangqi
 * @since 2017/11/15 18:16
 */

public interface ShareCallBack {
    void onSuccess(String result);

    void onCanceled(String result);

    void onFailed(String result);
}

ResultReceiver的處理

EasyPayShare的doPayWx方法裏面調用了WxShare的pay方法,將預支付訂單和ResultReceiver通過Intent傳遞給WxPayEntryActivity類,onReceiveResult接收處理後的結果,通過不同的requestCode來區分支付是失敗還是取消還是成功

/**
 * @author wangqi
 * @since 2017/11/15 18:14
 */

public class WxShare extends ResultReceiver implements IWeixin {



    public static final String KEY_SHARE_LISTENER = "key_share_listener";



    public static final String KEY_PAY = "key_pay";


    private WeakReference<Context> contextWeakRef;
    private ShareCallBack callback;


    public WxShare(Context context) {
        super(null);
        contextWeakRef = new WeakReference<>(context);
    }
    @Override
    public void pay(PayWeixin.JsonDataBean payWeixin, ShareCallBack callback) {
        this.callback = callback;
        Context context = contextWeakRef.get();//
        if (context != null) {//
            context.startActivity(new Intent(context, WXPayEntryActivity.class)
                    .putExtra(KEY_SHARE_LISTENER, this)
                    .putExtra(KEY_PAY, payWeixin)
            );
        }
    }


    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {
        String result;
        if (resultData == null) {
            result = "null";
        } else {
            result = resultData.getString("result", "null");
        }
        if (resultCode == IWeixin.RESULT_SUCCESS) {
            if (callback != null) {
                callback.onSuccess(result);
            }
        } else if (resultCode == IWeixin.RESULT_CANCELD) {
            if (callback != null) {
                callback.onCanceled(result);
            }
        } else {
            if (callback != null) {
                callback.onFailed(result);
            }
        }
    }
}

WxPayEntryActivity頁面的處理

整個WxPayEntryActivity頁面十分的簡單,拿到預支付訂單支付,然後通過ResultReceiver把結果返回,這個地方我讓WxPayEntryActivity去繼承了EasyWxPayEntryActivity,這樣,開發者在使用該庫的時候,只需要在特定的包名位置繼承EasyWxPayEntryActivity就行了


/**
 * @author wangqi
 * @since 2017/11/18 15:25
 */

public class EasyWxPayEntryActivity extends Activity implements IWXAPIEventHandler {
    Bundle bundle;
    ResultReceiver listener;
    PayWeixin payWeixin;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EasyPayShare.getInstance().getWxApi().handleIntent(getIntent(), this);
        // 判斷是否安裝了微信客戶端
        if (!EasyPayShare.getInstance().getWxApi().isWXAppInstalled()) {
            Toast.makeText(this, "您還未安裝微信客戶端!", Toast.LENGTH_SHORT).show();
            finish();
        }
        bundle = getIntent().getExtras();
        listener = bundle.getParcelable(WxShare.KEY_SHARE_LISTENER);
        payWeixin = (PayWeixin) bundle.getSerializable(WxShare.KEY_PAY);

        pay();
    }


    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        EasyPayShare.getInstance().getWxApi().handleIntent(intent, this);
    }


    private void pay() {
        PayReq req = new PayReq();
        req.appId = payWeixin.getAppid();
        req.partnerId = payWeixin.getPartnerid();
        req.prepayId = payWeixin.getPrepayid();
        req.packageValue = payWeixin.getPackag();
        req.nonceStr = payWeixin.getNoncestr();
        req.timeStamp = payWeixin.getTimestamp();
        req.sign = payWeixin.getSign();
        EasyPayShare.getInstance().getWxApi().sendReq(req);
    }


    @Override
    public void onReq(BaseReq baseReq) {
    }

    @Override
    public void onResp(BaseResp resp) {
        switch (resp.errCode) {
            case BaseResp.ErrCode.ERR_OK:
                listener.send(IWeixin.RESULT_SUCCESS, bundle);
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                listener.send(IWeixin.RESULT_CANCELD, bundle);
                break;
            default:
                listener.send(IWeixin.RESULT_FAIL, bundle);
                break;
        }
        finish();
    }
}

結果返回

支付的結果通過ResultReceiver send到WxShare頁面的onReceiveResult頁面,通過requestCode來區分不同的結果,然後將訂單頁傳遞過來的ShareCallBack回調給訂單頁,整個思路的處理非常的簡單和Easy化

總結

代碼量下來並不多,總之,一個好的思路會給開發帶來很多的方便。多說一句,平時在使用框架的時候不能只專注使用,我們要多關注關注框架內部的實現,也就是看源碼,一個好的思路能給開發者帶來很大的啓發
源碼:https://github.com/MRwangqi/EasyPayShare

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章