• Android微信登录、分享、支付


    转载需要著名出处:

    http://blog.csdn.net/lowprofile_coding/article/details/78004224
    

    之前写过微信登录分享支付第一版:

    http://blog.csdn.net/lowprofile_coding/article/details/48086381
    

    前言

    大部分的app都有接入第三方sdk的需求。例如第三方登录需要接入微信、QQ、微博。第三方支付需要接入微信、支付宝、银联。

    这些我都有使用过,都有使用过他们的sdk,感觉最麻烦的就是微信,不能直接调试,得用正式的签名进行签名才能调试。还有他们官方的demo也是跑不起来的,因为没有签名文件。需要注意的地方也很多。

    代码实现

    微信sdk现在支持Android Studio在线引用了,之前都是添加jar的方法。需要访问微信的接口获取用户信息,所以把我们之前封装的okhttp也一起在线引用。okhttp需要在自定义的Application中初始化这个我就不贴代码了。之前已经讲过很多次。在app/build.gradle文件dependencies标签中加入以下两行代码:

    compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
    compile 'com.ansen.http:okhttpencapsulation:1.0.1'
    

    需要用到网络,所以在AndroidManifest.xml文件中加入网络权限:

    <uses-permission android:name="android.permission.INTERNET" />
    

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp"
        android:orientation="vertical">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="登录之后信息在这里显示"/>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/tv_nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="昵称:"/>
    
            <TextView
                android:id="@+id/tv_age"
                android:layout_below="@+id/tv_nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="年龄:"/>
        </RelativeLayout>
    
        <Button
            android:id="@+id/btn_login"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="微信登录"/>
    
        <Button
            android:id="@+id/btn_share_friend_circle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="分享到朋友圈"/>
    
        <Button
            android:id="@+id/btn_share_friend"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="分享给好友"/>
    
        <Button
            android:id="@+id/btn_pay"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="微信支付"/>
    </LinearLayout>
    

    布局文件很简单,就LinearLayout里面放了几个TextView,跟几个按钮。

    WeiXin.java 用于EventBus来传送消息,微信sdk有个很奇怪的地方,就是不管登录、分享、支付之后都得用一个Activity来接收,所以我们还得从接收的那个activity把结果信息通过EventBus传递给MainActivity。虽然用广播也能实现,但是个人喜欢用EventBus,使用灵活。简单轻量。

    public class WeiXin {
        private int type;//1:登录 2.分享 3:微信支付
        private int errCode;//微信返回的错误码
        private String code;//登录成功才会有的code
    
        public WeiXin() {
        }
    
        public WeiXin(int type,int errCode, String code) {
            this.type = type;
            this.errCode=errCode;
            this.code = code;
        }
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            this.type = type;
        }
    
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public int getErrCode() {
            return errCode;
        }
    
        public void setErrCode(int errCode) {
            this.errCode = errCode;
        }
    }
    

    Constant.java 常量类,微信appid跟secret的值用两个常量保存。为了保护隐私这两个值我已经修改过。

    public class Constant {
        public static String WECHAT_APPID="wxda6db2aec81389af";
        public static String WECHAT_SECRET="8fed5a2d510022587ef8a6194c965be3";
    }
    

    MainActivity.java 全部代码贴出来比较乱,暂时贴出MainActivity部分代码。

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private IWXAPI wxAPI;
        private TextView tvNickname,tvAge;
        public static final int IMAGE_SIZE=32768;//微信分享图片大小限制
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            EventBus.getDefault().register(this);//注册
            wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true);
            wxAPI.registerApp(Constant.WECHAT_APPID);
    
            findViewById(R.id.btn_login).setOnClickListener(this);
            findViewById(R.id.btn_share_friend_circle).setOnClickListener(this);
            findViewById(R.id.btn_share_friend).setOnClickListener(this);
            findViewById(R.id.btn_pay).setOnClickListener(this);
    
            tvNickname= (TextView) findViewById(R.id.tv_nickname);
            tvAge=(TextView) findViewById(R.id.tv_age);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.btn_login://微信登录
                    login();
                    break;
                case R.id.btn_share_friend_circle://微信分享到朋友圈
                    share(true);
                    break;
                case R.id.btn_share_friend://微信分享给朋友
                    share(false);
                    break;
                case R.id.btn_pay://微信支付
    //              先去服务器获取支付信息,返回一个WeiXinPay对象,然后调用pay方法
                    showToast("微信支付需要服务器支持");
                    break;
            }
        }
    
        /**
         * 这里用到的了EventBus框架
         * @param weiXin
         */
        @Subscribe
        public void onEventMainThread(WeiXin weiXin){
            Log.i("ansen","收到eventbus请求 type:"+weiXin.getType());
            if(weiXin.getType()==1){//登录
                getAccessToken(weiXin.getCode());
            }else if(weiXin.getType()==2){//分享
                switch (weiXin.getErrCode()){
                    case BaseResp.ErrCode.ERR_OK:
                        Log.i("ansen", "微信分享成功.....");
                        break;
                    case BaseResp.ErrCode.ERR_USER_CANCEL://分享取消
                        Log.i("ansen", "微信分享取消.....");
                        break;
                    case BaseResp.ErrCode.ERR_AUTH_DENIED://分享被拒绝
                        Log.i("ansen", "微信分享被拒绝.....");
                        break;
                }
            }else if(weiXin.getType()==3){//微信支付
                if(weiXin.getErrCode()==BaseResp.ErrCode.ERR_OK){//成功
                    Log.i("ansen", "微信支付成功.....");
                }
            }
        }
        
        ..........
    
        public void showToast(String message){
            Toast.makeText(this,message,Toast.LENGTH_LONG).show();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            EventBus.getDefault().unregister(this);//取消注册
        }
    }
    
    • onCreate 注册EventBus,通过WXAPIFactory创建IWXAPI类,并且注册appid,给四个按钮按钮设置点击事件。查找显示名字跟年龄的两个TextView。
    • onClick 点击事件监听,根据id来判断点击不同的按钮,跳转到相应的方法,这些方法没贴出来来,等会单独讲。
    • onEventMainThread(WeiXin weiXin) 用来接收消息,这个方法有个参数,用来判断类型,就是我们用EventBus发送时参数必须是WeiXin类型。首先判断type,是登录还是分享还是支付。登录成功情况下会获取到code,根据code然后我们就能获取到微信用户信息。
    • showToast Toast提示
    • onDestroy 取消EventBus注册

    微信登录

    微信登录流程有以下三个步骤:

    • 微信授权登陆
    • 根据授权登陆code 获取该用户token
    • 根据token获取用户资料

    当我们点击登录按钮的时候,调用的是login方法。这个方法就在MainActivity里面。就是给微信发起一个登录请求,弹出一个授权界面。

    public void login(){
        SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = String.valueOf(System.currentTimeMillis());
        wxAPI.sendReq(req);
    }
    

    在你的包名相应目录下新建一个wxapi目录,然后在wxapi目录下新增一个WXEntryActivity类,用来接收登录授权以及分享时微信的回调信息。这个类继承自Activity,需要实现IWXAPIEventHandler接口。

    package com.ansen.shoenet.wxapi;
    public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
        private IWXAPI wxAPI;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            wxAPI = WXAPIFactory.createWXAPI(this,Constant.WECHAT_APPID,true);
            wxAPI.registerApp(Constant.WECHAT_APPID);
            wxAPI.handleIntent(getIntent(), this);
        }
    
        @Override
        protected void onNewIntent(Intent intent){
            super.onNewIntent(intent);
            wxAPI.handleIntent(getIntent(),this);
            Log.i("ansen","WXEntryActivity onNewIntent");
        }
    
        @Override
        public void onReq(BaseReq arg0) {
            Log.i("ansen","WXEntryActivity onReq:"+arg0);
        }
    
        @Override
        public void onResp(BaseResp resp){
            if(resp.getType()== ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX){//分享
                Log.i("ansen","微信分享操作.....");
                WeiXin weiXin=new WeiXin(2,resp.errCode,"");
                EventBus.getDefault().post(weiXin);
            }else if(resp.getType()==ConstantsAPI.COMMAND_SENDAUTH){//登陆
                Log.i("ansen", "微信登录操作.....");
                SendAuth.Resp authResp = (SendAuth.Resp) resp;
                WeiXin weiXin=new WeiXin(1,resp.errCode,authResp.code);
                EventBus.getDefault().post(weiXin);
            }
            finish();
        }
    }
    

    onCreate、onNewIntent、onReq这三个方法是固定写法。onResp方法接收微信结果信息,首先判断类型,根据不同的类型去封装WeiXin对象,如果是登录操作,把code传入进去,然后把封装好的WeiXin对象通过EventBus发送出去。MainActivity的onEventMainThread方法就会接收到这个消息。最后调用finish关闭当前的activity。

    WXEntryActivity记得在AndroidManifest.xml中注册

    <activity
        android:exported="true"
        android:name=".wxapi.WXEntryActivity"/>
    

    继续回到首页的onEventMainThread,如果登录类型调用getAccessToken(),并且传入code。根据code获取access_token,这个url是微信公开的,需要传入三个参数,appid、secret、code。请求成功之后会返回access_token跟openid等信息。

    public void getAccessToken(String code){
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                "appid="+Constant.WECHAT_APPID+"&secret="+Constant.WECHAT_SECRET+
                "&code="+code+"&grant_type=authorization_code";
        HTTPCaller.getInstance().get(WeiXinToken.class, url, null, new RequestDataCallback<WeiXinToken>() {
            @Override
            public void dataCallback(WeiXinToken obj) {
                if(obj.getErrcode()==0){//请求成功
                    getWeiXinUserInfo(obj);
                }else{//请求失败
                    showToast(obj.getErrmsg());
                }
            }
        });
    }
    

    获取到access_token跟openid之后继续调用getWeiXinUserInfo方法获取用户信息。这样就能取到当前微信app登录的用户一些信息。有昵称、年龄、头像地址、语言等基本信息。在企业开发中,到了这一步就可以拿着这些信息调用自己服务器的登录接口。当然我们这边就把昵称跟年龄给TextView显示下。

    public void getWeiXinUserInfo(WeiXinToken weiXinToken){
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+
                weiXinToken.getAccess_token()+"&openid="+weiXinToken.getOpenid();
        HTTPCaller.getInstance().get(WeiXinInfo.class, url, null, new RequestDataCallback<WeiXinInfo>() {
            @Override
            public void dataCallback(WeiXinInfo obj) {
                tvNickname.setText("昵称:"+obj.getNickname());
                tvAge.setText("年龄:"+obj.getAge());
                Log.i("ansen","头像地址:"+obj.getHeadimgurl());
            }
        });
    }
    

    WeiXinToken跟WeiXinInfo这两个实体类就不贴代码了,WeiXinToken用来映射获取访问token接口返回的json。WeiXinInfo用来映射获取用户接口返回的json。

    微信分享

    分享有两种分享到朋友圈跟分享给好友,统一调用share方法。传入一个boolean类型来判断是否分享到朋友圈。

    public void share(boolean friendsCircle){
        WXWebpageObject webpage = new WXWebpageObject();
        webpage.webpageUrl = "www.baidu.com";//分享url
        WXMediaMessage msg = new WXMediaMessage(webpage);
        msg.title = "分享标题";
        msg.description = "分享描述";
        msg.thumbData =getThumbData();//封面图片byte数组
    
        SendMessageToWX.Req req = new SendMessageToWX.Req();
        req.transaction = String.valueOf(System.currentTimeMillis());
        req.message = msg;
        req.scene = friendsCircle ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
        wxAPI.sendReq(req);
    }
    

    分享内容有很多格式,分享图片、分享视频、分享消息。我们这边就分享消息为例,也是分享比较常见的格式。首先new一个WXWebpageObject对象,设置标题、内容、打开链接、封面等。最后调用wxAPI的sendReq放松一个请求。

    分享跟登录一样,都会回调WXEntryActivity,然后又把分享结果发送给MainActivity.onEventMainThread方法。

    支付
    支付首先需要请求我们自己的服务器,获取支付信息。获取成功之后调用pay方法。

    public void pay(WeiXinPay weiXinPay){
        PayReq req = new PayReq();
        req.appId = Constant.WECHAT_APPID;//appid
        req.nonceStr=weiXinPay.getNoncestr();//随机字符串,不长于32位。推荐随机数生成算法
        req.packageValue=weiXinPay.getPackage_value();//暂填写固定值Sign=WXPay
        req.sign=weiXinPay.getSign();//签名
        req.partnerId=weiXinPay.getPartnerid();//微信支付分配的商户号
        req.prepayId=weiXinPay.getPrepayid();//微信返回的支付交易会话ID
        req.timeStamp=weiXinPay.getTimestamp();//时间戳
    
        wxAPI.registerApp(Constant.WECHAT_APPID);
        wxAPI.sendReq(req);
    }
    

    weiXinPay的值应该是我们从自己服务器获取的,然后把返回信息封装到PayReq对象中,最后调用wxAPI的sendReq方法发起请求。

    在wxapi目录下新增一个WXPayEntryActivity类,这个类跟WXEntryActivity同级,用来接收微信支付的回调信息。这个类继承自Activity,需要实现IWXAPIEventHandler接口。

    public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
    	private IWXAPI wxAPI;
    	
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    		wxAPI = WXAPIFactory.createWXAPI(this, Constant.WECHAT_APPID);
    		wxAPI.handleIntent(getIntent(), this);
        }
        
        @Override
        protected void onNewIntent(Intent intent){
            super.onNewIntent(intent);
    		setIntent(intent);
            wxAPI.handleIntent(intent, this);
        }
    
    	@Override
    	public void onReq(BaseReq baseReq) {}
    
    	@Override
    	public void onResp(BaseResp resp) {
    		Log.i("ansen", "微信支付回调 返回错误码:"+resp.errCode+" 错误名称:"+resp.errStr);
    		if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX){//微信支付
    			WeiXin weiXin=new WeiXin(3,resp.errCode,"");
    			EventBus.getDefault().post(weiXin);
    		}
    		finish();
    	}
    }
    

    其他方法都是固定写法,在onResp中判断如果是微信登录,就封装一个WeiXin对象,然后发送EventBus请求。这样MainActivity的onEventMainThread就会接收到这个WeiXin对象。

    WXPayEntryActivity记得在AndroidManifest.xml中注册。

    <activity
        android:exported="true"
        android:name=".wxapi.WXPayEntryActivity"/>
    

    项目结构图如下所示,从图中我们看到软件包名是com.ansen.shoenet。接收微信登录支付返回的Activity的包名必须是com.ansen.shoenet.wxapi。两个activity的名字也是固定写法。

    project_structure

    签名

    微信登录分享支付都有一个签名验证,这个很麻烦,导致每次调试都需要重新签名。

    首先用android studio生成一个正式的签名文件,签名文件是.jks结尾的,这个签名文件是你以后打线上包一直要用到的。然后用这个签名文件生成apk。这个时候我们的app就有了正式签名。把正式签名的apk发送到手机上进行安装。

    并且下载一个签名生成工具安装,这个工具用于获取安装到手机的第三方应用签名的apk包。微信官方下载地址:

    https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android2.apk
    

    以上两个app都安装好了之后打开从微信下载的那个app,软件名字叫「GenSignature」,有一个输入框,输入我们软件的包名,点击Get Signature按钮.效果图如下:
    get_signature

    把那行绿色的16进制数炒下来保存到txt文本中。

    微信sdk官网后台配置

    官网地址:

    https://open.weixin.qq.com/
    

    在微信sdk首页,有个管理中心点击之后默认就是移动应用,如果还没有创建移动应用就先创建一个,如果有了就点击当前的应用后面的查看按钮,就会进入应用详细界面。

    在应用详细界面一直往下滚动,滚到最底部有个开发信息。点击修改,进入修改界面,在修改界面滚动到最下面,效果图如下所示:
    app_info
    首先我们在Android应用这里打上勾,然后填写应用签名,这个签名都是我之前要你们保存到记事本上的那个值,包名就是app包名。点击保存。

    运行软件

    登录之后效果图如下:

    login_success

    分享到朋友圈如下:

    share_friend_circle

    分享给朋友:

    share_friend

    微信支付没法测试,因为需要服务器支持。

    微信官方开发文档

    我这偏文章只是针对现在微信的sdk版本接入,但是sdk是有可能变化的,版本变化、接口变化等。所以建议大家还是以官方文档为主。我的文章提供参考。

    移动应用微信登录开发指南

    https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN
    

    Android微信支付开发手册

    https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317784&token=219192a54f13e8e7011ced8e4ce5b36b699629c4&lang=zh_CN
    

    注意事项

    接入微信sdk有很多需要注意的地方,这里我们最后再来做一个总结。

    • 微信登陆,分享,支付回调的Activity包名跟类名一定要严格按照要求去写
    • 接收回调的是Activity一定要在AndroidManifest.xml中中注册
    • Constant里面两个常量的值要去微信申请并且创建应用才有的,这里需要改成你们申请的值。
    • 需要访问网络所以记得在AndroidManifest.xml中添加权限
    • 调用微信的登陆,分享,支付你的安装包一定要有签名,签名信息一定要跟你在微信官网上配置的签名信息一致
    • 微信没有客服支持.....如果出了问题看官方的Demo或者官方API
    • 微信SDK经常升级,如果你开发的时候有最新的就用最新的吧.....

    最后的最后

    你们直接运行我的demo是不行的,因为你们没有的jks文件,没法签名,并且源码中的appid跟secret被我修改过了,是不能使用的,但是你们可能又想看运行效果,所以我在项目下建了个apk文件夹,里面放了一个可以测试微信登录分享的apk安装包。

    源码下载

    如果你想第一时间看我的后期文章,扫码关注公众号,每周不定期推送Android开发实战教程文章...

          Android开发666 - 安卓开发技术分享
                 扫描二维码加关注
    

    Android开发666

  • 相关阅读:
    Ubuntu下sudo apt-get install vim 失败的解决办法
    电脑突然出现成功连接网络但不能上网、网络受限(解决办法)
    wxWidgets 安装方法(Windows 8.1 + Visual Studio 2013)
    wxWidgets界面开发工具wxFormBuilder的使用
    隐私策略
    MyEclipse 中自定义日期格式
    Debug Assertion Failed!
    p2 弹簧
    p2 关节
    p2 形状
  • 原文地址:https://www.cnblogs.com/yishaochu/p/7531638.html
Copyright © 2020-2023  润新知