Android第三方登录

项目中不泛使用第三方登录 常用的有QQ、新浪微博、微信等

原理基本都是一样的,就是客户端通过按钮去点击 吊起第三方应用AIDL等用第三方账号密码授权 确认授权后返回token/code等唯一标识(证明这个这个第三方账号是你本人)的字符串,把字符串在客户端按type区分,如:手机登录type=0,qq登录type=1,微信登录type=2……

然后把这个唯一标识和type发给服务器去校验 服务器获取第三方账号的个人信息(头像/昵称等)存到数据库,分配应用内唯一的uid,然后返回表明注册成功的json(如

{ret:true,user:{用户信息}}

),客户端解析后确认登录成功,把用户信息存到本地,这样下次客户端再登录的时候就不用去重新登录了。。当然token是有有效期的,主要看服务器怎么去处理,当然一般都不会去处理。。。


下面直接贴代码,主要讲解QQ,新浪微博,微信的客户端操作,因为主要是说明实际操作方法 像友盟,ShareSDK集成好的直接看文档就行,这里说的是没集成过的原生第三方。

首先就是导入jar包,微信是libammsdk.jar/QQ是open_sdk_XXXX.jar/微博是weibosdkcore_xxxx.jar

同时微信需要在项目主包内导入wxapi.WXEntryActivity

首先需要处理清单文件

[html]  view plain  copy
  1.  <activity  
  2.             android:name="com.tencent.tauth.AuthActivity"  
  3.             android:launchMode="singleTask"  
  4.             android:noHistory="true" >  
  5.             <intent-filter>  
  6.                 <action android:name="android.intent.action.VIEW" />  
  7.   
  8.                 <category android:name="android.intent.category.DEFAULT" />  
  9.                 <category android:name="android.intent.category.BROWSABLE" />  
  10.   
  11.                 <data android:scheme="'tencent'+在腾讯开发者平台获取的tencentid,如tencent12345678" />  
  12.             </intent-filter>  
  13.         </activity>  
  14.         <activity  
  15.             android:name="com.tencent.connect.common.AssistActivity"  
  16.             android:configChanges="orientation|keyboardHidden"  
  17.             android:screenOrientation="portrait"  
  18.             android:theme="@android:style/Theme.Translucent.NoTitleBar" />  
  19.   
  20.         <!-- 必须注册在微博授权,分享微博时候用到 -->  
  21.         <activity  
  22.             android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"  
  23.             android:configChanges="keyboardHidden|orientation"  
  24.             android:exported="false"  
  25.             android:windowSoftInputMode="adjustResize" />  
  26. <span style="white-space:pre">    </span><activity  
  27.             android:name=".wxapi.WXEntryActivity"  
  28.             android:configChanges="keyboardHidden|orientation|screenSize"  
  29.             android:exported="true"  
  30.             android:screenOrientation="portrait"  
  31.             android:theme="@android:style/Theme.Translucent.NoTitleBar" />  
然后写两个工具类 Settings和Global ,Settings存储SharePreference对象 用户用户的读取

比如saveUser() getUser() saveCurrentUser() getCurrentUser()这个方法就不多说了 主要看自己的实现
然后是初始化操作 比如首先进入MainActivity 在onCreate里初始化IWXAPI对象 然后调用getCurrentUser() 如果获取为null或者为-1(以uid存储)那么就直接跳转到登录页

如果登录后有操作就startActivityResult或者发广播..

基本原理就是这样

----------------------------


然后建立一个与账号操作相关的基类Activity(为什么与账号相关?因为应用内有可能不只登录会用到这个类 有可能会有账号绑定等页面 这时候就省的去重复写方法了。。)

[java]  view plain  copy
  1. public class AuthenticatorActivity extends BaseActivity implements WeiboAuthListener, IUiListener {  
  2.     public static final int EXISTED_USER_ERROR = 2005;  
  3.   
  4.     private static final String TAG = AuthenticatorActivity.class.getName();  
  5.   
  6.     protected static final int VALUE_APP = 1;  
  7.   
  8.     protected static final int VALUE_SINA = 2;  
  9.   
  10.     protected static final int VALUE_QQ = 3;  
  11.   
  12.     protected static final int VALUE_WECHAT = 4;  
  13.   
  14.     protected static final String KEY_TOKEN = "token";  
  15.   
  16.     protected static final String KEY_OPEN_ID = "openid";  
  17.   
  18.     protected static final String KEY_USERNAME = "username";  
  19.   
  20.     protected static final String KEY_PASSWORD = "password";  
  21.   
  22.     protected static final String KEY_EMAIL = "email";  
  23.   
  24.     protected static final int REQUEST_CODE_BIND_OR_REGISTER = 1;  
  25.   
  26.     protected static final int REQUEST_CODE_COMPLETE_INFO = 2;  
  27.   
  28.     protected AuthInfo mWeiboAuth;  
  29.   
  30.     protected Oauth2AccessToken accessToken;  
  31.   
  32.     protected SsoHandler mSsoHandler;  
  33.   
  34.     protected Tencent mTencent;  
  35.   
  36.     private String errorMsg;  
  37. //使用广播操作微信登录 注意下面的WXEntryActivity代码,授权成功返回code值当做唯一标识<span style="font-family: Arial, Helvetica, sans-serif;">   </span><span style="font-family: Arial, Helvetica, sans-serif;"> </span>  
[java]  view plain  copy
  1.     BroadcastReceiver mReciver = new BroadcastReceiver() {  
  2.         @Override  
  3.         public void onReceive (Context context, Intent intent){  
  4.             if (intent.getBooleanExtra("result"false)) {  
  5.                 String code = intent.getStringExtra("code");  
  6.                 afterLogin(VALUE_WECHAT, code, code);  
  7.             } else {  
  8.                 Toast.makeText(AuthenticatorActivity.this, getString(R.string.log_in_failed), Toast.LENGTH_SHORT).show();  
  9.             }  
  10.         }  
  11.     };  
  12.   
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         initTencent();  
  17.         initWeibo();  
  18.         initWechat();  
  19.     }  
  20.   
  21.     @Override  
  22.     protected void onDestroy() {  
  23.         super.onDestroy();  
  24.         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);  
  25.         lbm.unregisterReceiver(mReciver);  
  26.     }  
  27.   
  28.     protected void initTencent() {  
  29.         try {  
  30.             mTencent = Tencent.createInstance(Constants.TencentAppId, getApplicationContext());  
  31.         } catch (Throwable e) {  
  32.             e.printStackTrace();  
  33.         }  
  34.     }  
  35.   
  36.     protected void initWeibo() {  
  37.         mWeiboAuth = new AuthInfo(this, Constants.SinaAppKey, Constants.SinaAppRedirectURI,  
  38.                 Constants.SinaScope);  
  39.         mSsoHandler = new SsoHandler(this, mWeiboAuth);  
  40.     }  
  41.   
  42.     protected void initWechat() {  
  43.         LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);  
  44.         lbm.registerReceiver(mReciver, new IntentFilter(Constants.ACTION_WECHAT_LOGIN));  
  45.     }  
  46.   
  47. //QQ登录成功回调方法 返回access_token和openid  
  48.     @Override  
  49.     public void onComplete(Object o) {  
  50.         JSONObject object = (JSONObject) o;  
  51.         try {  
  52.             LogUtils.d(TAG, "onTencentComplete, object is " + object.toString());  
  53.             String token = object.optString("access_token");  
  54.             String openId = object.optString("openid");  
  55.             String expireTime = object.optString("expires_in");  
  56.             Oauth2AccessToken qqAccessToken = new Oauth2AccessToken(token, expireTime);  
  57.             if (qqAccessToken.isSessionValid()) {  
  58.                 String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new java.util.Date  
  59.                         (qqAccessToken  
  60.                                 .getExpiresTime()));  
  61.                 LogUtils.d(TAG, "QQ log in, expire date is " + date);  
  62.             }  
  63.             afterLogin(VALUE_QQ, openId, token);  
  64.         } catch (Exception e) {  
  65.             e.printStackTrace();  
  66.         }  
  67.     }  
  68.   
  69.     @Override  
  70.     public void onError(UiError uiError) {  
  71.         LogUtils.d(TAG,  
  72.                 "onError, uiError is " + uiError.errorDetail + ", " + uiError.errorMessage);  
  73.         Toast.makeText(this,  
  74.                 TextUtils.isEmpty(uiError.errorMessage) ? getString(R.string.qq_log_in_failed)  
  75.                         : uiError.errorMessage, Toast.LENGTH_SHORT).show();  
  76.     }  
  77. //新浪登录成功回调方法 返回accessToken对象  
  78.     @Override  
  79.     public void onComplete(Bundle bundle) {  
  80.         try {  
  81.             accessToken = Oauth2AccessToken.parseAccessToken(bundle);  
  82.             LogUtils.d(TAG,  
  83.                     "onComplete, accessToken is " + accessToken.getUid() + ":" + accessToken  
  84.                             .getToken() + ", expireTime is " + accessToken.getExpiresTime());  
  85.             if (accessToken.isSessionValid()) {  
  86.                 String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")  
  87.                         .format(new java.util.Date(accessToken.getExpiresTime()));  
  88.                 LogUtils.d(TAG, "weibo log in, expire date is " + date);  
  89.                 afterLogin(VALUE_SINA, accessToken.getUid(), accessToken.getToken());  
  90.             }  
  91.         } catch (Exception e) {  
  92.             e.printStackTrace();  
  93.             Toast.makeText(this, getString(R.string.log_in_failed), Toast.LENGTH_SHORT).show();  
  94.         }  
  95.     }  
  96.   
  97.     @Override  
  98.     public void onWeiboException(WeiboException e) {  
  99.         LogUtils.d(TAG, "e.message is " + e.getLocalizedMessage());  
  100.         e.printStackTrace();  
  101.         Toast.makeText(this, String.format(getString(R.string.weibo_error), e.getMessage()),  
  102.                 Toast.LENGTH_LONG).show();  
  103.   
  104.     }  
  105.   
  106.     @Override  
  107.     public void onCancel() {  
  108.   
  109.     }  
  110.   
  111.     @Override  
  112.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  113.         super.onActivityResult(requestCode, resultCode, data);  
  114.         if ((requestCode == REQUEST_CODE_BIND_OR_REGISTER  
  115.                 || requestCode == REQUEST_CODE_COMPLETE_INFO) && resultCode == RESULT_OK) {  
  116.             setResult(RESULT_OK);  
  117.             finish();  
  118.             return;  
  119.         }  
  120.         // sso 授权回调  
  121.         try {  
  122.             if (mSsoHandler != null) {  
  123.                 mSsoHandler.authorizeCallBack(requestCode, resultCode, data);  
  124.             }  
  125.         } catch (Exception e) {  
  126.             e.printStackTrace();  
  127.         }  
  128.     }  
  129. //子类需要重写的方法 在上方三种登录授权成功都会回调这个方法 将type uid token发送给服务器验证  
  130.     protected void afterLogin(int type, String uid, String token) {  
  131.   
  132.     }  
  133. //保存用户信息方法LoginResponse就是一个Bean 内部包含User对象,字段为data, Settings为SharePerference工具类该方法存储user对象json  
