Android 微信支付用广播来封装回调

395 阅读4分钟
微信支付的回调 一般的做法有:

1、用单例类解决/静态函数

  • 需要注意回收
  • 如果有多个地方有支付,需要维护多个回调

2、Eventbus (这个比较常用)

  • 需要注册和接触注册
  • 支付的页面在有叠加的情况下
  • 如果需要准确的回调到对应的页面,那么需要每个页面都要做订单id判断

3、系统广播

  • 需要注册和解除注册

  • 用订单号来发广播不需要维护多个回调

  • 系统广播 + Lifecycle 封装后, 不需要每个页面都去注册和解除注册

  • WXPayEntryActivity 中的代码:

 @Override
    public void onResp(BaseResp resp) {
        AppPayHelper.sendWeiXinPayResp(this, resp);
        finish();
    }
  • 使用的时候代码:
    AppPayHelper.get(this).setCallback(object : AppPayHelper.OnPayCallback() {
        override fun onSuccess(prepayId: String) {
            loadingDialog.dismiss()
            finish()
        }

        override fun onCancel(prepayId: String) {
            loadingDialog.dismiss()
            ToastUtil.show("支付已取消")
        }

        override fun onError(prepayId: String, throwable: Throwable) {
            loadingDialog.dismiss()
            ToastUtil.show(throwable.message.toDefault(""))
        }

    }).onWeiXinPay(WeiXinUtil.WEIXIN_APP_ID, dto.noncestr, dto.partnerid, dto.prepayid, dto.pck, dto.timestamp, dto.sign)
  • 封装代码:
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.tencent.mm.opensdk.constants.ConstantsAPI
import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.modelpay.PayResp

/**
 * 微信支付 帮助类
 */
object WxPayHelper {
    /**
     * 微信返回的参数 支付实体
     */
    private const val WX_PAY_RESP = "wx_pay_resp"

    private const val BROADCAST_PAY = "WxPayHelper"

    /**
     * 微信支付成功,通过发广播来回调给 发起支付的页面
     */
    @JvmStatic
    fun sendWeiXinPayResp(context: Context?, resp: BaseResp?) {
        context ?: return
        resp ?: return
        //这里只处理微信支付的回调
        if (resp.type != ConstantsAPI.COMMAND_PAY_BY_WX) {
            return
        }
        //将微信的baseResp 转成 payResp 能拿到 预订单id,
        //通过预订单id 发送对应的广播,保证发起支付对象的 预订单id,和 支付结果的 预订单id一致
        val payResp = (resp as? PayResp)
        //toDefault 使用来判空的
        val intent = Intent(BROADCAST_PAY + payResp?.prepayId.toDefault(""))
        //转成json 字符串 来发送
        intent.putExtra(WX_PAY_RESP, payResp.toJsonString())
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
    }

    @JvmStatic
    fun get(activity: AppCompatActivity): WxPayRequestHelper {
        val helper = WxPayRequestHelper(activity)
        activity.lifecycle.addObserver(helper)
        return helper
    }

    @JvmStatic
    fun get(fragment: Fragment): WxPayRequestHelper {
        val helper = WxPayRequestHelper(fragment.context)
        fragment.lifecycle.addObserver(helper)
        return helper
    }

    @JvmStatic
    fun get(owner: LifecycleOwner, context: Context): WxPayRequestHelper {
        val helper = WxPayRequestHelper(context)
        owner.lifecycle.addObserver(helper)
        return helper
    }


    class WxPayRequestHelper(private val context: Context?) : LifecycleEventObserver {

        /**
         *  支付回调
         */
        private var mPayCallback: OnWxPayCallback? = null

        /**
         * 广播通知
         */
        private var mBroadcastReceiver: BroadcastReceiver? = null


        private val mLocalBroadcastManager by lazy { context?.let { LocalBroadcastManager.getInstance(it) } }


        /**
         * 正在执行支付的 订单id/预订单号 /支付交易会话ID
         */
        private var mPrepayId: String? = null

