首先到微信官网注册:https://open.weixin.qq.com/cgi-bin/frame?t=home/app_tmpl&lang=zh_CN
这里需要注意一点的是,app的签名。我们在android studio获取签名的格式如下:
MD5: 97:CF:28:B9:D6:8E:E1:2D:CB:78:4F:7B:C6:C6:E4:F8
但官网需要的应用签名必须小写且无符号,所以应该改为:
97cf28b9d68ee12dcb784f7bc6c6e4f8。
微信获取签名的工具:点击下载
1.首先在项目根目录下建一个
wxapi包以及WXEntryActivity类,包名和类名必须同上。
在manifest配置如下:
<!--微信登录配置--> <activity android:name=".wxapi.WXEntryActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:exported="true" /> </application>
2.在主界面添加如下代码:
/*微信登录*/ private void wxLogin() { //通过WXAPIFactory工厂获取IWXApI的示例 IWXAPI api = WXAPIFactory.createWXAPI(this, Constant.APP_ID_WX, true); //将应用的appid注册到微信 api.registerApp(Constant.APP_ID_WX); SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; // req.scope = "snsapi_login";//提示scope参数错误或者没有scope权;限用snsapi_base提示没权限 req.state = "wechat_sdk_微信登录"; //用于保持请求和回调的状态,授权请求后原样带回给第三方。 // 该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验。 api.sendReq(req); }
3.WXEntryActivity详解:
public class WXEntryActivity extends AppCompatActivity implements IWXAPIEventHandler { /** * 微信登录相关 */ private IWXAPI api; private String tag = "WXEntryActivity"; public static String access_token = "access_token"; public static String openid = "openid"; public static final String ACTION_GETWX = "com.bs.utown.get_wx_msg";//用于广播的action @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //通过WXAPIFactory工厂获取IWXApI的示例 api = WXAPIFactory.createWXAPI(this, Constant.APP_ID_WX, true); //将应用的appid注册到微信 api.registerApp(Constant.APP_ID_WX); Logs.d("------------------------------------"); //注意: //第三方开发者如果使用透明界面来实现WXEntryActivity,需要判断handleIntent的返回值,如果返回值为false, // 则说明入参不合法未被SDK处理,应finish当前透明界面,避免外部通过传递非法参数的Intent导致停留在透明界面,引起用户的疑惑 try { boolean result = api.handleIntent(getIntent(), this); if (!result) { Logs.i("参数不合法,未被SDK处理,退出"); finish(); } } catch (Exception e) { e.printStackTrace(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); api.handleIntent(data, this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); finish(); } @Override public void onReq(BaseReq baseReq) { Logs.d(tag + "74 baseReq:" + JSON.toJSONString(baseReq)); } @Override public void onResp(BaseResp baseResp) { Logs.w(tag + "78 " + JSON.toJSONString(baseResp)); Logs.i(tag + "79 " + baseResp.errStr + "," + baseResp.openId + "," + baseResp.transaction + "," + baseResp.errCode); String code = ((SendAuth.Resp) baseResp).code; String result = ""; switch (baseResp.errCode) { case BaseResp.ErrCode.ERR_OK: result = "发送成功"; /*现在请求获取数据 access_token https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code*/ OkHttpUtils.get().url("https://api.weixin.qq.com/sns/oauth2/access_token") .addParams("appid", Constant.APP_ID_WX) .addParams("secret", Constant.APP_SECRET_WX) .addParams("code", code) .addParams("grant_type", "authorization_code") .build() .execute(new StringCallback() { @Override public void onError(okhttp3.Call call, Exception e, int id) { Logs.e(tag + "113 请求错误.." + e+" "+id+" \n "+call); } @Override public void onResponse(String response, int id) { Logs.v(tag + "118 response:" + response); String tokenstr = null, openidstr = null; try { JSONObject jo = new JSONObject(response); tokenstr = jo.getString(access_token); openidstr = jo.getString(openid); Logs.i(tag + " 116 " + tokenstr + " " + openidstr); } catch (JSONException e) { e.printStackTrace(); } /*通过广播将access_token和openid返回登录界面*/ LocalBroadcastManager.getInstance(WXEntryActivity.this).sendBroadcast(new Intent(ACTION_GETWX). putExtra(access_token, tokenstr).putExtra(openid, openidstr)); } }); break; case BaseResp.ErrCode.ERR_USER_CANCEL: result = "发送取消"; break; case BaseResp.ErrCode.ERR_AUTH_DENIED: result = "发送被拒绝"; break; case BaseResp.ErrCode.ERR_BAN: result = "签名错误"; break; default: result = "发送返回"; break; } Toast.makeText(WXEntryActivity.this, result, Toast.LENGTH_LONG).show(); finish(); } }
3.1首先来看,如果你的签名无效返回的数据如下:
WXEntryActivity78 {"errCode":-6,"openId":"","type":1}
我们首先来看这个
BaseResp.ErrCode
int ERR_BAN = -6;签名错误
其他几种错误格式
static int ERR_AUTH_DENIED 认证被否决 static int ERR_COMM 一般错误 static int ERR_OK 正确返回 static int ERR_SENT_FAILED 发送失败 static int ERR_UNSUPPORT 不支持错误 static int ERR_USER_CANCEL 用户取消
3.2SendAuth.Resp详解
我们可以看出继承自baseResp
{ "code":"0712DRee0kzwiz13fUce0900feRet", "country":"CN", "errCode":0, "lang":"zh_CN", "state":"wechat_sdk_微信登录", "type":1, "url":"wxb363a9ff53731258://oauth?code=0712DRee0kzwiz13fUce0900fe02DRet&ate=wechat_sdk_%E5%BE%AE%E4%BF%A1%E7%99%BB%E5%BD%95" } 解释: errCode: //ERR_OK = 0(用户同意) ERR_AUTH_DENIED = -4(用户拒绝授权 ERR_USER_CANCEL = -2(用户取消) code:用户换取access_token的code,仅在ErrCode为0时有效 state:第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用sendReq时传入,由微信终端回传,state字符串长度不能超过1K lang:微信客户端当前语言 country:微信用户当前国家信息
3.3获取access_token和openid
获取的地址:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数说明:
appid:应用唯一标识,在微信开放平台提交应用审核通过后获得
secret:应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
code:填写第一步获取的code参数
grant_type:固定值,写authorization_code
返回结果说明:
{ "access_token":"hSTsG7nq8e0yEFhOZFT-wAdTsjT9jC0AYvGRiqGwwR6Hko99o_mmYR8KO18kMxeDOz33d9tnBhMzu_NLsIha2HqvTm1OGPL1weBdvXZVFFc", "expires_in":7200, "refresh_token":"AeN69M27vttqCedxoIOSeY6cxvbt1N584HjEOclUXtNWxRaZWgmtfvn2jWIDX4tq5t-7Btlc1UkEyyFhV7HVIMXe-V6RPjoZdF525vLzev8", "openid":"olmt4wfxS21G4VeeVX16_zUhZezY", "scope":"snsapi_userinfo", "unionid":"o5aWQwAa7niCIXhAIRBOwglIJ7UQ" }
access_token:接口调用凭证
expires_in :access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
3.4刷新或续期access_token使用
接口说明
access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种:
1.若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;
2.若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。
refresh_token拥有较长的有效期(30天),当refresh_token失效的后,需要用户重新授权,所以,请开发者在refresh_token即将过期时(如第29天时),进行定时的自动刷新并保存好它。
请求方法
使用/sns/oauth2/access_token接口获取到的refresh_token进行以下接口调用:
http请求方式: GET
参数说明
参数 是否必须 说明
appid 是 应用唯一标识
grant_type 是 填refresh_token
refresh_token 是 填写通过access_token获取到的refresh_token参数
4.接收数据
/*通过广播将access_token和openid返回登录界面*/ LocalBroadcastManager.getInstance(WXEntryActivity.this).sendBroadcast(new Intent(ACTION_GETWX). putExtra(access_token, tokenstr).putExtra(openid, openidstr));
我们可以看到我在WXEntryActivity中添加了用接收数据的广播,最主要是通过openid和access_token获取个人信息。
4.1首先在登录的界面添加接收的广播:
/*创建用于接收数据的广播*/ private BroadcastReceiver wxReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WXEntryActivity.ACTION_GETWX)) { wx_access_token = intent.getStringExtra(WXEntryActivity.access_token); wx_openid = intent.getStringExtra(WXEntryActivity.openid); getWxUserInfo(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); /*注册微信广播*/ IntentFilter filter = new IntentFilter(WXEntryActivity.ACTION_GETWX); LocalBroadcastManager.getInstance(this).registerReceiver(wxReceiver, filter);
4.2请求个人信息的方式如下:
/*获取WX的用户信息*/ private void getWxUserInfo() { //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID OkHttpUtils.get() .url("https://api.weixin.qq.com/sns/userinfo") .addParams("access_token", wx_access_token) .addParams("openid", wx_openid)//openid:授权用户唯一标识 .build() .execute(new StringCallback() { @Override public void onError(okhttp3.Call call, Exception e, int id) { Logs.e(tag + "141获取错误 " + e + " " + id + " " + call); } @Override public void onResponse(String response, int id) { Logs.i(tag + "144 " + response + " " + id); DialogNotileUtil.show(LoginActivity.this, response); } }); }
4.3返回的数据: