在新进的项目中,原先使用SharedSDK做第三方登录。在近期的数据统计分析中,发现会存在获取openid成功,而获取QQ用户信息不成功的情形。除却在获取信息失败情形下添加条件拦截外,使用QQ SDK直接实现第三方登录是另一个选择。
一、资源查看与下载
度娘还是很好用的啦,信息渠道的扩展,极大地缩小了信息搜索的难度,增加了信息获取的公平性。
这里是QQ官方文档,用于引导开发者使用并达到功能实现。
二、功能实现
1,官方渠道注册
保存并获取APPID。
在新建项目中,导入下载的QQ 登录注册等相关jar包。
ps:QQ sdk 在3.2.1版本中添加基础包,有最基本的功能。【正在完善APP中只需要登录功能,遂换成基础包】
2,项目代码实现 -- 清单文件添加权限
<!-- QQ登录授权所需权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
3,项目代码实现 -- 声明Activity
<!-- 注册SDKActivity -->
<activity
android:name="com.tencent.tauth.AuthActivity"
android:launchMode="singleTask"
android:noHistory="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tencentAppID" /> <!-- 开放平台获取的APPID -->
</intent-filter>
</activity>
<activity android:name="com.tencent.connect.common.AssistActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:screenOrientation="portrait"/>
ps:有些博客中没有声明AssistActivity,会导致创建Tencent对象为空的情形。
AppID为之前官方渠道注册所得,前面tencent字符串不可省不可改。
4,项目代码实现 --- IUiListener接口实现
/**
* qq登录监听器
*/
public class BaseUiListener implements IUiListener {
protected void doComplete(Object values) {
}
@Override
public void onComplete(Object response) {
doComplete(response);
}
@Override
public void onError(UiError e) {
}
@Override
public void onCancel() {
}
}
doComplete()方法在不同版本中传参可能不一样,并不影响使用。另一种传参为JsonObject。在实际的数据解析中,都会转换成为JSonObject从而获取需要的值。5,项目代码实现 --- 创建Tencent实例
mTencent = Tencent.createInstance("AppID", this.getApplicationContext());
当清单文件没有AssistActivity声明,会导致获取对象为空。
6,项目代码实现 --- 登录事件触发
在页面实现的QQ点击进行第三方登陆的onClick()事件下添加:
if (!mTencent.isSessionValid()) {
mTencent.login(this, "all", new BaseUiListener());
}
7,项目代码实现 --- 回调监听
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mTencent != null) {
mTencent.handleLoginData(data, new BaseUiListener() {
@Override
protected void doComplete(Object values) {
String expires_in = "";
try {
qq_id = new JSONObject(values.toString()).getString("openid");
qq_token = new JSONObject(values.toString()).getString("access_token");
expires_in = new JSONObject(values.toString()).getString("expires_in");
} catch (Exception e) {
e.printStackTrace();
}
//依据回调回来的值修改原有默认值
mTencent.setOpenId(qq_id);
mTencent.setAccessToken(qq_token, expires_in);
QQToken qqToken = mTencent.getQQToken();
UserInfo info = new UserInfo(LoginMainActivity.this, qqToken);
//获取用户基本信息
info.getUserInfo(new BaseUiListener() {
@Override
protected void doComplete(Object values) {
try {
JSONObject jsonObject = new JSONObject(values.toString());
qq_name = jsonObject.getString("nickname");
qq_icon = jsonObject.getString("figureurl_qq_2");
/**
* 增加QQ信息获取不完整拦截
*/
if (qq_name == null || qq_name.length() <= 0
|| qq_icon == null || qq_icon.length() <= 0
|| qq_id == null || qq_id.length() <= 0) {
CustomProgressDialog.getInstance().dismiss();
ToastView.showToast(LoginMainActivity.this, R.string.network_bad, ToastView.LENGTH_SHORT);//工具类,展示信息获取不完整
return;
}
//登录到客户端服务器
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
});
}
}
注意:
(1)QQToken qqToken = mTencent.getQQToken();
获取前需要依据返回值设置数据,否则在之后的用户信息获取下会出现传参错误。
(2)用户信息获取的方法模式封装好
info.getUserInfo(new BaseUiListener() {});回调方法里面处理详细细节
(3)获取到用户信息,openid之后,需要与客户端本身的服务器关联,实现真正的登录。
三、细节注意
1,APPID的两处使用,清单文件中携带tencent的字符串,代码中获取Tencent对象不加任何其他字符;
2,获取用户信息前,需要重新设置Tencent对象的值;
3,mTencent.isSessionValid()是否使用:
(1)使用:需要在和APP登录成功后,注销掉QQ登录,使其失效。否则会出现APP退出再进行登录无效。
【原因:QQ已经是登陆状态,还没有失效,下次不会重新获取,触发登录流程】
mTencent.logout(this);
能够注销登录。(2)不使用
每次点击事件都相当于触发登录事件,走登录流程。
客户端会有连续快速点击,需要做快速点击防止!
4,无QQ客户端添加拦截
在客户端处理没有QQ客户端拦截,不允许登录或者提示安装QQ客户端再登录。否则会有:WebAuthorizeActivity错误:
java.lang.NoSuchMethodError: cn.sharesdk.framework.authorize.e.disableScreenCapture
at cn.sharesdk.framework.authorize.e.onCreate(WebAuthorizeActivity.java:125)
at com.mob.tools.MobUIShell.onCreate(MobUIShell.java:89)
at android.app.Activity.performCreate(Activity.java:5350)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2332)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2430)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1342)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5334)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
at dalvik.system.NativeStart.main(Native Method)
小小的自我提醒:
在追求任何知识和技能的过程中,最顶端的最后一小段路的边际成本是最高的,关山修阻,难以成行。但是边际理论只能带你到那里,最后一段路上请你务必忘记它。