神刀安全网

什么,集成微信登录只要三行代码

对你没有看错,不是标题党,真的只要三行代码,先上结论代码:

  1. 在Application的onCreate中写:
    // GeneralAppliction.java public static IWXAPI sApi; @Override public void onCreate() {  super.onCreate();  sApi = WXEntryActivity.initWeiXin(this, AppConst.WEIXIN_APP_ID); }
  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. 在开放平台注册创建应用,申请登录权限

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

什么,集成微信登录只要三行代码
Paste_Image.png

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

什么,集成微信登录只要三行代码
Paste_Image.png

此处应用签名我使用的是线上的key的md5,关于这个需要注意的问题可以看我的另外一篇文章:Android的签名总结

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

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

什么,集成微信登录只要三行代码
微信目录所放的正确位置.png

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

总结

集成的详细描述就这样,至于获取的用户信息,小伙伴们应该知道后续自己业务的需求,该怎么处理了。

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 什么,集成微信登录只要三行代码

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址