如何在Unity中使用官方SDK实现微信、QQ、微博帐号登录(Android)
发表于2017-02-16
对于一些没有过安卓开发经验的开发者来说,为了实现安卓第三方登陆肯定是费尽了脑汁,不知道从何着手解决,为了让开发者少走弯路,下面就给大家介绍下Unity中使用官方SDK实现微信、QQ、微博帐号登录的方法,一起来看看吧。
一、新建安卓工程并导入jar文件
注意写好自己的包名,微信登录和微博登录都要用到包名获取签名,把获取到的签名上传到开放平台。
填好包名后一直点next就可以了,点击finish完成创建。
创建完成后,新建一个module类,同样写好自己的包名。
二、QQ登录
QQ登录时最简单的一个,因为不需要签名。在qq开放平台下载好sdk,然后copy到libs文件夹下。
点击Add as Library就可以了,微信和微博的jar包导入也是一样,Unity的classes.jar也需要导入,后面就不赘述了。
通过调用Tencent类的login函数发起登录/校验登录态。
该API具有两个作用:
(1)如果开发者没有调用mTencent实例的setOpenId、setAccessToken API,则该API执行正常的登录操作;
(2)如果开发者先调用mTencent实例的setOpenId、setAccessToken API,则该API执行校验登录态的操作。如果登录态有效,则返回成功给应用,如果登录态失效,则会自动进入登录流程,将最新的登录态数据返回给应用。
建议开发者在每次应用启动时调用一次该API(先调用setOpenId、setAccessToken),以确保每次打开应用时用户都是有登录态的。
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 | public class MainActivity extends UnityPlayerActivity { private Tencent mTencent; private BaseUiListener mBaseUiListener= new BaseUiListener(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mTencent = Tencent.createInstance( "你的APPID" , this .getApplicationContext()); } /** * qq登录代码 Unity里调用 */ public void QQlogin() { //登录代码。。。 if (!mTencent.isSessionValid()) { mTencent.login( this , "" , mBaseUiListener); } } /** * qq请求回调 */ private class BaseUiListener implements IUiListener { @Override public void onComplete(Object o) { JSONObject response=(JSONObject)o; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //把请求到的参数传给unity UnityPlayer.UnitySendMessage( "ThirdLoginGameobject" , "QQCallBack" ,o.toString()); } @Override public void onError(UiError uiError) { } @Override public void onCancel() { } } /** * qq登录页面返回处理 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { Tencent.onActivityResultData(requestCode,resultCode,data,mBaseUiListener); } |
然后再mainfest里配置权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
SDK_V2.0引入了AssistActivity,开发者需在androidManifest.xml中注册。代码如下:
1 |
android:theme= "@android:style/Theme.Translucent.NoTitleBar" android:configchanges= "orientation|keyboardHidden|screenSize" >
|
现在就可以成功拉起QQ授权页面并登陆了。
三、微信登录
新建一个名为wxapi的包和WXEntryActivity的类。
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 82 83 84 85 86 87 88 | 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" ; public static WeChatCode mWeChatCode; public WeChatCode getWeChatCode() { return mWeChatCode; } public void setWeChatCode(WeChatCode weChatCode) { mWeChatCode = weChatCode; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 微信事件回调接口注册 MyApplication.sApi.handleIntent(getIntent(), this ); } //微信组件注册初始化 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; } /** * 登录微信 */ public static void loginWeixin(Context context, IWXAPI api, WeChatCode wechatCode) { // 判断是否安装了微信客户端 // if (!api.isWXAppInstalled()) { // Toast.makeText(context.getApplicationContext(), "您还未安装微信客户端!", Toast.LENGTH_SHORT) // .show(); // return; // } mWeChatCode=wechatCode; // 发送授权登录信息,来获取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; mWeChatCode.getResponse(code); break ; } } /** * 返回code的回调接口 */ public interface WeChatCode { void getResponse(String code); } } |
MainActivity中添加如下代码:
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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 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" ; 微信登录 unity中调用该方法 public void weiLogin() { WXEntryActivity.loginWeixin(MainActivity. this , MyApplication.sApi, new WXEntryActivity.WeChatCode() { @Override public void getResponse(String code) { // 通过code获取授权口令access_token getAccessToken(code); Log.i( "获取token成功" ,code.toString()); // 从手机本地获取存储的授权口令信息,判断是否存在access_token,不存在请求获取,存在就判断是否过期 String accessToken = (String) ShareUtils.getValue(MainActivity. this , WEIXIN_ACCESS_TOKEN_KEY, "none" ); String openid = (String) ShareUtils.getValue(MainActivity. this , WEIXIN_OPENID_KEY, "" ); if (! "none" .equals(accessToken)) { // 有access_token,判断是否过期有效 isExpireAccessToken(accessToken, openid); } else { // 没有access_token getAccessToken(code); Log.i( "获取token成功" ,code.toString()); } } }); Log.i( "登录成功" , "aaaaaaaaaaaaaaaaaaaaaaaaaa" ); } /** * 微信登录获取授权口令 */ private void getAccessToken(String code) { "appid=" + AppConst.WEIXIN_APP_ID + "&secret=" + AppConst.WEIXIN_APP_SECRET + "&code=" + code + "&grant_type=authorization_code" ; // 网络请求获取access_token OkHttpUtils. get ().url(url).build().execute( new StringCallback() { @Override public void onError(Call call, Exception e, int id) { e.printStackTrace(); } @Override public void onResponse(String response, int id) { // 判断是否获取成功,成功则去获取用户信息,否则提示失败 processGetAccessTokenResult(response); } }); } /** * 微信登录处理获取的授权信息结果 * * @param response 授权信息结果 */ public void processGetAccessTokenResult(String response) { // 验证获取授权口令返回的信息是否成功 if (validateSuccess(response)) { // 使用Gson解析返回的授权口令信息 // WXAccessTokenInfo tokenInfo = mGson.fromJson(response, WXAccessTokenInfo.class); // 保存信息到手机本地 // saveAccessInfotoLocation(tokenInfo); // 获取用户信息 // getUserInfo(tokenInfo.getAccess_token(), tokenInfo.getOpenid()); } else { // 授权口令获取失败,解析返回错误信息 // WXErrorInfo wxErrorInfo = mGson.fromJson(response, WXErrorInfo.class); } } /** *微信登录获取tokenInfo的WEIXIN_OPENID_KEY,WEIXIN_ACCESS_TOKEN_KEY,WEIXIN_REFRESH_TOKEN_KEY保存到shareprephence中 * @param tokenInfo */ private void saveAccessInfotoLocation(WXAccessTokenInfo tokenInfo) { ShareUtils.saveValue(MyApplication.mContext,WEIXIN_OPENID_KEY,tokenInfo.getOpenid()); ShareUtils.saveValue(MyApplication.mContext,WEIXIN_ACCESS_TOKEN_KEY,tokenInfo.getAccess_token()); ShareUtils.saveValue(MyApplication.mContext,WEIXIN_REFRESH_TOKEN_KEY,tokenInfo.getRefresh_token()); } /** * 验证是否成功 * * @param response 返回消息 * @return 是否成功 */ private boolean validateSuccess(String response) { String errFlag = "errmsg" ; return (errFlag.contains(response) && ! "ok" .equals(response)) || (! "errcode" .contains(response) && !errFlag.contains(response)); } /** * 微信登录判断accesstoken是过期 * * @param accessToken token * @param openid 授权用户唯一标识 */ private void isExpireAccessToken(final String accessToken, final String openid) { "access_token=" + accessToken + "&openid=" + openid; OkHttpUtils. get ().url(url).build().execute( new StringCallback() { @Override public void onError(Call call, Exception e, int id) { } @Override public void onResponse(String response, int id) { if (validateSuccess(response)) { // accessToken没有过期,获取用户信息 getUserInfo(accessToken, openid);
|
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 | //把请求到的数据传递到unity UnityPlayer.UnitySendMessage( "与安卓交互的C#脚本挂载的物体名" , "函数名" ,response.toString()); Toast.makeText(getApplicationContext(),response.toString(),Toast.LENGTH_LONG).show(); } else { // 过期了,使用refresh_token来刷新accesstoken refreshAccessToken(); } } }); } /** * 微信登录刷新获取新的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; // 请求执行 OkHttpUtils. get ().url(url).build().execute( new StringCallback() { @Override public void onError(Call call, Exception e, int id) { System. out .println( "刷新获取新的access_token信息失败!!!" ); // 重新请求授权 weiLogin(); } @Override public void onResponse(String response, int id) { // 判断是否获取成功,成功则去获取用户信息,否则提示失败 processGetAccessTokenResult(response); } }); } /** * 微信token验证成功后,联网获取用户信息 * @param access_token * @param openid */ private void getUserInfo(String access_token, String openid) { "access_token=" + access_token + "&openid=" + openid; OkHttpUtils. get ().url(url).build().execute( new StringCallback() { @Override public void onError(Call call, Exception e, int id) { System. out .println( "联网获取用户信息失败!!!" ); } @Override public void onResponse(String response, int id) { // 解析获取的用户信息 // WXUserInfo userInfo = mGson.fromJson(response, WXUserInfo.class); System. out .println( "获取用户信息String是::::::" +response); } }); } |
写了一个类来存APPID和SECRET
新建一个MyApplication类来初始化微信登录和网络请求
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 | public class MyApplication extends Application { public static IWXAPI sApi; public static Context mContext; @Override public void onCreate() { super.onCreate(); mContext= this ; //初始化微信 sApi = WXEntryActivity.initWeiXin( this , AppConst.WEIXIN_APP_ID); initOkHttp(); } //封装okhttp框架的初始化配置 private void initOkHttp() { HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory( null , null , null ); CookieJarImpl cookieJar = new CookieJarImpl( new PersistentCookieStore(getApplicationContext())); OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor( new LoggerInterceptor( "TAG" )) .cookieJar(cookieJar) .connectTimeout(20000L, TimeUnit.MILLISECONDS) .readTimeout(20000L,TimeUnit.MILLISECONDS) .writeTimeout(20000L,TimeUnit.MILLISECONDS) .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager) //其他配置 .build(); OkHttpUtils.initClient(okHttpClient); } } |
mainfest里初始化MyApplication
只要填写正确的APPID以及签名正确,就可以拉起微信登录页面了。
四、微博登录
微博登录不光要导入jar包,libs里面的.so文件也要导入,这里只讲客户端授权。
从官方demo中复制AccessTokenKeeper这个类到你的工程中。写一个Constance类来存APPKEY,把这三个类也从官方的demo中复制过来,下面贴上我删减后的代码:
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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | public class WBAuthActivity extends Activity { private static final String TAG = "weibosdk" ; private AuthInfo mAuthInfo; /** 封装了 "access_token","expires_in","refresh_token",并提供了他们的管理功能 */ private Oauth2AccessToken mAccessToken; /** 注意:SsoHandler 仅当 SDK 支持 SSO 时有效 */ private SsoHandler mSsoHandler; /** * @see {@link Activity#onCreate} */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAuthInfo = new AuthInfo( this , Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE); mSsoHandler = new SsoHandler(WBAuthActivity. this , mAuthInfo); // SSO 授权, 仅客户端 WBLogin(); // 从 SharedPreferences 中读取上次已保存好 AccessToken 等信息, // 第一次启动本应用,AccessToken 不可用 mAccessToken = AccessTokenKeeper.readAccessToken( this ); if (mAccessToken.isSessionValid()) { updateTokenView( true ); } } /** * 当 SSO 授权 Activity 退出时,该函数被调用。 * * @see {@link Activity#onActivityResult} */ @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // SSO 授权回调 // 重要:发起 SSO 登陆的 Activity 必须重写 onActivityResults // ++++++++++++++++++ //如果是sso授权登陆,必须先执行下面的回调,然后才会执行监听器里的 回调 if (mSsoHandler != null ) { mSsoHandler.authorizeCallBack(requestCode, resultCode, data); } } private void WBLogin() { mSsoHandler.authorizeClientSso( new AuthListener()); } /** * 微博认证授权回调类。 * 1. SSO 授权时,需要在 {@link #onActivityResult} 中调用 {@link SsoHandler#authorizeCallBack} 后, * 该回调才会被执行。 * 2. 非 SSO 授权时,当授权结束后,该回调就会被执行。 * 当授权成功后,请保存该 access_token、expires_in、uid 等信息到 SharedPreferences 中。 */ class AuthListener implements WeiboAuthListener { @Override public void onComplete(Bundle values) { // 从 Bundle 中解析 Token mAccessToken = Oauth2AccessToken.parseAccessToken(values); UnityPlayer.UnitySendMessage( "ThirdLoginGameobject" , "WeiboCallBack" ,values.toString()); //从这里获取用户输入的 电话号码信息 // String phoneNum = mAccessToken.getUid(); if (mAccessToken.isSessionValid()) { // 显示 Token updateTokenView( false ); } else { // 以下几种情况,您不会收到 Code: // 1. 当您未在平台上注册的应用程序的包名与签名时; // 2. 当您注册的应用程序包名与签名不正确时; // 3. 当您在平台上注册的包名和签名与您当前测试的应用的包名和签名不匹配时。 } } @Override public void onCancel() { } @Override public void onWeiboException(WeiboException e) { } } /** * 显示当前 Token 信息。 * * @param hasExisted 配置文件中是否已存在 token 信息并且合法 */ private void updateTokenView(boolean hasExisted) { } } |
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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | public class WBAuthCodeActivity extends Activity { private static final String TAG = "WBAuthCodeActivity" ; /** * WeiboSDKDemo 程序的 APP_SECRET。 * 请注意:请务必妥善保管好自己的 APP_SECRET,不要直接暴露在程序中,此处仅作为一个DEMO来演示。 */ /** 通过 code 获取 Token 的 URL */ /** 微博 Web 授权接口类,提供登陆等功能 */ private AuthInfo mAuthInfo; /** 获取到的 Code */ private String mCode; /** 获取到的 Token */ private Oauth2AccessToken mAccessToken; /** * @see {@link Activity#onCreate} */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_auth_code); // 初始化微博对象 mAuthInfo = new AuthInfo( this , Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE); } /** * 微博认证授权回调类。 */ class AuthListener implements WeiboAuthListener { @Override public void onComplete(Bundle values) { if ( null == values) { return ; } String code = values.getString( "code" ); if (TextUtils.isEmpty(code)) { return ; } mCode = code; } @Override public void onCancel() { } @Override public void onWeiboException(WeiboException e) { } } /** * 异步获取 Token。 * * @param authCode 授权 Code,该 Code 是一次性的,只能被获取一次 Token * @param appSecret 应用程序的 APP_SECRET,请务必妥善保管好自己的 APP_SECRET, * 不要直接暴露在程序中,此处仅作为一个DEMO来演示。 */ public void fetchTokenAsync(String authCode, String appSecret) { WeiboParameters requestParams = new WeiboParameters(Constants.APP_KEY); requestParams.put(WBConstants.AUTH_PARAMS_CLIENT_ID, Constants.APP_KEY); requestParams.put(WBConstants.AUTH_PARAMS_CLIENT_SECRET, appSecret); requestParams.put(WBConstants.AUTH_PARAMS_GRANT_TYPE, "authorization_code" ); requestParams.put(WBConstants.AUTH_PARAMS_CODE, authCode); requestParams.put(WBConstants.AUTH_PARAMS_REDIRECT_URL, Constants.REDIRECT_URL); // 异步请求,获取 Token new AsyncWeiboRunner(getApplicationContext()).requestAsync(OAUTH2_ACCESS_TOKEN_URL, requestParams, "POST" , new RequestListener() { @Override public void onComplete(String response) { // 获取 Token 成功 Oauth2AccessToken token = Oauth2AccessToken.parseAccessToken(response); if (token != null && token.isSessionValid()) { mAccessToken = token; String date = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss" ).format( new java.util.Date(mAccessToken.getExpiresTime())); String format = token.toString(); } else { } } @Override public void onWeiboException(WeiboException e) { } }); } } |
WBShareMainActivity继承Activity为空即可,在MainActivity的onCreate里写上LogUtil.sIsLogEnable = true;
MainActivity里加上微博登录代码
1 2 3 4 5 | //微博登录 Unity里调用 public void WBLogin() { startActivity( new Intent(MainActivity. this , WBAuthActivity. class )); } |
mainfest里加上 即可。
把MainActivity里的代码整合到一起后,build
把libs里的classes.jar删掉,把红框圈起来的classes.jar拖到libs文件夹里,然后把libs,res和AndroidMainfest这三个文件拖到Unity工程的Plugins/Android文件夹下。
然后在unity创建三个按钮并添加点击事件
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 | public void OnQQBtnClick(ButtonScript obj, object args, object param1, object param2) { #if UNITY_IPHONE c_thirdQQLogin(); #elif UNITY_ANDROID AndroidJavaClass jc = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ); AndroidJavaObject jo = jc.GetStatic "currentActivity" ); jo.Call( "QQlogin" ); #endif } public void OnWeChatBtnClick(ButtonScript obj, object args, object param1, object param2) { #if UNITY_IPHONE c_thirdLogin(); #elif UNITY_ANDROID AndroidJavaClass jc = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ); AndroidJavaObject jo = jc.GetStatic "currentActivity" ); jo.Call( "weiLogin" ); #endif } public void OnWeiboBtnClick(ButtonScript obj, object args, object param1, object param2) { #if UNITY_IPHONE c_thirdWeiboLogin(); #elif UNITY_ANDROID AndroidJavaClass jc = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ); AndroidJavaObject jo = jc.GetStatic "currentActivity" ); jo.Call( "WBLogin" ); #endif } |
发布安卓应用的时候记得签名,不然微信和微博登录会报错。