之前整合的版本很古老,可能是2018年的,最近想升级到当前最新版V3.5.14.4,遇到一些问题在此备忘。
注1:我的app只用到登录并得到open id和nickname,以下备忘仅针对此功能(如果希望得到更多用户信息参考官方demo,里边有处理头像等其它信息的代码)。
注2:最初的准备工作即申请QQ互联id等等,网上有很多介绍。
1、从app转入QQ登录界面的设置
<manifest> 内须添加
<queries>
<package android:name="com.tencent.mobileqq" />
</queries>
这是因为Android11开始权限紧缩,若不加<queries>则无法转入QQ登录界面
2、变更引入的SDK
将gradle中对旧版SDK的引用
api files('libs/open_sdk_r6008_lite.jar')
变更为对最新版引用
api files('libs/open_sdk_3.5.14.4_r377deaa_lite.jar')
改变后注意点击Sync按钮(或File - Sync Project ...)
这个jar在官方demo下工程文件夹并列的libs/下,在官方demo工程下的libs下也有个open_sdk_lite.jar,两者大小都不一样,我选用的是这个文件名带版本号的。
3、代码部分(注意看注释)
3-1、变量和类
final Activity activity = this;// Toast用,请自行修改变量名
public static Tencent mTencent;// 腾讯互联变量
// 用户在QQ登录界面登录或返回后,此侦听器进一步处理
IUiListener loginListener = new BaseUiListener() {
@Override
protected void doComplete(JSONObject values) {
initOpenidAndToken(values);
updateUserInfo();
}
};
// BaseUiListener类
private class BaseUiListener extends DefaultUiListener {
@Override
public void onComplete(Object response) {
if (null == response) {
Toast.makeText(activity, "null == response", Toast.LENGTH_SHORT).show();
return;
}
JSONObject jsonResponse = (JSONObject) response;
if (jsonResponse.length() == 0) {
Toast.makeText(activity, "jsonResponse.length() == 0", Toast.LENGTH_SHORT).show();
return;
}
// 此时已得到用户的 open id
Toast.makeText(activity, response.toString(), Toast.LENGTH_SHORT).show();
doComplete((JSONObject)response);
}
protected void doComplete(JSONObject values) {
// ...
}
@Override
public void onError(UiError e) {
// e.errorCode, e.errorMessage, e.errorDetail
Toast.makeText(activity, "onError", Toast.LENGTH_SHORT).show();
}
@Override
public void onCancel() {
Toast.makeText(activity, "onCancel", Toast.LENGTH_SHORT).show();
}
}
// 获取用户信息后的处理句柄
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
JSONObject response = (JSONObject) msg.obj;
if (response.has("nickname")) {
try {
// 此时已得到用户的 nickname
Toast.makeText(activity, response.getString("nickname"), Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
Toast.makeText(activity, "JSONException", Toast.LENGTH_SHORT).show();
}
}
}
}
};
3-2、方法
private void loginQQ() {
if(null == mTencent) {
Toast.makeText(activity, "null == mTencent", Toast.LENGTH_SHORT).show();
} else {
if (!mTencent.isSessionValid()) {
mTencent.login(this, "all", loginListener);
// 调用后转入QQ登录界面,选择账号(若apk未签名则只能选择申请的测试QQ)
// 选择并登录后,会返回app界面,自动调用onActivityResult()
// 然后才能触发loginListener的onComplete或on其它方法
} else {
Toast.makeText(activity, "Already logged in", Toast.LENGTH_SHORT).show();
}
}
}
public static void initOpenidAndToken(JSONObject jsonObject) {
try {
String token = jsonObject.getString(Constants.PARAM_ACCESS_TOKEN);
String expires = jsonObject.getString(Constants.PARAM_EXPIRES_IN);
String openId = jsonObject.getString(Constants.PARAM_OPEN_ID);
if (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(expires)
&& !TextUtils.isEmpty(openId)) {
mTencent.setAccessToken(token, expires);
mTencent.setOpenId(openId);
}
} catch(Exception e) {
}
}
private void updateUserInfo() {
if (mTencent != null && mTencent.isSessionValid()) {
IUiListener listener = new DefaultUiListener() {
@Override
public void onError(UiError e) {
Toast.makeText(activity, "onError", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete(final Object response) {
Message msg = new Message();
msg.obj = response;
msg.what = 0;
mHandler.sendMessage(msg);
}
@Override
public void onCancel() {
Toast.makeText(activity, "onCancel", Toast.LENGTH_SHORT).show();
}
};
// 获取详细信息例如nickname
UserInfo info = new UserInfo(this, mTencent.getQQToken());
info.getUserInfo(listener);
} else {
// ...
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 自V3.3.0 必须,否则无法呼出 loginListener的onComplete
Tencent.onActivityResultData(requestCode,resultCode,data,listener);
}
3-3 调用
例如在点击界面里的登录按钮时
// 授权;实测有时不需要调用,原因未知,为保险起见调用一下
Tencent.setIsPermissionGranted(true);
// 创建 mTencent; Demo是3个参数,第3个参数对于登录来说没必要(可能对分享功能必要)
mTencent = Tencent.createInstance("your app id", this);// 替换 your app id
// 登录QQ
loginQQ();
loginQQ后的流程简介:
mTencent.login() -> QQ登录界面 -> onActivityResult()内调用Tencent.onActivityResultData() -> loginListener(BaseUiListener类)的onComlete() 得到了用户open id -> loginListener(override)的doComplete(),其内调用initOpenidAndToken(), updateUserInfo(), 后者创建内部listener并getUserInfo -> 该listener的onComplete()发送消息给mHandler -> mHandler得到用户nickname
4、混淆keep class
-keep class com.tencent.connect.** {*;}
-keep class com.tencent.open.** {*;}
-keep class com.tencent.tauth.** {*;}
否则debug时没问题,release版崩溃。
最主要的坑:
1、未处理onActivityResult()导致后续流程受阻;
2、未进行混淆处理。
参考
A、Logcat异常
若不在gradle增加
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
则会在Logcat中发现异常;但不影响登录功能。
Caused by: java.lang.ClassNotFoundException: Didn't find class "okhttp3.internal.Version" on path
B、未用到的jar
在官方demo的工程文件夹下的libs/下有3个jar
mid-sdk-2.10.jar
mta-sdk-2.0.0.jar
open_sdk_lite.jar
实测不引入前2个jar,对登录功能无影响
至于第3个jar,见前边第2条