1. 程式人生 > 實用技巧 >Unity 多平臺原生SDK接入速覽(二):QQ互聯

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 和工程專案,這個真的要給好評。

七、引用

  1. Android_SDK環境搭建 - QQ互聯WIKI
  2. Android FileProvider的使用
  3. onActivityResult的用法_許佳佳的部落格-CSDN部落格_protected void onactivityresult