ZeroyiQ:Unity 多平台原生SDK接入速览(一):微信开放平台
ZeroyiQ:Unity 多平台原生SDK接入速览(三):Facebook
ZeroyiQ:Unity 多平台原生SDK接入速览(四):Twitter
ZeroyiQ:Unity 多平台原生SDK接入速览(五):微博
一、前言
QQ互联,当前(2020-6-29)支持个人开发者认证和企业认证。创建应用,等待审核后获取 AppID 和 AppKey。
二、SDK接入
1. 添加 jar 包
下载 jar 包,添加到工程 libs 路径下。(Android SDK 中就包含了演示工程 Demo)
2. 设置权限
AndroidManifest.xml 文件中添加网络权限。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
3. 配置 Activity
AndroidManifest.xml 添加 Activity 配置 ,需要填入 AppId。注意格式为 tencent+AppId,例,AppId 是 2222 ,则填入 tencent2222。
<application>
<activity
android:name="com.tencent.tauth.AuthActivity"
android:noHistory="true"
android:launchMode="singleTask" >
<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="tencent你的AppId" />
</intent-filter>
</activity>
<activity
android:name="com.tencent.connect.common.AssistActivity"
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<application>
4. 初始化
创建 Tencent 实例。
public static final String QQ_ID = "你的AppId";
public static final String AUTHORITIES = "<包名>.fileprovider";
public static Tencent QQ_API;
private void init() {
if (!bIsInitialized) {
bIsInitialized = true;
// Tencent类是SDK的主要实现类,开发者可通过Tencent类访问腾讯开放的OpenAPI。
// 其中APP_ID是分配给第三方应用的appid,类型为String。
// 其中Authorities为 Manifest文件中注册FileProvider时设置的authorities属性值
QQ_API = Tencent.createInstance(QQ_ID, activity.getApplicationContext(), AUTHORITIES);
}
}
注,初始化依赖 FileProvider,如果没有添加,可以从 Demo 中找到 Jar 包, 依照 第1步 一样添加 Jar包。
在 AndroidManifest.xml 中配置,替换包名。
上面的创建实例传入的 AUTHORITIES 值与 android:authorities 保持一致。
<application>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<包名>.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
5. 实现回调
通过实现对应接口,创建和传入对应 Listener,实现请求的回调监听。然而,当前存在两种回调接口。
IUiListener(SDK 封装的情况)
例如:登录、快速支付登录、应用分享、应用邀请等接口,需传入该回调的实例。
private class BaseUiListener implements IUiListener {
public static final String TAG = "QQUiListener";
@Override
public void onComplete(Object response) {
if (null == response) {
UnityCallApi.unityLogError(TAG, "QQ request error. response is null.");
ToastUtils.show(activity, R.string.errcode_null);
return;
}
JSONObject jsonResponse = (JSONObject) response;
if (jsonResponse.length() == 0) {
UnityCallApi.unityLogError(TAG, "QQ request error. response length is 0.");
ToastUtils.show(activity, R.string.errcode_null);
return;
}
UnityCallApi.unityLogInfo(TAG, "QQ request successfully.");
ToastUtils.show(activity, R.string.errcode_success);
// 有奖分享处理
// handlePrizeShare();
onSuccessful((JSONObject) response);
}
@Override
public void onError(UiError e) {
UnityCallApi.unityLogError(TAG, "QQ request error" + e.toString());
ToastUtils.show(activity, activity.getString(R.string.errcode_unknown) + ", type=" + e.errorMessage);
onFailed();
}
@Override
public void onCancel() {
UnityCallApi.unityLogInfo(TAG, "QQ request cancel.");
ToastUtils.show(activity, R.string.errcode_cancel);
onFailed();
}
protected void onFailed() {
}
protected void onSuccessful(JSONObject values) {
}
}
IRequestListener (SDK 未封装的情况)
使用requestAsync、request等通用方法调用sdk未封装的接口时,例如上传图片、查看相册等,需传入该回调的实例。(轻度使用 SDK,将不会涉及该接口 ,故对于接口内容不做展示)
特别注意,为了能收到回调,还需要在调用 SDK 接口的 Activity 的 onActivityResult 添加如下方法。官方文档 中的方法已经被废弃,当前使用的是 Demo 演示中的方法,loginListener 就是 BaseUiListener 的用来处理登录回调的实例。可以根据 requestCode 来判断该响应那个回调。关于 onActivityResult 可以看这个介绍文章,从 otherActivity 切换回来当前 Activity 的时候运行。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "-->onActivityResult " + requestCode + " resultCode=" + resultCode);
if (requestCode == Constants.REQUEST_LOGIN ||
requestCode == Constants.REQUEST_APPBAR) {
// 传递回调
Tencent.onActivityResultData(requestCode,resultCode,data,loginListener);
}
super.onActivityResult(requestCode, resultCode, data);
}
三、登录
1.发起登录请求
在初始化 Tencent 后,发起登录请求。
public void login(Activity activity) {
this.activity = activity;
// 判断会话是否有效
if (!QQ_API.isSessionValid()) {
// all 全部作用域,loginListener 就是上文的登录回调
QQ_API.login(activity, "all", loginListener);
Log.d("SDKQQAgentPref", "FirstLaunch_SDK:" + SystemClock.elapsedRealtime());
}
}
2.实例化回调
实例化我们之前实现的 IUiListener 的 BaseUiListener 类。
IUiListener loginListener = new BaseUiListener() {
@Override
protected void onSuccessful(JSONObject values) {
UnityCallApi.unityLogInfo(TAG, "Login successful.");
// 初始化 openId 和 Token
initOpenidAndToken(values);
// 获取用户信息
updateUserInfo();
}
@Override
protected void onFailed() {
UnityCallApi.unityLogInfo(TAG, "Login failed.");
}
};
注意别忘记前文所说,在 Activity 的 onActivityResult 添加对应的 onActivityResultData。
3.初始化 OpenId 和 Token
使用登陆接口登陆成功以后,在登陆的回调接口保存登陆返回的token和过期时间。
private 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)) {
QQ_API.setAccessToken(token, expires);
QQ_API.setOpenId(openId);
QQ_API.saveSession(jsonObject);
}
} catch (Exception e) {
e.printStackTrace();
UnityCallApi.unityLogError(TAG, "Parse response to json error.");
}
}
四、获取用户信息
在登录后,发送获取用户信息请求。
private void updateUserInfo() {
if (QQ_API != null && QQ_API.isSessionValid()) {
IUiListener listener = new BaseUiListener() {
@Override
protected void onSuccessful(JSONObject values) {
// 传递到 Unity 中进行解析
UnityCallApi.sendLoginInfoToUnity(true, values.toString());
}
@Override
protected void onFailed() {
UnityCallApi.sendLoginInfoToUnity(false, "");
}
};
// 只有初始化过 token 后才能 get
UserInfo info = new UserInfo(activity, QQ_API.getQQToken());
info.getUserInfo(listener);
}
}
将返回信息传递给 Unity 进行解析。
正确返回的 json。
五、分享
1. 图文(网页)
QQ分享不支持直接分享纯文字,必须要传入跳转 URL。
public void shareWebLink(Bundle params) {
Bundle paramsIn = new Bundle();
paramsIn.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT); // 类型 default (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_TARGET_URL,"链接"); // 链接 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_TITLE,"标题"); // 链接标题 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_SUMMARY,"摘要"); // 链接摘要 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_IMAGE_URL,"图片URL"); // 本地 or 网络图片 url (可选)
paramsIn.putString(QQShare.SHARE_TO_QQ_APP_NAME, APP_NAME); // 应用名称 客户端顶部替换返回按钮文字 (可选)
paramsIn.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE); // 隐藏 QZone (可选)
// 分享Listener,会添加到 OnActivityResult 中
shareListener = new BaseUiListener() {
@Override
protected void onSuccessful(JSONObject values) {
// 成功
}
@Override
protected void onFailed() {
// 失败
}
};
QQ_API.shareToQQ(activity, paramsIn, shareListener);
}
QQShare.SHARE_TO_QQ_EXT_INT 参数值的分享到 QZone 就是如下界面。
因为跳转到了QQ界面,别忘了为了响应回调,需要在 OnActivityResult 中添加如下代码。
@Override //这段代码非常重要,不加的话无法获取回调
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 判断是QQ分享结果
if (requestCode == Constants.REQUEST_QQ_SHARE) {
Tencent.onActivityResultData(requestCode, resultCode, data, shareListener);
}
super.onActivityResult(requestCode, resultCode, data);
}
2. 纯图片
注意纯图片分享是只支持本地图片的,并不支持在线图片。图片大小不能超过 5M。
public void shareImage(Bundle params) {
Bundle paramsIn = new Bundle();
paramsIn.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_IMAGE); // 类型 Image (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, "本地图片路径Path"); // 本地图片路径 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_APP_NAME, APP_NAME); // 应用名称 客户端顶部替换返回按钮文字 (可选)
paramsIn.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE); // 隐藏 QZone (可选)
shareListener = new BaseUiListener() {
@Override
protected void onSuccessful(JSONObject values) {
// 成功
}
@Override
protected void onFailed() {
// 失败
}
};
String localPath = paramsIn.getString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL);
if (!TextUtils.isEmpty(localPath)) {
File file = new File(localPath);
if (file.length() >= 5 * 1024 * 1024) { // 大小不能超过 5M
shareListener.onError(new UiError(Constants.ERROR_IMAGE_TOO_LARGE, Constants.MSG_SHARE_IMAGE_TOO_LARGE_ERROR, null));
return;
}
}
QQ_API.shareToQQ(activity, paramsIn, shareListener);
}
3. 应用
分享其实和图文很类似,重点还是在 SHARE_TO_QQ_TARGET_URL 设置的网页。
public void shareApp(Bundle params) {
Bundle paramsIn = new Bundle();
paramsIn.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_APP); // 类型 App (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_TITLE, "标题"); // 链接标题 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_SUMMARY, "摘要"); // 链接摘要(必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_TARGET_URL, "应用链接"); // 应用链接 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, "应用icon链接"); // 应用icon链接 (必要)
paramsIn.putString(QQShare.SHARE_TO_QQ_APP_NAME, APP_NAME); // 应用名称 客户端顶部替换返回按钮文字 (可选)
paramsIn.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE); // 隐藏 QZone(可选)
shareListener = new BaseUiListener() {
@Override
protected void onSuccessful(JSONObject values) {
// 成功
}
@Override
protected void onFailed() {
// 失败
}
};
QQ_API.shareToQQ(activity, paramsIn, shareListener);
}
六、总结
QQ互联的接入和使用还是简单的。不需要微信那种通过登陆请求获取 code,再通过 code 获取 access token 的操作。并且QQ互联的分享,并不需要登陆也是可以的。官方提供的 SDK 的压缩包中,不光是 SDK,也包含了 Demo 的 APK 和工程项目,这个真的要给好评。