Unity 多平臺原生SDK接入速覽(二):QQ互聯
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 和工程專案,這個真的要給好評。