纯手工打造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

原文发布于微信公众号 - codelang(codelang)

原文发表时间:2017-11-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Web 开发

如何把捏前端模板颗粒度

今晚看到一篇博文,其原文是讲AngularJS的模板的,但觉得该作者讲的很多思路,不仅仅是AngularJS适用。凡是想在前端进行模板组织的,都可借鉴,故写下读...

610
来自专栏Java3y

图书管理系统【总结】

感想 该项目是目前为止,我写过代码量最多的项目了.....虽然清楚是没有含金量的【跟着视频来写的】,但感觉自己也在进步中...... 写的过程中,出了不少的问题...

3465
来自专栏Android 开发者

开发者也是用户 - 第二部分:改善 UI 和 API 可用性的五条指导原则

1333
来自专栏视频咖

如何写出一手好的小程序代码,从架构说起

? 作为微信小程序底层 API 维护者之一,经历了风风雨雨、各种各样的吐槽。为了让大家能更好的写一手小程序,特地梳理一篇文章介绍。如果有什么吐槽的地方,欢迎去...

1432
来自专栏FreeBuf

SQLCipher之攻与防

0×00 SQLCipher 在移动端,不管是iOS还是Android,开发人员用的最多的本地数据库非SQlite莫属了。SQLite是一个轻量的、跨平台的、开...

3476
来自专栏FSociety

Python爬取猫眼「碟中谍」全部评论

评论算保存完了,近期会再做一个关于此次数据的可视化分析。另外阿汤哥真心太帅了,全程打肾上腺素,各位还没去看的赶紧~

300
来自专栏xingoo, 一个梦想做发明家的程序员

C++库大全

基础类 1、 Dinkumware C++ Library 参考站点:http://www.dinkumware.com P.J. Plauger编写的高品质...

2046
来自专栏视频咖

从QQ音乐开发,探讨如何利用腾讯云SDK在直播中加入视频动画

看着精彩的德甲赛事,突然裁判一声口哨,球赛断掉了,屏幕开始自动播放“吃麦趣鸡盒,看德甲比赛”的视频广告

1161
来自专栏Crossin的编程教室

用程序帮你炒股

最近在知乎上看到一个问题:如何使用 Python 抓取雪球网页? 雪球是国内一个人气很高的股票财经类网站,上面有个投资组合功能,很多民间股神在上面设定自己的投资...

2937
来自专栏jessetalks

初探领域驱动设计(2)Repository在DDD中的应用

概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体、值类型和领域服务,也稍微讲到了DDD中的分层结构。但这只能算是一个很简单的介绍,并且我们在上篇的末...

3756

扫码关注云+社区