        /**
         * 生命周期发送变化时
         */
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                mBroadcastReceiver?.let {
                    mLocalBroadcastManager?.unregisterReceiver(it)
                }
                mBroadcastReceiver = null
                mPayCallback = null
            }
        }

        /**
         * 注册广播
         */
        private fun onRegisterBroadcast() {
            if (mBroadcastReceiver != null) {
                return
            }
            mBroadcastReceiver = object : BroadcastReceiver() {
                override fun onReceive(context: Context?, intent: Intent?) {
                    if (intent == null) {
                        mPayCallback?.onError(mPrepayId.toDefault(""), "-1", Throwable("未返回支付结果"))
                        return
                    }
                    val payResp = intent.getStringExtra(WX_PAY_RESP).stringToObj<PayResp>()
                    if (payResp == null) {
                        mPayCallback?.onError(mPrepayId.toDefault(""), "-1", Throwable("未返回支付结果"))
                        return
                    }
                    if (mPrepayId == null || payResp.prepayId != mPrepayId) {
                        mPayCallback?.onError(mPrepayId.toDefault(""), "-1", Throwable("订单号错误"))
                        return
                    }
                    //当 请求支付的 订单id 与 支付完成的 订单id一致时才能有回调
                    when (payResp.errCode) {
                        BaseResp.ErrCode.ERR_OK -> mPayCallback?.onSuccess(mPrepayId.toDefault(""))
                        BaseResp.ErrCode.ERR_USER_CANCEL -> mPayCallback?.onCancel(mPrepayId.toDefault(""))
                        else -> mPayCallback?.onError(
                            mPrepayId.toDefault(""),
                            payResp.errCode.toString(),
                            Throwable(String.format("%s,错误码:%d", payResp.errStr.toDefault(""), payResp.errCode))
                        )
                    }
                    //收到广播通知后,及时解出注册
                    mBroadcastReceiver?.let {
                        mLocalBroadcastManager?.unregisterReceiver(it)
                    }
                    mBroadcastReceiver = null
                }
            }
            mBroadcastReceiver?.let { broadcastReceiver ->
                val intentFilter = IntentFilter()
                intentFilter.addAction(BROADCAST_PAY + mPrepayId.toDefault(""))
                mLocalBroadcastManager?.registerReceiver(broadcastReceiver, intentFilter)
            }
        }

        /**
         *  设置回调
         */
        fun setCallback(callback: OnWxPayCallback): WxPayRequestHelper {
            mPayCallback = callback
            return this
        }

        /**
         * 微信支付
         */
        fun onWeiXinPay(wxDto: WxPayRequestData) {
            onWeiXinPay(wxDto.getWxAppId(), wxDto.getWxNonceStr(), wxDto.getWxPartnerId(), wxDto.getWxPrepayId(), wxDto.getWxPck(), wxDto.getWxTimestamp(), wxDto.getWxSign())
        }


        /**
         * 微信支付
         * @param appId 微信开放平台 appId
         * @param nonceStr 随机字符串,随机字符串,不长于32位。推荐随机数生成算法
         * @param partnerId 微信支付分配的商户号
         * @param prepayId 微信返回的支付交易会话ID
         * @param pck 固定值
         * @param timestamp 时间戳,请见接口规则-参数规定
         * @param sign  签名,详见签名生成算法注意:签名方式一定要与统一下单接口使用的一致
         */
        fun onWeiXinPay(appId: String?, nonceStr: String?, partnerId: String?, prepayId: String?, pck: String?, timestamp: String?, sign: String?) {
            if (context == null) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:context不存在"))
                return
            }
            if (appId.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:appId"))
                return
            }
            if (nonceStr.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:nonceStr"))
                return
            }
            if (partnerId.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:partnerId"))
                return
            }
            if (prepayId.isNullOrEmpty()) {
                mPayCallback?.onError("", "-1", Throwable("订单生成错误:prepayId"))
                return
            }
            if (pck.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:pck"))
                return
            }
            if (timestamp.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:timestamp"))
                return
            }
            if (sign.isNullOrEmpty()) {
                mPayCallback?.onError(prepayId.toDefault(""), "-1", Throwable("订单生成错误:sign"))
                return
            }
            mPrepayId = prepayId

            //这里的appid,替换成自己的即可
            val wxApi = WXAPIFactory.createWXAPI(context, appId)
            wxApi.registerApp(appId)

            if (!wxApi.isWXAppInstalled) {
                mPayCallback?.onError(prepayId, "-1", Throwable("请先安装微信App"))
                return
            }

            val payRequest = PayReq()
            payRequest.appId = appId
            ////随机字符串,随机字符串,不长于32位。推荐随机数生成算法
            payRequest.nonceStr = nonceStr
            ////微信支付分配的商户号
            payRequest.partnerId = partnerId
            ////微信返回的支付交易会话ID
            payRequest.prepayId = prepayId
            //固定值
            payRequest.packageValue = pck
            //时间戳,请见接口规则-参数规定
            payRequest.timeStamp = timestamp
            //签名,详见签名生成算法注意:签名方式一定要与统一下单接口使用的一致
            payRequest.sign = sign
            //发起请求,调起微信前去支付
            val isSendReq = wxApi.sendReq(payRequest)
            if (!isSendReq) {
                mPayCallback?.onError(prepayId, "-1", Throwable("微信支付请求发送失败"))
            }
            onRegisterBroadcast()
        }

    }

    /**
     * 选择回调
     */
    abstract class OnWxPayCallback(val context: Context?) {
        /**
         * 成功
         * @param prepayId 预定单id/订单id
         */
        abstract fun onSuccess(prepayId: String)

        /**
         * @param prepayId 预定单id/订单id
         */
        open fun onCancel(prepayId: String) {
        }

        /**
         * @param prepayId 预定单id/订单id
         * @param code 错误码
         * @param throwable 错误信息
         */
        open fun onError(prepayId: String, code: String, throwable: Throwable) {
        }

    }

    /**
     *  实体类继承这个 可以直接使用
     */
    interface WxPayRequestData {
        fun getWxAppId(): String?
        fun getWxNonceStr(): String?
        fun getWxPartnerId(): String?
        fun getWxPrepayId(): String?
        fun getWxPck(): String?
        fun getWxTimestamp(): String?
        fun getWxSign(): String?
    }
}