[java]  view plain  copy
  1. //Global为全局变量 在运行时内存中存储当前用户对象   
  2.     protected void saveUserInfo(LogInResponse result) {  
  3.         Settings.saveUser(result.data);  
  4.         Global.currentUser = result.data;  
  5.     }  
  6. }  

然后就是子类的实现了 ,登录页的登录事件代码

[java]  view plain  copy
  1. <span style="white-space:pre">    </span>case R.id.weibo_log_in_button:  
  2.                mSsoHandler.authorize(this);  
  3.                break;  
  4.        case R.id.qq_log_in_button:  
  5.                if (mTencent == null) {  
  6.                    Utils.showToast(R.string.qq_not_installed);  
  7.                    return;  
  8.                }  
  9.                mTencent.login(this"get_user_info"this);  
  10.                break;  
  11.        case R.id.weixin_log_in_button:  
[java]  view plain  copy
  1. //这个mWxApi已经在MainActivity中初始化了 注意  
  2.                 if (Global.mWxApi.isWXAppInstalled() && Global.mWxApi.isWXAppSupportAPI()) {  
  3.                     final SendAuth.Req req = new SendAuth.Req();  
  4.                     req.scope = "snsapi_userinfo";  
  5.                     req.state = "none";  
  6.                     Global.mWxApi.sendReq(req);  
  7.                 } else {  
  8.                     Utils.showToast(R.string.weixin_oauth_failed);  
  9.                 }  
  10.                 break;  

也就是说 当我们点击之后 如果授权成功 最终会调用afterLogin方法,里面有三个参数 type uid token,当然 直接登录成功也可以调用这个方法 uid = username,token=password..

然后在这个方法里向我们自己的服务器发请求就可以 服务器返回成功地指示后我们再调用子类重写的saveUserInfo()

