Android微信支付接入

原文地址

前言:本文主要说明如何在Android项目中接入微信支付,介绍微信支付在项目中的配置,分析微信支付数据与其交互流程,分享个人遇到的坑,以帮助有需要的朋友能更快的在项目中进行微信支付的接入。
正文:
1,开发资质申请:
这个过程在本文中不详细介绍,总的来说需要企业资质申请微信支付功能以及微信开发者,最终是为了得到APPID和商户密钥(后面会详讲这个两个值怎么使用)
2,流程总体介绍
微信支付总体结构图:
这里写图片描述
订单信息:简单来讲就是对订单的封装,其中包含了支付金额,支付时间,订单号,签名信息等等订单信息。这些信息在项目中一般是由服务端构建的,交付给APP转发给微信服务器即可。但是实际情况中服务端可能也没有做这个工作,那么订单信息也有可能在APP端合成。所以开发时务必和后端开发人员协商好关于订单信息构造的工作。(订单构造详情见下文)
支付请求:即APP在程序中调用支付SDK将订单信息发送给微信服务器,这个过程在代码中是很简单的,微信封装好了这个请求接口执行一行代码即可调用(详情见下文)
支付结果反馈:微信会在特定回调接口通知支付接口
总体上这就是微信支付的结构,操作上稍微复杂的是订单信息的构造,容易导致出错的微信SDK的配置。那么接下来就具体的一一介绍每个点的实现。
3,下载官方demo
官网SDK以及demo下载地址:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN
官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=1_1
下载完成后将libammsdk.jar导入到项目中,至于官方demo,建议大家看看就好,不要太相信。因为写的是在太烂了(不知道为什么微信这么大个平台,开发的demo是如此的不考虑用户的感受)
4,实现
a,导入jar包
b,在工程包名下根目录新建wxapi包,这个wxapi包的位置一定要是包名根目录,包名也不能错。(这让对包名有强迫症的开发者会很不爽,但是没办法)
这里写图片描述
c,在该包下新建回调类WXPayEntryActivity,该类的名字一定是在wxapi包下,名字也一定是WXPayEntryActivity。因为他是微信回调的接口,如果改变位置或名字,就会导致微信无法将支付结果反馈,从而导致支付失败。
这里写图片描述
(图中WXEntryActivity是用作微信分享或其他功能的,只做微信支付的朋友可以忽略)
d,WXPayEntryActivity的代码实现以及使用说明:
该类是不需要开发者自己调用的,他是在微信支付后SDK为了回调通知APP的接口,SDK内部会调用该Activity,该Activity的界面布局可以自定义的设置。
其具体的回调接口是该类中的onResp函数,在该函数中可判断是否支付成功。

    public class WXPayEntryActivity extends AppCompatActivity implements IWXAPIEventHandler {
     
        private IWXAPI api;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_wxpay_entry);
            api = WXAPIFactory.createWXAPI(this, "wxAPPID");//这里填入自己的微信APPID
            api.handleIntent(getIntent(), this);
        }
     
        @Override
        public void onReq(BaseReq baseReq) {
     
        }
     
        @Override
        public void onResp(BaseResp baseResp) {
            Log.d("coyc", "onPayFinish, errCode = " + baseResp.errCode);
     
            if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
                int errCord = baseResp.errCode;
                if (errCord == 0) {
                    App.getInstance().tos("支付成功!");
                } else {
                    App.getInstance().tos("支付失败");
                }
                //这里接收到了返回的状态码可以进行相应的操作,如果不想在这个页面操作可以把状态码存在本地然后finish掉这个页面,这样就回到了你调起支付的那个页面
                //获取到你刚刚存到本地的状态码进行相应的操作就可以了
                finish();
            }
        }
     
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            setIntent(intent);
            api.handleIntent(intent, this);
        }
    }


e,AndroidManifest.xml配置:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     
            <!-- 微信支付 -->
            <activity
                android:name=".wxapi.WXPayEntryActivity"
                android:exported="true"
                android:launchMode="singleTop">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
     
                    <category android:name="android.intent.category.DEFAULT" />
     
                    <data android:scheme="自己的wxAPPID" />
                </intent-filter>
            </activity>


f,调用支付接口:

    IWXAPI api= WXAPIFactory.createWXAPI(context, "wxAPPID",false);//填写自己的APPID
    api.registerApp("wxAPPID");//填写自己的APPID,注册本身APP
    PayReq req = new PayReq();//PayReq就是订单信息对象
    //给req对象赋值
    req.appId = appid;//APPID
    req.partnerId = partnerid;//    商户号
    req.prepayId = prepayid;//  预付款ID
    req.nonceStr = getRoundString();//随机数
    req.timeStamp = getTimeStamp();//时间戳
    req.packageValue = "Sign=WXPay";//固定值Sign=WXPay
    req.sign = sign;//签名
     
    api.sendReq(req);//将订单信息对象发送给微信服务器,即发送支付请求


那么写到这里,上面的PayReq 对象其实是未被赋值的

            req.appId = appid;//APPID
            req.partnerId = partnerid;//    商户号
            req.prepayId = prepayid;//  预付款ID
            req.nonceStr = getRoundString();//随机数
            req.timeStamp = getTimeStamp();//时间戳
            req.packageValue = "Sign=WXPay";//固定值Sign=WXPay
            req.sign = sign;//签名


而且这7个参数是缺一不可的,如果这些参数都是在服务端生成的,那么在Android开发人员就不用做什么工作了,将服务端给的值给其赋值就好了,那么整个微信支付流程也就做完了(一般来讲也确实是这个样子)。但是有些情况下服务端的同事没有做这些工作,比如说签名工作等等。那么这么这些工作就要在APP本地实现。
下面我给出随机数获取算法,时间戳获取算法,签名算法。

    private String getRoundString() {
     
            Random random = new Random();
     
            return random.nextInt(10000) + "";
        }
     
        private String getTimeStamp() {
            return new Date().getTime() / 10 + "";
        }
        private String getSign() {
            Map<String, String> map = new HashMap<>();
            map.put("appid", req.appId);
            map.put("partnerid", req.partnerId);
            map.put("prepayid", req.prepayId);
            map.put("package", req.packageValue);
            map.put("noncestr", req.nonceStr);
            map.put("timestamp", req.timeStamp);
     
            ArrayList<String> sortList = new ArrayList<>();
            sortList.add("appid");
            sortList.add("partnerid");
            sortList.add("prepayid");
            sortList.add("package");
            sortList.add("noncestr");
            sortList.add("timestamp");
            sort(sortList);
     
            String md5 = "";
            int size = sortList.size();
            for (int k = 0; k < size; k++) {
                if (k == 0) {
                    md5 += sortList.get(k) + "=" + map.get(sortList.get(k));
                } else {
                    md5 += "&" + sortList.get(k) + "=" + map.get(sortList.get(k));
                }
            }
            String stringSignTemp = md5+"&key=商户密钥";//这里填写自己的商户密钥,所以说如果签名工作实在服务端完成的,商户密钥在APP端是用不到的
     
            String sign=MD5.Md5(stringSignTemp).toUpperCase();
     
            return sign;
        }


    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
     
    package com.android.pc.util;
     
    import java.security.MessageDigest;
     
    public class MD5 {
        public MD5() {
        }
     
        public static final String Md5(String s) {
            char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
     
            try {
                byte[] e = s.getBytes("UTF-8");
                MessageDigest mdTemp = MessageDigest.getInstance("MD5");
                mdTemp.update(e);
                byte[] md = mdTemp.digest();
                int j = md.length;
                char[] str = new char[j * 2];
                int k = 0;
     
                for(int i = 0; i < j; ++i) {
                    byte byte0 = md[i];
                    str[k++] = hexDigits[byte0 >>> 4 & 15];
                    str[k++] = hexDigits[byte0 & 15];
                }
     
                return new String(str);
            } catch (Exception var10) {
                return null;
            }
        }
    }


商户号以及预付款ID这个必须是服务端同事给定的值,在APP端是无法代码生成的。
那么整个微信支付的代码工作到这里就结束了。这里我将自己封装的支付类贴出来,仅供参考。

    public class WX_Pay {
     
        public IWXAPI api;
        private PayReq req;
     
        public WX_Pay(Context context) {
     
            api = WXAPIFactory.createWXAPI(context, "wxAPPID",false);
        }
     
        /**
         * 向微信服务器发起的支付请求
         */
        public void pay(String appid,String partnerid,String prepayid) {
     
            req = new PayReq();
     
            req.appId = appid;//APPID
            req.partnerId = partnerid;//    商户号
            req.prepayId = prepayid;//  预付款ID
            req.nonceStr = getRoundString();//随机数
            req.timeStamp = getTimeStamp();//时间戳
            req.packageValue = "Sign=WXPay";//固定值Sign=WXPay
     
            String sign = getSign();
            req.sign = sign;//签名
     
            api.registerApp("wxAPPID");
            api.sendReq(req);
        }
     
        @NonNull
        private String getSign() {
            Map<String, String> map = new HashMap<>();
            map.put("appid", req.appId);
            map.put("partnerid", req.partnerId);
            map.put("prepayid", req.prepayId);
            map.put("package", req.packageValue);
            map.put("noncestr", req.nonceStr);
            map.put("timestamp", req.timeStamp);
     
            ArrayList<String> sortList = new ArrayList<>();
            sortList.add("appid");
            sortList.add("partnerid");
            sortList.add("prepayid");
            sortList.add("package");
            sortList.add("noncestr");
            sortList.add("timestamp");
            sort(sortList);
     
            String md5 = "";
            int size = sortList.size();
            for (int k = 0; k < size; k++) {
                if (k == 0) {
                    md5 += sortList.get(k) + "=" + map.get(sortList.get(k));
                } else {
                    md5 += "&" + sortList.get(k) + "=" + map.get(sortList.get(k));
                }
            }
            String stringSignTemp = md5+"&key=商户密钥";
     
            String sign=MD5.Md5(stringSignTemp).toUpperCase();
     
            return sign;
        }
     
        private String getRoundString() {
     
            Random random = new Random();
     
            return random.nextInt(10000) + "";
        }
     
        private String getTimeStamp() {
            return new Date().getTime() / 10 + "";
        }
     
     
        private static void sort(ArrayList<String> strings) {
            Collections.sort(strings);
        }
    }


那么在APP中这样使用就好

    WX_Pay pay = new WX_Pay(getContext());
    pay.pay(str1,str2,str3);


5,错误小结:本人在开发中遇到过两个错误
a,无法起调微信支付界面:错误原因是没有将WXPayEntryActivity 类放在在wxapi包下。
b,支付失败:错误原因是在签名算法中忘记将商户密钥签名。
这里基本可以总结下错误类型:
1,起调失败:工程配置错误
2,支付订单报错:订单信息错误
c,千万注意微信支付要编译为release版才能通过支付测试
---------------------
作者:孜燃
来源:CSDN
原文:https://blog.csdn.net/qq_15059163/article/details/80562171
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值