用了微信sdk各种痛苦,感觉比qq sdk调用麻烦多了,回调过于麻烦,还必须要在指定包名下的actvity进行回调,所以我在这里写一篇博客,有这个需求的朋友可以借鉴一下,以后自己别的项目有用到也有个找资料的地方.
一.微信登陆分三个步骤:
1).微信授权登陆
2).根据授权登陆code 获取该用户token
3).根据token获取用户资料
4).接收微信的请求及返回值 如果你的程序需要接收微信发送的请求,或者接收发送到微信请求的响应结果,需要下面3步操作:
a. 在你的包名相应目录下新建一个wxapi目录,并在该wxapi目录下新增一个wxentryactivity类,该类继承自activity(例如应用程序的包名为net.sourceforge.simcpux,
则新添加的类如下图所示)
并在manifest文件里面加上exported属性,设置为true,例如:
b. 实现iwxapieventhandler接口,微信发送的请求将回调到onreq方法,发送到微信请求的响应结果将回调到onresp方法
c. 在wxentryactivity中将接收到的intent及实现了iwxapieventhandler接口的对象传递给iwxapi接口的handleintent方法,示例如下图:
微信官网登陆教程:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=&lang=zh_cn
微信官网接入指南:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=1417751808&token=&lang=zh_cn
二.微信分享直接调用sdk就行,回调跟登陆回调的类是一样的,根据baseresp的类型来区分是登陆还是分享。
三.微信支付
1).发送一个支付请求
2).接收微信支付的返回值(跟接收微信登陆.分享的返回值类似,我就不写详细操作步骤了)
官网参考地址:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_5
四.贴上代码进行讲解
我把微信登陆,分享,支付都封装到了一个类里面了,你们可以参考这个类.封装了6个方法,我对几个需要的方法介绍一下
1).构造方法:初始化对象的时候,顺便初始化微信对象,把app_id注册到微信
2).login() 发起一个登陆的请求 在微信登陆监听actviity中获取code
3).getaccesstoken(string code) 当你从监听activity中获取了code之后就可以通过这个方法获取微信访问token了
4).getweixinuserinfo(final weixintoken obj) 获取微信用户信息 传入一个weixintoken对象,这个对象是第三步的返回值
5).share(final boolean friendscircle,final videob videob) 分享给朋友或者朋友圈 如果你有分享图片,图片过大的时候一定要经过压缩,微信官网说明图片不能大
于32kb
6).iswxappinstalled() 检查微信是否安装
7).wxpay(final baseactivity activity,string order_id,string paytype) 微信支付 我们项目微信支付的一些参数保存在服务器上,所以我这边还请求了自己的
服务器,如果你们是放在本地,直接copy回调函数里面的代码即可.在微信支付监听actviity中获取支付的状态码
payreq类属性对应含义请参考微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
/** * 微信分享,登陆,支付 * @author ansen * @create time 2015-08-29 */ public class weixinpresenter extends presenter{ public static final int image_size= 32768 ; //微信分享图片大小限制 public static final string app_id = "" ; //应用唯一标识,在微信开放平台提交应用审核通过后获得 public static final string secret= "" ; //应用密钥appsecret,在微信开放平台提交应用审核通过后获得 private iwxapi wxapi; private iview iview; private iusercontroller usercontroller; @override public iview getiview() { return iview; } public weixinpresenter(context context){ if (context!= null && context instanceof iview) iview =(iview) context; if (wxapi== null ){ wxapi = wxapifactory.createwxapi(context,app_id, true ); wxapi.registerapp(app_id); } if ( null ==usercontroller) usercontroller=controllerfactory.getusercontroller(); } /** * 微信登陆(三个步骤) * 1.微信授权登陆 * 2.根据授权登陆code 获取该用户token * 3.根据token获取用户资料 * @param activity */ public void login(){ sendauth.req req = new sendauth.req(); req.scope = "snsapi_userinfo" ; req.state = string.valueof(system.currenttimemillis()); wxapi.sendreq(req); } /** * 获取微信访问token */ public void getaccesstoken(string code){ if (!usercontroller.islogin()){ //没有登陆的情况用第三方登陆 usercontroller.getweixinaccesstoken(app_id,secret,code, new requestdatacallback<weixintoken>(){ @override public void datacallback(weixintoken obj){ if (obj!= null ){ if (obj.geterrcode()== 0 ){ if (mlog.debug) iview.showtoast( "授权用户唯一标识:" +obj.getopenid()); getweixinuserinfo(obj); } else { iview.showtoast(obj.geterrmsg()); } } else { } } }); } else { //用户已登陆 } } /** * 获取微信用户信息 */ private void getweixinuserinfo( final weixintoken obj){ usercontroller.getweixinuserinfo(obj.getaccess_token(), obj.getopenid(), new requestdatacallback<registerb>() { @override public void datacallback(registerb registerb){ registerb.setaccess_token(obj.getaccess_token()); registerb.settoken_expire_at(obj.getexpires_in()); if (registerb.geterrcode()== 0 ){ registerb.setthird_type_name(constants.wei_xin); thirdlogin(registerb); } else { iview.showtoast(registerb.geterrmsg()); } } }); } /** * 调用我们自己的服务器进行登录 * @param registerb */ private void thirdlogin(registerb registerb){ usercontroller.thirdauth(registerb, new requestdatacallback<userp>(){ @override public void datacallback(userp user){ if (checkcallbackdata(user, true )){ if (user.geterror()==user.errornone){ iview.showtoast(r.string.login_success); getappcontroller().sendloginchangeintent(); usercontroller.saveloginuser(user,fileutil.getfilepath()); ((iloginview)iview).tomain(); } else { iview.showtoast(user.geterror_reason()); } } } }); } /** * 微信分享 * @param friendscircle 是否分享到朋友圈 */ public void share( final boolean friendscircle, final videob videob){ new loadpicthread(videob.getcover_url(), new handler(){ @override public void handlemessage(message msg) { byte [] bytes=( byte []) msg.obj; if (bytes.length>image_size){ iview.showtoast(r.string.image_no_big); return ; } system.out.println( "图片长度:" +bytes.length); wxvideoobject videoobject = new wxvideoobject(); //视频类型 videoobject.videourl = videob.getshare_url() + constants.wei_xin + "&share_from=" +com.kaka.utils.constants.android; // 视频播放url wxmediamessage wxmessage = new wxmediamessage(videoobject); wxmessage.title = videob.getcontent(); wxmessage.thumbdata = bytes; sendmessagetowx.req req = new sendmessagetowx.req(); //transaction字段用于唯一标识一个请求 req.transaction = string.valueof(videob.getid() + system.currenttimemillis()); req.message = wxmessage; req.scene = friendscircle ? sendmessagetowx.req.wxscenetimeline : sendmessagetowx.req.wxscenesession; wxapi.sendreq(req); } }).start(); } private class loadpicthread extends thread{ private string url; private handler handler; public loadpicthread(string url,handler handler){ this .url=url; this .handler=handler; } @override public void run(){ try { url picurl = new url(url); httpurlconnection conn = (httpurlconnection)picurl.openconnection(); // 获得连接 conn.setconnecttimeout( 6000 ); //设置超时 conn.setdoinput( true ); conn.setusecaches( false ); //不缓存 conn.connect(); bitmap bmp=bitmapfactory.decodestream(conn.getinputstream()); bytearrayoutputstream output = new bytearrayoutputstream(); bmp.compress(bitmap.compressformat.jpeg, 100 , output); int options = 100 ; while (output.tobytearray().length > image_size && options != 10 ) { output.reset(); // 清空baos bmp.compress(bitmap.compressformat.jpeg, options, output); // 这里压缩options%,把压缩后的数据存放到baos中 options -= 10 ; } bmp.recycle(); byte [] result = output.tobytearray(); output.close(); message message=handler.obtainmessage(); message.obj=result; message.sendtotarget(); } catch (exception e) { e.printstacktrace(); } } } //检查微信是否安装 public boolean iswxappinstalled(){ return wxapi.iswxappinstalled(); } public void wxpay( final baseactivity activity,string order_id,string paytype){ activity.showprogress( "" ); controllerfactory.getwalletscontroller().getpayments(order_id, paytype, new requestdatacallback<paymentsp>() { @override public void datacallback(paymentsp obj) { if (checkcallbackdata(obj, true )){ if (obj.geterror()==obj.errornone){ payreq req = new payreq(); //待修改 req.appid = obj.getappid(); req.noncestr=obj.getnoncestr(); req.packagevalue=obj.getpackage_value(); req.sign=obj.getsign(); req.partnerid=obj.getpartnerid(); req.prepayid=obj.getprepayid(); req.timestamp=obj.gettimestamp(); wxapi.registerapp(obj.getappid()); wxapi.sendreq(req); mlog.i( "ansen" , "开始进行微信支付.." ); iview.showtoast( "开始进行微信支付.." ); } } else { iview.showtoast(obj.geterror_reason()); } activity.hideprogress(); } }); } } |
微信登陆以及分享 请求跟返回值的接收 我这边登陆.分享的状态都是发送广播出去,然后结束当前的activity.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/** * 微信登陆分享回调activity * @author ansen * @create time 2015-05-25 */ public class wxentryactivity extends activity implements iwxapieventhandler{ private iwxapi wxapi; @override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); if (mlog.debug) system.out.println( "wxentryactivity oncreate" ); wxapi = wxapifactory.createwxapi( this ,weixinpresenter.app_id, true ); wxapi.registerapp(weixinpresenter.app_id); wxapi.handleintent(getintent(), this ); } @override protected void onnewintent(intent intent){ super .onnewintent(intent); wxapi.handleintent(getintent(), this ); if (mlog.debug) system.out.println( "wxentryactivity onnewintent" ); } @override public void onreq(basereq arg0) { if (mlog.debug) system.out.println( "wxentryactivity onreq:" +arg0); if (mlog.debug) toast.maketext( this , "onreq 方法运行" , 0 ).show(); } @override public void onresp(baseresp resp){ mlog.d( "ansen" , "onresp....." ); if (mlog.debug) toast.maketext( this , "onresp 方法运行" , 0 ).show(); if (resp.gettype()==constantsapi.command_sendmessage_to_wx){ //分享 switch (resp.errcode){ case baseresp.errcode.err_ok: if (mlog.debug) toast.maketext(wxentryactivity. this , "分享成功!" , toast.length_short).show(); break ; case baseresp.errcode.err_user_cancel: // toast.maketext(wxentryactivity.this, "分享取消!", toast.length_short).show(); break ; case baseresp.errcode.err_auth_denied: break ; } intent intent = new intent(); intent.setaction(apidefineconst.broadcast_action_weixin_share); localbroadcastmanager lbm = localbroadcastmanager.getinstance( this ); lbm.sendbroadcast(intent); } else if (resp.gettype()==constantsapi.command_sendauth){ //登陆发送广播 sendauth.resp authresp = (resp) resp; string code = authresp.code; intent intent = new intent(); intent.setaction(apidefineconst.broadcast_action_weixin_token); intent.putextra( "errcode" , authresp.errcode); if (authresp.errcode == baseresp.errcode.err_ok){ //用户同意 intent.putextra( "code" , code); } if (mlog.debug) toast.maketext( this , "wxentryactivity 发送登陆广播!!!!" , 0 ).show(); if (android.os.build.version.sdk_int >= 12 ) { intent.setflags( 32 ); //3.1以后的版本需要设置intent.flag_include_stopped_packages } localbroadcastmanager lbm = localbroadcastmanager.getinstance( this ); lbm.sendbroadcast(intent); } finish(); } } |
微信支付 请求跟返回值的接收 微信支付也是发送广播,如果你们还有需求判断支付成功或者失败,可以在广播的intent中进行传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/** * 微信支付回调activity * @author ansen * @create time 2015-08-29 */ public class wxpayentryactivity extends activity implements iwxapieventhandler{ private iwxapi wxapi; @override protected void oncreate(bundle savedinstancestate) { super .oncreate(savedinstancestate); wxapi = wxapifactory.createwxapi( this , weixinpresenter.app_id); wxapi.handleintent(getintent(), this ); } @override protected void onnewintent(intent intent){ super .onnewintent(intent); setintent(intent); wxapi.handleintent(intent, this ); } @override public void onreq(basereq arg0) { } @override public void onresp(baseresp resp) { mlog.i( "微信支付回调.." , "ansen onresp" ); if (resp.gettype() == constantsapi.command_pay_by_wx){ //微信支付回调 if (resp.errcode==baseresp.errcode.err_ok){ //微信支付成功 intent intent = new intent(); intent.setaction(apidefineconst.broadcast_action_weixin_pay); localbroadcastmanager lbm = localbroadcastmanager.getinstance( this ); lbm.sendbroadcast(intent); //成功 // toast.maketext(this,r.string.wxpay_success, 0).show(); } else { // toast.maketext(this,r.string.wxpay_success, 0).show(); } } finish(); } } |
强调一点,一定要注意 接收微信的请求及返回值 的包名跟类名,包名是应用程序的包名+".wxapi" 类名必须是微信指定的类名 并且这两个activity一定要在androidmanifest.xml中注册,上传一张是我做的app中包名跟类名的截图
如何在activity中调用微信登陆
1).登陆广播监听内部类 如果接收到了广播就去获取微信token
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
private class wxentryreceiver extends broadcastreceiver { @override public void onreceive(context context, intent intent){ mlog.i( "wxentryreceiver" , "接收微信登陆广播" ); if (mlog.debug) showtoast( "接收微信登陆广播" ); if (intent.getaction().equals(apidefineconst.broadcast_action_weixin_token)){ int errcode = intent.getextras().getint( "errcode" ); if (mlog.debug) system.out.println( "获取错误码:" +errcode); if (errcode==baseresp.errcode.err_user_cancel||errcode==baseresp.errcode.err_auth_denied){ requestdatafinish(); } else { string code = intent.getextras().getstring( "code" ); xintestpresenter.getaccesstoken(code); } } } } |
2).定义成员变量
1
|
private wxentryreceiver wxentryreceiver= null ; |
3).在oncreate中注册广播
1
2
3
4
5
6
|
//微信登陆广播 wxentryreceiver= new wxentryreceiver(); localbroadcastmanager lbm = localbroadcastmanager.getinstance( this ); intentfilter filter = new intentfilter(); filter.addaction(apidefineconst.broadcast_action_weixin_token); lbm.registerreceiver(wxentryreceiver,filter); |
4).调用微信登陆
1
2
|
weixinpresenter xintestpresenter= new weixinpresenter( this ); xintestpresenter.login(); |
在activity中调用微信分享跟调用微信支付的代码我就不贴出来了,我这篇博客只是给大家一个参考的地方,遇到问题还是建议第一时间看官方文档.
说说我在做微信登陆碰到的问题
1.微信登陆、分享、支付 回调的activity 包名跟类名一定要严格按照要求去写
2.接收回调的是activity 一定要在androidmanifest.xml中注册
3.weixinpresenter中有两个常量 app_id跟secret 要去微信申请的时候才有的.你们copy代码的时候要给这两个常量赋值
4.可能访问网络神马的还需要一些权限 记得在androidmanifest.xml添加权限
5.调用微信的登陆、分享、支付 你的安装包一定要有签名,签名信息一定要跟你在微信官网上申请时签名信息一致
6.微信没有客服支持。。。。。如果出了问题看官方demo 或者 官方api
7.微信sdk经常升级,如果你开发的时候有最新的就用最新的吧.....