欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android集成微信登录的步骤详解

程序员文章站 2024-03-05 19:10:49
一、首先在application的oncreate中写: // generalappliction.java public static iwxapi sa...

一、首先在application的oncreate中写:

// generalappliction.java
public static iwxapi sapi;
@override
public void oncreate() {
 super.oncreate();
 sapi = wxentryactivity.initweixin(this, appconst.weixin_app_id);
}

二、在需要登录的地方添加:

// 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. 在开放平台注册创建应用,申请登录权限

这一步其实不用怎么讲,无法就是在上注册一个账号,然后创建移动应用。

Android集成微信登录的步骤详解

需要注意的是:应用签名的部分

Android集成微信登录的步骤详解

此处应用签名我使用的是线上的key的md5,关于这个需要注意的问题可以看:android的签名总结

2. 下载sdk,拷贝相关文件到项目工程目录

开发工具包(sdk)的下载:可以使用微信分享、登录、收藏、支付等功能需要的库以及文件

示例demo

下载后把libammsdk.jar文件拷贝到as工程的libs目录,并把示例demo里源文件目录下的wxapi目录整个拷贝到,工程目录的src下的根包下:

Android集成微信登录的步骤详解

如果wxapi这个文件夹放的位置不对,讲无法登录,微信sdk无法找到登录的activity授权功能。然后在manifest.xml里面加入:

<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对象方便操作):

@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中:

// 实现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参数,进一步加强自身授权登录的安全性。

这样客户端使用的地方只要:

wxentryactivity.loginweixin(mainactivity.this, generalappliction.sapi);

5. 通过code获取授权口令access_token

我们在onresp的回调方法中获取了code,然后通过code获取授权口令access_token:

/** 
* 获取授权口令 
*/
private void getaccesstoken(string code) { 
 string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
 "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是否登录过或者过期的问题:

// 从手机本地获取存储的授权口令信息,判断是否存在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);
}

判断授权口令是否有效:

/** 
* 判断accesstoken是过期 
* @param accesstoken token 
* @param openid 授权用户唯一标识 
*/
private void isexpireaccesstoken(final string accesstoken, final string openid) {
 string url = "https://api.weixin.qq.com/sns/auth?" + 
 "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来刷新

/**
 * 刷新获取新的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请求地址
 string url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?" +
 "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获取用户信息

/**
 * 获取用户信息
 *
/
private void getuserinfo(string access_token, string openid) {
 string url = "https://api.weixin.qq.com/sns/userinfo?" +
 "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("获取用户信息失败");
 }
 });
}

通信部分

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);
}

总结

集成的详细描述就这样,至于获取的用户信息,小伙伴们应该知道后续自己业务的需求,该怎么处理了。以上就是本文的全部内容了,希望能对大家的学习或者工作带来一定的帮助,如果有疑问大家可以留言交流。