• 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)

    img

    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。

    img

    五、分享

    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 就是如下界面。

    img

    因为跳转到了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);
        }
    

    img

    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);
        }
    

    img

    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);
        }
    

    img

    六、总结

    QQ互联的接入和使用还是简单的。不需要微信那种通过登陆请求获取 code,再通过 code 获取 access token 的操作。并且QQ互联的分享,并不需要登陆也是可以的。官方提供的 SDK 的压缩包中,不光是 SDK,也包含了 Demo 的 APK 和工程项目,这个真的要给好评。

    七、引用

    1. Android_SDK环境搭建 - QQ互联WIKI
    2. Android FileProvider的使用
    3. onActivityResult的用法_许佳佳的博客-CSDN博客_protected void onactivityresult
  • 相关阅读:
    关于异步IO与同步IO的写操作区别
    慢慢开始记录一些技术心得吧
    写了placement new就要写placement delete
    关于针对class自定义new操作符失败的函数处理
    operator->和operator->*
    关于继承中的拷贝构造函数
    关于g++编译模板类的问题
    关于互斥锁,条件变量的内核源码解析
    关于sigwait
    观察者设计模式
  • 原文地址:https://www.cnblogs.com/ZeroyiQ/p/13353820.html
Copyright © 2020-2023  润新知