android 微信授权、分享、支付之坑——纪念那踩不完的坑

微信分享的demo更新了,貌似没有以前坑了,最好先把demo改一下再打开。

1.无用的文件删掉否则会报错:Error:Unknown host 'android.oa.com'. You may need to adjust the proxy settings in Gradle,只保留4个:整个app目录、build.gradle、debug.keystore、settings.gradle

2.sdk版本,build tools版本适配版本等

 

微信支付生成签名什么的最好后台计算,不然别人破解包就gg了。

 

上面的坑有踩过的请分享至下方谢谢,本人用的友盟所以就没去踩了。

 

坑一:分享或支付必须创建指定Activity的坑,这个坑微信是不会告诉你的。

分享或支付时必须在项目目录下创建wxapi>WXEntryActivity或者WXPayEntryActivity,并且必须实现IWXAPIEventHandler接口。这样还会引发耦合性较高的问题,其他界面的分享或支付逻辑不一样的情况下会出现如下代码:

    public static int AAA = 0;
    @Override
    public void onResp(BaseResp resp) {
        switch (AAA){
            case 1:
                //a界面
                break;
            case 2:
                //b界面
                break;
            case 3:
                //c界面
                break;
            //...n界面
            default:
                break;
        }
    }

然后动态改AAA的值,这样Activity不仅杂乱难堪,还难以维护,如果注释不够清晰,这里的代码等同于天书。建议这样修改

    private static OnWXListener mListener = null;
    private static WeakReference mActivity = null;
    public static final int DEFAULT_WXTIME = 300;
    private static int mTime = DEFAULT_WXTIME;
    private static OnCancelClickListener mTimeListener = null;

    @Override
    public void onReq(BaseReq req) {
        if (mListener != null) {
            mListener.onReq(req);
            mListener = null;
        }
        finish();
    }

    @Override
    public void finish() {
        api.detach();//终于找到了,去除wx内存泄漏的方法(微信:“有问题去看源码”)
        super.finish();
    }

    @Override
    public void onResp(BaseResp resp) {
        if (mListener != null) {
            mListener.onResp(resp);
            mListener = null;
        }
        finish();
    }

    public static void setResultListener(Activity activity, WXEntryActivity.OnWXListener listener) {
        if (mListener != null) {
            mListener.onError(WXEntryActivity.OnWXListener.TYPE_REPLACE, "支付变更!", null);
        }
        mActivity = new WeakReference<>(activity);
        mListener = listener;
        if (mTimeListener == null) {
            mTimeListener = new OnCancelClickListener() {
                @Override
                public void clickCancel(Void aVoid) {
                    mTime--;
                    Activity ac = mActivity.get();
                    if (ac == null || ac.isFinishing()) {
                        clear();
                    }
                    if (mTime < 0) {
                        if (mListener != null) {
                            mListener.onError(WXEntryActivity.OnWXListener.TYPE_TIMEOUT, "支付超时!", null);
                        }
                        clear();
                    }
                }

                void clear() {
                    TimeUtil.removeTimeListener(this);//取消回调
                    mActivity = null;
                    mListener = null;
                    mTime = WXEntryActivity.DEFAULT_WXTIME;
                }
            };
        }
        mTime = WXEntryActivity.DEFAULT_WXTIME;
        TimeUtil.addTimeListener(mTimeListener);//这个只是1秒回调一次的handler
    }
    /**
     * 把微信支付解耦,只需要调这个方法即可
     */
    public static void WXPay(Activity activity, WXCode wc/*后台返回的支付数据*/, OnWXListener listener) {
        setResultListener(activity, listener);
        //传Application对分身不太友好...找半天才发现有detach方法
        IWXAPI api = WXAPIFactory.createWXAPI(activity, wc.appid);//finish时加上detach方法,这样就不会内存泄漏了
        api.registerApp(wc.appid);
        if (!api.isWXAppInstalled()) {
            Utils.toast("您可能没有安装微信!");
        }
        PayReq request = new PayReq();
        request.appId = wc.appid;
        request.partnerId = wc.mch_id;
        request.prepayId = wc.prepay_id;
        request.packageValue = "Sign=WXPay";//随机码,如果想要安全,可以生成一个
        request.nonceStr = wc.nonce_str;
        request.timeStamp = String.valueOf(wc.timestamp);
        request.sign = wc.paySign;
        api.sendReq(request);
    }

    public static abstract class OnWXListener {
        //错误类型:请求超时;没有回调并被新的分享或支付替换;微信的错误
        public static final int TYPE_TIMEOUT = 0, TYPE_REPLACE = 1, TYPE_WX = 2;

        @IntDef({TYPE_TIMEOUT, TYPE_REPLACE, TYPE_WX})
        @Retention(RetentionPolicy.SOURCE)
        public @interface type {
        }//该变量只能传入上面几种,否则会报错

        //微信主动调app
        public void onReq(BaseReq req) {
        }

        /**
         * app调授权支付等,此处对resp进行了判断,分别拆分到了{@link #onWXSuccess}{@link #onError}
         */
        public void onResp(BaseResp resp) {
            switch (resp.errCode) {
                case BaseResp.ErrCode.ERR_OK:
                    onWXSuccess(resp);
                    break;
                case BaseResp.ErrCode.ERR_COMM:
                    onError(TYPE_WX, "通信失败!", resp);
                    break;
                case BaseResp.ErrCode.ERR_USER_CANCEL:
                    onError(TYPE_WX, "取消支付!", resp);
                    break;
                case BaseResp.ErrCode.ERR_SENT_FAILED:
                    onError(TYPE_WX, "发送失败!", resp);
                    break;
                case BaseResp.ErrCode.ERR_AUTH_DENIED:
                    onError(TYPE_WX, "身份验证失败!", resp);
                    break;
                case BaseResp.ErrCode.ERR_UNSUPPORT:
                    onError(TYPE_WX, "暂不支持此方式!", resp);
                    break;
                case BaseResp.ErrCode.ERR_BAN:
                    onError(TYPE_WX, "支付被禁止!", resp);
                    break;
                default:
                    onError(TYPE_WX, "其他支付错误!", resp);
                    break;
            }
        }

        public abstract void onWXSuccess(BaseResp resp);

        /**
         * @param errType  错误类型:超时、替换、微信错误
         * @param errorMsg 错误原因
         * @param resp     当微信返回错误的时候不是null
         */
        public abstract void onError(@type int errType, String errorMsg, @Nullable BaseResp resp);
    }

