安卓集成微信登陆
一、首先在Application的onCreate中写:
1
2
3
4
5
6
7
|
//
GeneralAppliction.java
public
static
IWXAPI sApi;
@Override
public
void
onCreate() {
super .onCreate();
sApi
= WXEntryActivity.initWeiXin( this ,
AppConst.WEIXIN_APP_ID);
}
|
二、在需要登录的地方添加:
1
2
|
//
MainActivity.java
WXEntryActivity.loginWeixin(MainActivity. this ,
GeneralAppliction.sApi);
|
三、下面对具体的集成步骤做详细的描述。
集成步骤:
1、在开放平台注册创建应用,申请登录权限
2、下载sdk,拷贝相关文件到项目工程目录
3、全局初始化微信组件
4、请求授权登录,获取code
5、通过code获取授权口令access_token
6、在第5步判断access_token是否存在和过期
7、如果access_token过期无效,就用refresh_token来刷新
8、使用access_token获取用户信息
1. 在开放平台注册创建应用,申请登录权限
这一步其实不用怎么讲,无法就是在微信开放平台上注册一个账号,然后创建移动应用。
需要注意的是:应用签名的部分
此处应用签名我使用的是线上的key的md5,关于这个需要注意的问题可以看:Android的签名总结
2. 下载sdk,拷贝相关文件到项目工程目录
开发工具包(SDK)的下载:可以使用微信分享、登录、收藏、支付等功能需要的库以及文件
下载后把libammsdk.jar文件拷贝到AS工程的libs目录,并把示例Demo里源文件目录下的wxapi目录整个拷贝到,工程目录的src下的根包下:
如果wxapi这个文件夹放的位置不对,讲无法登录,微信sdk无法找到登录的Activity授权功能。然后在Manifest.xml里面加入:
1
2
3
4
5
6
|
<activity
android:name= ".wxapi.WXEntryActivity"
android:theme= "@android:style/Theme.Translucent.NoTitleBar"
android:configChanges= "keyboardHidden|orientation|screenSize"
android:exported= "true"
android:screenOrientation= "portrait"
/>
|
3. 全局初始化微信组件
全局初始化微信组件,当然是Application的onCreate里(当然Activity的onCreate也是可以的,为了全局使用微信api对象方便操作):
1
2
3
4
5
6
7
8
9
10
11
|
@Override
public
void
onCreate() {
super .onCreate();
//
初始化微信组件
initWeiXin();
}
public
static
IWXAPI sApi;
private
void
initWeiXin() {
sApi
= WXEntryActivity.initWeiXin( this ,
AppConst.WEIXIN_APP_ID);
}
|
4. 请求授权登录,获取code
为了同一业务的单一原则我把微信相关的都统一封装到了wxapi包下和WXEntryActivity中:
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
|
//
实现IWXAPIEventHandler 接口,以便于微信事件处理的回调
public
class
WXEntryActivity extends
Activity implements
IWXAPIEventHandler {
private
static
final
String WEIXIN_ACCESS_TOKEN_KEY = "wx_access_token_key" ;
private
static
final
String WEIXIN_OPENID_KEY = "wx_openid_key" ;
private
static
final
String WEIXIN_REFRESH_TOKEN_KEY = "wx_refresh_token_key" ;
private
Gson mGson;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
//
微信事件回调接口注册
GeneralAppliction.sApi.handleIntent(getIntent(),
this );
mGson
= new
Gson();
}
/**
*
微信组件注册初始化
*
@param context 上下文
*
@param weixin_app_id appid
*
@return 微信组件api对象
*
/
public
static IWXAPI initWeiXin(Context context, @NonNull String weixin_app_id) {
if
(TextUtils.isEmpty(weixin_app_id)) {
Toast.makeText(context.getApplicationContext(),
"app_id 不能为空", Toast.LENGTH_SHORT).show();
}
IWXAPI
api = WXAPIFactory.createWXAPI(context, weixin_app_id, true);
api.registerApp(weixin_app_id);
return
api;
}
/**
*
登录微信
*
*
@param api 微信服务api
*/
public
static
void
loginWeixin(Context context, IWXAPI api) {
//
判断是否安装了微信客户端
if
(!api.isWXAppInstalled()) {
Toast.makeText(context.getApplicationContext(),
"您还未安装微信客户端!" ,
Toast.LENGTH_SHORT).show();
return ;
}
//
发送授权登录信息,来获取code
SendAuth.Req
req = new
SendAuth.Req();
//
应用的作用域,获取个人信息
req.scope
= "snsapi_userinfo" ;
/**
*
用于保持请求和回调的状态,授权请求后原样带回给第三方
*
为了防止csrf攻击(跨站请求伪造攻击),后期改为随机数加session来校验
*/
req.state
= "app_wechat" ;
api.sendReq(req);
}
//
微信发送请求到第三方应用时,会回调到该方法
@Override
public
void
onReq(BaseReq req) {
switch
(req.getType()) {
case
ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
break ;
case
ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
break ;
default :
break ;
}
}
//
第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
@Override
public
void
onResp(BaseResp resp) {
switch
(resp.errCode) {
//
发送成功
case
BaseResp.ErrCode.ERR_OK:
//
获取code
String
code = ((SendAuth.Resp) resp).code;
//
通过code获取授权口令access_token
getAccessToken(code);
break ;
}
}
}
|
小伙伴有疑问code是啥玩意:
第三方通过code进行获取access_token的时候需要用到,code的超时时间为10分钟,一个code只能成功换取一次access_token即失效。code的临时性和一次保障了微信授权登录的安全性。第三方可通过使用https和state参数,进一步加强自身授权登录的安全性。
这样客户端使用的地方只要:
1
|
WXEntryActivity.loginWeixin(MainActivity. this ,
GeneralAppliction.sApi);
|
5. 通过code获取授权口令access_token
我们在onResp的回调方法中获取了code,然后通过code获取授权口令access_token:
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
|
/**
*
获取授权口令
*/
private
void
getAccessToken(String code) {
"appid="
+ AppConst.WEIXIN_APP_ID +
"&secret="
+ AppConst.WEIXIN_APP_SECRET +
"&code="
+ code +
"&grant_type=authorization_code" ;
//
网络请求获取access_token
httpRequest(url,
new
ApiCallback<String>() {
@Override
public
void
onSuccess(String response) {
Logger.e(response);
//
判断是否获取成功,成功则去获取用户信息,否则提示失败
processGetAccessTokenResult(response);
}
@Override
public
void
onError( int
errorCode, final
String errorMsg) {
Logger.e(errorMsg);
showMessage( "错误信息:
"
+ errorMsg);
}
@Override
public
void
onFailure(IOException e) {
Logger.e(e.getMessage());
showMessage( "登录失败" );
}
});
}
/**
*
处理获取的授权信息结果
*
@param response 授权信息结果
*/
private
void
processGetAccessTokenResult(String response) {
//
验证获取授权口令返回的信息是否成功
if
(validateSuccess(response)) {
//
使用Gson解析返回的授权口令信息
WXAccessTokenInfo
tokenInfo = mGson.fromJson(response, WXAccessTokenInfo. class );
Logger.e(tokenInfo.toString());
//
保存信息到手机本地
saveAccessInfotoLocation(tokenInfo);
//
获取用户信息
getUserInfo(tokenInfo.getAccess_token(),
tokenInfo.getOpenid());
}
else
{
//
授权口令获取失败,解析返回错误信息
WXErrorInfo
wxErrorInfo = mGson.fromJson(response, WXErrorInfo. class );
Logger.e(wxErrorInfo.toString());
//
提示错误信息
showMessage( "错误信息:
"
+ wxErrorInfo.getErrmsg());
}
}
/**
*
验证是否成功
*
*
@param response 返回消息
*
@return 是否成功
*/
private
boolean
validateSuccess(String response) {
String
errFlag = "errmsg" ;
return
(errFlag.contains(response) && ! "ok" .equals(response))
||
(! "errcode" .contains(response)
&& !errFlag.contains(response));
}
|
6. 在第5步判断access_token是否存在和过期
在回调的onResp方法中获取code后,处理access_token是否登录过或者过期的问题:
1
2
3
4
5
6
7
8
9
10
|
//
从手机本地获取存储的授权口令信息,判断是否存在access_token,不存在请求获取,存在就判断是否过期
String
accessToken = (String) ShareUtils.getValue( this ,
WEIXIN_ACCESS_TOKEN_KEY, "none" );
String
openid = (String) ShareUtils.getValue( this ,
WEIXIN_OPENID_KEY, "" );
if
(! "none" .equals(accessToken))
{
//
有access_token,判断是否过期有效
isExpireAccessToken(accessToken,
openid);
}
else
{
//
没有access_token
getAccessToken(code);
}
|
判断授权口令是否有效:
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
|
/**
*
判断accesstoken是过期
*
@param accessToken token
*
@param openid 授权用户唯一标识
*/
private
void
isExpireAccessToken( final
String accessToken, final
String openid) {
"access_token="
+ accessToken +
"&openid="
+ openid;
httpRequest(url,
new
ApiCallback<String>() {
@Override
public
void
onSuccess(String response) {
Logger.e(response);
if
(validateSuccess(response)) {
//
accessToken没有过期,获取用户信息
getUserInfo(accessToken,
openid);
}
else
{
//
过期了,使用refresh_token来刷新accesstoken
refreshAccessToken();
}
}
@Override
public
void
onError( int
errorCode, final
String errorMsg) {
Logger.e(errorMsg);
showMessage( "错误信息:
"
+ errorMsg);
}
@Override
public
void
onFailure(IOException e) {
Logger.e(e.getMessage());
showMessage( "登录失败" );
}
});
}
|
7. 如果access_token过期无效,就用refresh_token来刷新
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
|
/**
*
刷新获取新的access_token
*
/
private
void
refreshAccessToken() {
//
从本地获取以存储的refresh_token
final
String refreshToken = (String) ShareUtils.getValue( this ,
WEIXIN_REFRESH_TOKEN_KEY, "" );
if
(TextUtils.isEmpty(refreshToken)) {
return ;
}
//
拼装刷新access_token的url请求地址
"appid="
+ AppConst.WEIXIN_APP_ID +
"&grant_type=refresh_token"
+
"&refresh_token="
+ refreshToken;
//
请求执行
httpRequest(url,
new
ApiCallback<String>() {
@Override
public
void
onSuccess(String response) {
Logger.e( "refreshAccessToken:
"
+ response);
//
判断是否获取成功,成功则去获取用户信息,否则提示失败
processGetAccessTokenResult(response);
}
@Override
public
void
onError( int
errorCode, final
String errorMsg) {
Logger.e(errorMsg);
showMessage( "错误信息:
"
+ errorMsg);
//
重新请求授权
loginWeixin(WXEntryActivity. this .getApplicationContext(),
GeneralAppliction.sApi);
}
@Override
public
void
onFailure(IOException e) {
Logger.e(e.getMessage());
showMessage( "登录失败" );
//
重新请求授权
loginWeixin(WXEntryActivity. this .getApplicationContext(),
GeneralAppliction.sApi);
}
});
}
|
8. 使用access_token获取用户信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/**
*
获取用户信息
*
/
private
void
getUserInfo(String access_token, String openid) {
"access_token="
+ access_token +
"&openid="
+ openid;
httpRequest(url,
new
ApiCallback<String>() {
@Override
public
void
onSuccess(String response) {
//
解析获取的用户信息
WXUserInfo
userInfo = mGson.fromJson(response, WXUserInfo. class );
Logger.e( "用户信息获取结果:"
+ userInfo.toString()); }
@Override
public
void
onError( int
errorCode, String errorMsg) {
showMessage( "错误信息:
"
+ errorMsg);
}
@Override
public
void
onFailure(IOException e) {
showMessage( "获取用户信息失败" );
}
});
}
|
通信部分
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
|
private
OkHttpClient mHttpClient = new
OkHttpClient.Builder().build();
private
Handler mCallbackHandler = new
Handler(Looper.getMainLooper());
/**
*
通过Okhttp与微信通信
*
* @param url 请求地址
*
@throws Exception
*/
public
void
httpRequest(String url, final
ApiCallback<String> callback) {
Logger.e( "url:
%s" ,
url);
final
Request request = new
Request.Builder()
.url(url)
.get()
.build();
mHttpClient.newCall(request).enqueue( new
Callback() {
@Override
public
void
onFailure(Call call, final
IOException e) {
if
(callback != null )
{
mCallbackHandler.post( new
Runnable() {
@Override
public
void
run() {
//
请求失败,主线程回调
callback.onFailure(e);
}
});
}
}
@Override
public
void
onResponse(Call call, final
Response response) throws
IOException {
if
(callback != null )
{
if
(!response.isSuccessful()) {
mCallbackHandler.post( new
Runnable() {
@Override
public
void
run() {
//
请求出错,主线程回调
callback.onError(response.code(),
response.message());
}
});
}
else
{
mCallbackHandler.post( new
Runnable() {
@Override
public
void
run() {
try
{
//
请求成功,主线程返回请求结果
callback.onSuccess(response.body().string());
}
catch
( final
IOException e) {
//
异常出错,主线程回调
mCallbackHandler.post( new
Runnable() {
@Override
public
void
run() {
callback.onFailure(e);
}
});
}
}
});
}
}
}
});
}
//
Api通信回调接口
public
interface
ApiCallback<T> {
/**
*
请求成功
*
*
@param response 返回结果
*/
void
onSuccess(T response);
/**
*
请求出错
*
*
@param errorCode 错误码
*
@param errorMsg 错误信息
*/
void
onError( int
errorCode, String errorMsg);
/**
*
请求失败
*/
void
onFailure(IOException e);
}
|
相关推荐
- Salesforce Force.com Site 集成微信公众平台 文本消息处理
- 使用 CocoaPods 给微信集成 SDK 打印收发消息
- 微信公众号VUE项目安卓能请求到数据IOS不能
- 微信公众号VUE项目安卓能请求到数据IOS报NetworkError
- 微信跳一跳纯安卓端实现方法
- springcloud-手写微服务授权模块,集成微信登录授权,公众号关注授权,短信验证码,用户名密码等方式。
- 在线靶场-墨者-电子数据取证1星-安卓手机文件分析取证(微信发送的视频)
- 【第十二篇】微信支付(APP)集成时碰到的问题(.net提示“无权限”、iOS跳转到微信支付页面中间只有一个“确定”按钮)(转)...
- 微信小程序上基于Springboot+mybatis+mysql实现登陆、注册功能(简易)
- 微信深色模式最大的槽点终于被干掉了,这一次安卓用户先享受!
- 光纤跳线检测方法,校园网如何用光纤跳线连接? ...
- win7添加打印机失败