现在微信越来越火了,基本上每一个应用都会有一个微信登陆,于是跟同事商量着是不是写一个SDK出来,方便以后开发使用。写出来以后,本着开源的想法,还是分享给大家。本人的第二篇博客,如果哪里写的不好,请轻喷.....
废话不多说,直接进入整体。大家都知道,集成微信的功能,都要从微信开放平台上下载一个名为libammsdk.jar的文件,这个就不用多说了吧,大家上微信开放平台上下载就可以了。我自己封好的jar包链接如下:http://download.csdn.net/detail/q_probably/9714162
,大家只需要把这两个jar包放到自己的项目中,然后在项目的报名下新建一个wxapi的包名,然后在该报名下新建一个WXEntryActivity类,让这个类继承我的jar包中的WX_CallbackActivity类就可以了。要注意的是,这里的wxapi的包,必须建在主包名的下面。(一定要注意,不然不会走微信的回调)。然后在我们的配置文件中增加下面的代码:
<activity android:name=".wxapi.WXEntryActivity" android:exported="true"/>
重点来了,在做完上述准备工作之后,我们只需要一行代码,就可以集成了,我将自己测试的Demo中的代码贴出来:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textview); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { WeChatLogin.getWXInfo(MainActivity.this, "wxdc1e388c3822c80b", "3baf1193c85774b3fd9d18447d76cab0", new LoginInfoCallback() { @Override public void onSuccess(LOGIN login, final String s) { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { textView.setText(s); } }); } @Override public void onError(LOGIN login, Throwable throwable) { textView.setText("错误了"); } }); } }); }其实很简单,我的MainActivity的布局文件中只有一个Button和一个Textview,当我点击Button的时候,就会调用WechatLogin这个类中的getWxInfo()方法,这个方法中有四个参数:第一个是 上下文,因为我在MainActivity中,所以我这里传的是MainActivity.this。第二个参数,是我们在微信开放平台注册的app_id了,这个不用多说吧。第三个参数跟第二个差不多,是和app_id对应的app_secret这个也不用多说。第四个参数呢,是我自己写的一个监听,当我们调起微信授权登陆页面点击确定登陆以后,最后会走到这个回调里面,然后我们就可以拿到微信得数据了。当然了,这里面肯定涉及到了网络请求,所以是在子线程中进行的,如果想要更新UI的话,还是需要在主线程中进行的,也就是runOnUiThread()方法了。除此之外,权限也是必不可少的嘛,
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>下面说一下大家可能遇到的问题,因为Android从6.0开始,权限就需要动态的去配置了,我在写的时候,为了省事,就将gradle文件做了以下的调整,
compileSdkVersion 22
minSdkVersion 16 targetSdkVersion 22
compile 'com.android.support:appcompat-v7:22.0.0'
这里大家可以看得懂吧,我把sdkversion限定在了22,这样就不会出现权限的问题了。如果你的是23,你需要自己去动态的处理一下权限了。
后面有时间的话,我会增加动态权限的申请,暂时就先这样了。
下面的话,我把思路和代码跟大家顺一下,如果你感兴趣的话,可以看一下,其实也没什么,里面稍微复杂的应该就是回调了,相信懂回调的朋友看起来会很简单:
public class WX_CallbackActivity extends Activity implements IWXAPIEventHandler { private static LoginReqCallback _reqCallbrack; private static IWXAPI iwxapi; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); iwxapi.handleIntent(getIntent(),this); } @Override public void onReq(BaseReq baseReq) { } @Override public void onResp(BaseResp baseResp) { int errorCode = baseResp.errCode; switch (errorCode) { case BaseResp.ErrCode.ERR_OK: //用户同意 String code = ((SendAuth.Resp) baseResp).code; if (_reqCallbrack != null) { _reqCallbrack.complete(code); } finish(); break; case BaseResp.ErrCode.ERR_AUTH_DENIED: //用户拒绝 if (_reqCallbrack != null) { _reqCallbrack.denied(); } break; case BaseResp.ErrCode.ERR_USER_CANCEL: //用户取消 if (_reqCallbrack != null) { _reqCallbrack.cancel(); } break; default: break; } } /** * 向微信发送登陆请求 * @param reqCallbrack 请求的回调 * @param app_id 在微信开放平台注册的app id * */ public static void sendReq(Context context,String app_id, LoginReqCallback reqCallbrack) { iwxapi = WXAPIFactory.createWXAPI(context,app_id,true); iwxapi.registerApp(app_id); if( !iwxapi.isWXAppInstalled()){ Toast.makeText(context, "请先安装微信应用", Toast.LENGTH_SHORT).show(); return; } _reqCallbrack = reqCallbrack; SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat_sdk_demo_test"; iwxapi.sendReq(req); } }
这里面就是让大家继承的那个activity的所有代码了,在这里我实现了IWXAPIEventHandler接口,在微信得官方文档上是WXEntryActivity实现的该接口,按照继承的思想,是一样的拉。在这里,除了必须要实现的onReq和onResp方法外,我写了一个sendReq()方法,参数分别是context上下文,app_id,和一个回调接口,该接口中有三个方法,如下所示
public interface LoginReqCallback { public void complete(String code); public void denied(); public void cancel(); }其中的三个方法分别对应,用户授权,拒绝和取消。在该类里面,首先我拿到了sendReq()方法传过来的回到接口,并将它赋给我类中的成员变量,这样当用户点击不同的操作的时候,会在onResp方法中,调用接口的不同方法,来将用户进行的操作传递给实现该接口的方法中,如果用户同意,我们就可以拿到code了。
import android.content.Context; import android.util.Log; import android.widget.Toast; import com.llk.wechatlogin.activity.WX_CallbackActivity; import com.llk.wechatlogin.data.WeChatTokenEntity; import com.llk.wechatlogin.llk_enum.LOGIN; import com.llk.wechatlogin.llk_interface.HttpCallbackListener; import com.llk.wechatlogin.llk_interface.LoginInfoCallback; import com.llk.wechatlogin.llk_interface.LoginReqCallback; import com.llk.wechatlogin.utils.HttpUtil; import org.json.JSONException; import org.json.JSONObject; /** * Created by QQY on 2016/12/16 0016. * 微信登陆,调用微信客户端登陆 */ public class WeChatLogin { public WeChatLogin(){} /** * 获取微信授权,得到微信用户的信息 * * */ public static void getWXInfo(final Context context, final String app_id, final String app_secret, final LoginInfoCallback loginInfoCallback) { WX_CallbackActivity.sendReq(context,app_id, new LoginReqCallback() { @Override public void complete(String code) { Toast.makeText(context,"用户同意",Toast.LENGTH_SHORT).show(); Log.e("---------->","用户同意"); getToken(app_id,app_secret,code,loginInfoCallback); } @Override public void denied() { Toast.makeText(context,"用户拒绝",Toast.LENGTH_SHORT).show(); loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("您已拒绝")); } @Override public void cancel() { Toast.makeText(context,"用户取消",Toast.LENGTH_SHORT).show(); loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("成功取消")); } }); } /** * 根据code获取token * @param code 微信登陆必须的code * @param loginInfoCallback 获取微信用户信息的回调 * */ private static void getToken(String app_id, String app_secret, String code, final LoginInfoCallback loginInfoCallback) { final String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + app_id + "&secret=" + app_secret + "&code=" + code + "&grant_type=authorization_code"; //发送网络请求 HttpUtil.sendHttpRequest(url, new HttpCallbackListener() { @Override public void onFinish(String response) { try { JSONObject jsonObject = new JSONObject(response); if (jsonObject.optInt("errcode",-1) == -1) { WeChatTokenEntity entity = new WeChatTokenEntity(); entity.access_token=jsonObject.optString("access_token",""); entity.openid=jsonObject.optString("openid",""); //调用获取微信信息的方法 getInfo(entity,loginInfoCallback); } } catch (JSONException e) { e.printStackTrace(); } } @Override public void onErrot(Exception e) { loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常")); } }); } /** *获取微信用户信息 * @param entity Token相关实体类 * @param loginInfoCallback 回调接口 * */ private static void getInfo(WeChatTokenEntity entity, final LoginInfoCallback loginInfoCallback) { Log.e("------------>toiken",entity.access_token); String accessToken = entity.access_token; String openId = entity.openid; final String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId; HttpUtil.sendHttpRequest(url, new HttpCallbackListener() { @Override public void onFinish(String response) { try { JSONObject json = new JSONObject(response); if (json.optInt("errcode",-1) == -1) { if (loginInfoCallback != null) { Log.e("------------->",response); loginInfoCallback.onSuccess(LOGIN.WEIXIN,response); }else { if (loginInfoCallback != null) { loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常")); } } } } catch (JSONException e) { if (loginInfoCallback != null) { loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常")); } } } @Override public void onErrot(Exception e) { loginInfoCallback.onError(LOGIN.WEIXIN,new Throwable("请求异常")); } }); } }
在上面我们说过,只需要调用WechatLogin中degetWxInfo()方法就可以,这个方法中的参数,大家自己看代码就可以了,我就不多说了。在这个方法的一开始,我们调用了
WX_CallbackActivity.sendReq(context,app_id, new LoginReqCallback()方法,这里new 出了一个LoginReqCallback()接口,这样就对应上上面所说的了,当用户授权以后,我们实现的complete()方法就可以拿到code了,拿到code以后,我们调用了getToken()方法来获取token。大家可以看到,我们在getWXInfo()方法传进来的LoginInfoCallback接口会一直传到最后面的getInfo()方法中,另外HttpCallBackListener回调接口是我们在向微信请求数据的监听回调,在我们发送网络请求的时候,也就是
HttpUtil.sendHttpRequest(url, new HttpCallbackListener()
这一行代码。该接口中两个方法,分别对应请求成功和请求失败,当我们请求成功以后,我们调用了从最上面的getWXInfo()方法中一直传过来的LoginInfoCallback接口中的onSuccess()方法,将我们请求到的数据传出去。这样我们在最开始调用getWXInfo()方法时候new 出来的 LofinInfoCallback接口实现的两个方法中,就可以拿到数据了。
基本的思路就是这样了,我把剩下的代码都给大家贴出来
/** * Created by QQY on 2016/12/17 0017. * 网络请求的回调 */ public interface HttpCallbackListener { void onFinish(String response); void onErrot(Exception e); }
public interface LoginInfoCallback { void onSuccess(LOGIN type, String response); void onError(LOGIN type, Throwable text); }
public enum LOGIN { WEIXIN, SINA_WEIBO, QQ, PHONE_NUMBER }
public class WeChatTokenEntity { public String access_token ; // 接口调用凭证 public long expires_in; //接口调用凭证超时时间,单位(秒) public String refresh_token ; // 用户刷新access_token public String openid ; // 授权用户唯一标识 public String scope ; // 用户授权的作用域,使用逗号(,)分隔 public String unionid; // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 }
public class HttpUtil { /** * 发送一个网络请求的方法 * @param address 要访问的地址 * @param listener 回调接口 * */ public static void sendHttpRequest(final String address, final HttpCallbackListener listener) { //网络请求为耗时操作,在子线程中运行 new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream in = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } if (listener != null) { //回调onFininsh()方法 listener.onFinish(response.toString()); } } catch (MalformedURLException e) { listener.onErrot(e); } catch (IOException e) { listener.onErrot(e); } finally { if (connection != null) { //断开连接 connection.disconnect(); } } } }).start(); } }
好了,就到这里了,如果大家有什么疑问的话,可以留言问我。我看到的话会尽量帮大家解决。重申一下,本人写的第二篇博客,写的不好的地方,希望大家理解,如果不喜欢实在想喷的话,请轻喷。