这是WXPayEntryActivity的例子,只要调用WXPayEntryActivity.WXPay方法,传入指定参数和回调即可,分享也可以参考参考

这样使用起来就非常的方便了,如下:

        WXPayEntryActivity.WXPay(this, wc, new WXEntryActivity.OnWXListener() {
            @Override
            public void onWXSuccess(BaseResp resp) {
                Utils.toast("支付成功");
            }

            @Override
            public void onError(int errType, String errorMsg, @Nullable BaseResp resp) {
                Utils.toast(errorMsg);
            }
        });

demo见GitHub:https://github.com/weimingjue/WXEntry

坑二:支付成功然后一直失败的问,微信也不会告诉你的

当你根据微信传说中的demo集成后,拉起支付,哇塞一次性拉起成功好开森,然后高高兴兴的发给测试。2分钟后测试反馈,支付不了,然后你再试发现怎么都是通信失败,一脸懵逼...。

原因很简单:没配置对,请检查你的微信开放平台的配置。

为什么第一次能成功?因为比较坑呗(猜测依然是缓存问题,第一次拉起支付并没有缓存,微信就当做成功来支付,第二次有了缓存,微信发现你app的key包名什么的不对,于是就直接抛出了个异常来了)

坑三:开放平台的签名问题,微信:我不说,我就是不说

签名是个深坑,请多次确认你的签名格式正确,正确格式:MD5并且没有冒号(没有冒号!没有冒号!),不区分大小写。

如果签名写的是SHA1,那么恭喜你重填;

如果直接copy签名算出来的MD5值,那么恭喜你,算出来的基本都带冒号;

如果已经确认内容正确,那么请往下看。

 

坑四:微信缓存之巨坑,微信更不可能告诉你了。

如果你的签名或包名写错了,并且修改完全正确后仍然不能授权或者支付一次之后总是提示通信失败,那么恭喜入坑。

原因:你改的数据确实立即保存到微信服务器端了,但是微信app端会在第一次授权时会把签名缓存到本地,这个手机第一次授权得到了错误的签名,后面再授权都是一样。

解决方式大致以下几种:1.退出登录再重新登录;2.清除微信缓存(不是清除数据);3.如果以上两种都不行,清除数据或者卸载重装(用户操作后不知道会不会想念妖妖灵?);4.听天由命,等待微信的缓存刷新(一天内一般会刷新)

坑五:深渊巨坑

如果确保你的对接完全正确并支付成功了,但却怎么也收不到微信的跳转回调,那么恭喜你掉进了史上最坑爹的api天坑。

先说一下微信/支付的原理(准备好储血袋):参数>startActivity跳转到微信指定界面>微信界面分享/支付完成>startActivity跳转到WXEntryActivity/WXPayEntryActivity...多好的API啊思路简单清晰(坑)明了暴力(爹)?

如果你的applicationId和你的包路径不一致(可能是多项目的原因吧),比如com.wang.application和com.wang.package,而微信调用getPackageName()时得到的是com.wang.application(此处不再多说为什么,自己bd),跳回来的Activity就是com.wang.application.wxapi.WXEntryActivity,和你的Activity完全对不上,当然不可能回调回来了。

此问题有3种解决方案:1.重命名你的包路径(多项目不可行)

2.在创建和你applicationId一致的文件夹来放WXEntryActivity(一两个还比较好解决)

3.使用gradle或apt自动生成对应路径下的Activity(最好的解决方案,但是...?)

你可能感兴趣的:(android教程)