[java]  view plain  copy
  1. @Override  
  2.    protected void saveUserInfo(LogInResponse result) {  
[java]  view plain  copy
  1. //父类存储用户信息 全局变量里有user  
  2.         super.saveUserInfo(result);  
[java]  view plain  copy
  1. //子类存储当前的UID信息 当应用退出后下次重进直接通过uid去getUser 这样就不用重复登录了  
  2.         Settings.setCurrentUid(result.data.uid);  
  3.     }  

这样就基本实现第三方登录了

接下来是微信的WXEntryActivity 因为我们使用的是LocalBroadCastRecevier,因此我们在微信登录成功后需要发送广播给实现基类的登录页Activity

[java]  view plain  copy
  1. public class WXEntryActivity extends Activity implements IWXAPIEventHandler {  
  2.     @Override  
  3.     protected void onCreate(Bundle savedInstanceState) {  
  4.         super.onCreate(savedInstanceState);  
  5.         Global.mWxApi.handleIntent(getIntent(), this);  
  6.     }  
  7.   
  8.     @Override  
  9.     protected void onNewIntent(Intent intent) {  
  10.         super.onNewIntent(intent);  
  11.         Global.mWxApi.handleIntent(intent, this);  
  12.     }  
  13.   
  14.   
  15.     @Override  
  16.     public void onReq(BaseReq baseReq) {  
  17.   
  18.     }  
  19.   
  20.     @Override  
  21.     public void onResp(BaseResp baseResp) {  
  22.         if (baseResp instanceof SendAuth.Resp) {  
[java]  view plain  copy
  1. //发送广播  
  2.             LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);  
  3.             Intent intent = new Intent(Constants.ACTION_WECHAT_LOGIN);  
  4.             intent.putExtra("result", baseResp.errCode == BaseResp.ErrCode.ERR_OK);  
  5.             intent.putExtra("code", ((SendAuth.Resp) baseResp).code);  
  6.             lbm.sendBroadcast(intent);  
  7.             finish();  
  8.         }else {  
  9.             int result = 0;  
  10.             switch (baseResp.errCode) {  
  11.                 case BaseResp.ErrCode.ERR_OK:  
  12.                     result = R.string.errcode_success;  
  13.                     break;  
  14.                 case BaseResp.ErrCode.ERR_USER_CANCEL:  
  15.                     result = R.string.errcode_cancel;  
  16.                     break;  
  17.                 case BaseResp.ErrCode.ERR_AUTH_DENIED:  
  18.                     result = R.string.errcode_deny;  
  19.                     break;  
  20.                 default:  
  21.                     result = R.string.errcode_unknown;  
  22.                     break;  
  23.             }  
  24.   
  25.             Toast.makeText(this, getString(result), Toast.LENGTH_LONG).show();  
  26.             finish();  
  27.         }  
  28.     }  
  29. }  

这样就基本完成登录和登录后避免再次登录了,接下来还有一些问题,

1.微信登录需要将apk打包签名 并通过微信的一个校验apk在里面输入包名 生成一个校验码粘贴到开发者平台才能够使用 而且费用300一年

2.微博也需要校验包名

3.每次重复签名很麻烦 又懒得换成测试版的签名 如果使用as或者idea的话 可以在build.gradle里输入

4.微信登录在开发者平台弄好之后不是马上就能用 有1个小时左右的延迟

[html]  view plain  copy
  1. signingConfigs {  
  2.        myConfig {  
  3.            storeFile file("你的keystore文件,相对路径")  
  4.            storePassword 库密码  
  5.            keyAlias alias  
  6.            keyPassword 密码  
  7.        }  
  8.    }  
  9.   
  10.    buildTypes {  
[html]  view plain  copy
  1. //release版本  
  2.         release {  
[html]  view plain  copy
  1. //是否混淆  
  2.             minifyEnabled true  
[html]  view plain  copy
  1. //混淆规则  
  2.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
[html]  view plain  copy
  1. //调用上面的签名方法  
  2.             signingConfig signingConfigs.myConfig  
  3.         }  
[html]  view plain  copy
  1. //debug版本  
  2.         debug {  
[html]  view plain  copy
  1. //调用上面的签名方法  
  2.             signingConfig signingConfigs.myConfig  
  3.         }  
  4.     }  

你可能感兴趣的:(第三方登录)