一、前言

因为之前本人我的项目的账号零碎不是十分欠缺,所以思考接入QQ这个弱小的第三方平台的接入,目前我的项目临时应用QQ登录的接口进行后期的测试,这次从搭建到欠缺花了整整两天工夫,不得不吐槽一下QQ互联的官网文档,从界面就能够看出了,好几年没培修了,示例代码也写的不是很分明,翻了好多源代码和官网的demo,这个demo能够作为辅助参考,官网文档的api生效了能够从外面找相应的代替,但它的代码也太多了,一个demo 一万行代码,心累,过后把demo弄到能够运行就花了不少工夫,很多api如同是生效了,笔者本人做了一些解决和欠缺,简直把sdk性能列表的登录相干的api都尝试了一下,真的相当的坑,注释行将开始,心愿这篇文章可能给后来者一些参考和帮忙。

二、环境配置

1.获取利用ID

这个比较简单,间接到QQ互联官网申请一个即可,官网地址

https://connect.qq.com

申请利用的时候须要留神利用名字不能呈现违规词汇,否则可能申请不通过

利用信息的填写须要以后利用的包名和签名,这个腾讯这边提供了一个获取包名和签名的app供咱们开发者应用,下载地址

https://pub.idqqimg.com/pc/misc/files/20180928/c982037b921543bb937c1cea6e88894f.apk

未通过审核只能应用调试的QQ号进行登录,通过就能够面向全副用户了,以下为审核通过的图片

2.官网下载相干的sdk

下载地址

https://tangram-1251316161.file.myqcloud.com/qqconnect/OpenSDK_V3.5.10/opensdk_3510_lite_2022-01-11.zip

举荐间接下载最新版本的,不过着实没看懂最新版本的更新布告,说是修复了retrofit抵触的问题,而后过后新建的我的项目没有用,后果报错,最初还是加上了,才能够

[图片上传失败...(image-f70a8f-1647264931314)]

3. jar的引入

将jar放入lib包下,而后在app 同级的 build.gradle增加以下代码即实现jar的援用

dependencies {    ...    implementation fileTree(dir: 'libs', include: '*.jar')    ...}

4.配置Manifest

在AndroidManifest.xml中的application结点下减少以下的activity和启动QQ利用的申明,这两个activity无需咱们在另外创立文件,引入的jar曾经解决好了

 <application       ...            <!--这里的权限为开启网络拜访权限和获取网络状态的权限,必须开启,不然无奈登录-->        <uses-permission android:name="android.permission.INTERNET" />        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />        <activity            android:name="com.tencent.tauth.AuthActivity"            android:exported="true"            android:launchMode="singleTask"            android:noHistory="true">            <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" />        <provider            android:name="androidx.core.content.FileProvider"            android:authorities="com.tencent.login.fileprovider"            android:exported="false"            android:grantUriPermissions="true">            <meta-data                android:name="android.support.FILE_PROVIDER_PATHS"                android:resource="@xml/file_paths" />        </provider>        ...    </application>

下面的哪个代码的最初提供了一个provider用于拜访 QQ 利用的,须要另外创立一个 xml 文件,其中的 authorities 是自定义的名字,确保惟一即可,这边最上面那个provider是翻demo找的,文档没有写,在res文件夹中新增一个包xml,外面增加文件名为file\_paths的 xml ,其内容如下

<?xml version="1.0" encoding="utf-8"?><paths>    <external-files-path name="opensdk_external" path="Images/tmp"/>    <root-path name="opensdk_root" path=""/></paths>

三、初始化配置

1.初始化SDK

退出以下代码在创立登录的那个activtiy下,不然无奈拉起QQ利用的登录界面,至于官网文档所说的须要用户抉择是否受权设施的信息的阐明,这里通用的做法是在利用外部申明一个第三方sdk的列表,而后在外面阐明SDK用到的相干设施信息的权限

Tencent.setIsPermissionGranted(true, Build.MODEL)

2.创立实例

这部分倡议放在全局配置,这样能够实现登录异样强制退出等性能

/** * 其中APP_ID是申请到的ID * context为全局context * Authorities为之前provider外面配置的值 */val mTencent = Tencent.createInstance(APP_ID, context, Authorities)

3.开启登录

在开启登录之前须要本人创立一个 UIListener 用来监听回调后果(文档没讲怎么创立的,找了良久的demo)这里的代码为根底的代码,比拟容易实现,目前还没写回调相干的代码,次要是为了疾速展现成果

open class BaseUiListener(private val mTencent: Tencent) : DefaultUiListener() {    private val kv = MMKV.defaultMMKV()    override fun onComplete(response: Any?) {        if (response == null) {            "返回为空,登录失败".showToast()            return        }        val jsonResponse = response as JSONObject        if (jsonResponse.length() == 0) {            "返回为空,登录失败".showToast()            return        }        "登录胜利".showToast()        doComplete(response)    }    private fun doComplete(values: JSONObject?) {    }    override fun onError(e: UiError) {        Log.e("fund", "onError: ${e.errorDetail}")    }    override fun onCancel() {        "勾销登录".showToast()    }}

建设一个按钮用于监听,这里进行登录操作

button.setOnClickListener {        if (!mTencent.isSessionValid) {        //判断会话是否无效        when (mTencent.login(this, "all",iu)) {                        //上面为login可能返回的值的状况            0 -> "失常登录".showToast()            1 -> "开始登录".showToast()            -1 -> "异样".showToast()            2 -> "应用H5登陆或显示下载页面".showToast()            else -> "出错".showToast()        }    }}

这边对mTencent.login(this, "all",iu)中login的参数做一下解释阐明

mTencent.login(this, "all",iu)//这里Tencent的实例mTencent的login函数的三个参数//1.为以后的context,//2.权限,可选项,个别抉择all即可,即全副的权限,不过目前如同也只有一个凋谢的权限了//3.为UIlistener的实例对象

还差最初一步,获取回调的后果的代码,activity的回调,这边显示办法曾经废除了,原本想革新一下的,前面发现要革新的话须要动sdk外面的源码,有点麻烦就没有改了,等更新

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {    super.onActivityResult(requestCode, resultCode, data)    //腾讯QQ回调,这里的iu依然是相干的UIlistener    Tencent.onActivityResultData(requestCode, resultCode, data,iu)    if (requestCode == Constants.REQUEST_API) {        if (resultCode == Constants.REQUEST_LOGIN) {            Tencent.handleResultData(data, iu)        }    }}

至此,曾经能够失常登录了,但还有一件咱们开发者最关怀的事件没有做,获取的用户的数据在哪呢?能够获取QQ号吗?上面将为大家解答这方面的纳闷。

四、接入流程以及相干代码

首先答复一下下面提出的问题,能够取得两段比拟要害的json数据,一个是 login 的时候获取的,次要是token相干的数据,还有一段就是用户的个人信息的 json 数据,这些都在 UIListener 中进行解决和获取。第二个问题能不能获取QQ号,答案是不能,咱们只能获取与一个与QQ号一样具备惟一标记的id即open\_id,显然这是出于用户的隐衷平安思考的,接下来简述一下具体的登录流程

1.登录之前查看是否有token缓存

  • 有,间接启动主activity
  • 无,进入登录界面

判断是否具备登录数据的缓存

//这里采纳微信的MMKV进行贮存键值数据MMKV.initialize(this)val kv = MMKV.defaultMMKV()kv.decodeString("qq_login")?.let{    val gson = Gson()    val qqLogin = gson.fromJson(it, QQLogin::class.java)    QQLoginTestApplication.mTencent.setAccessToken(qqLogin.access_token,qqLogin.expires_in.toString())    QQLoginTestApplication.mTencent.openId = qqLogin.openid}

查看token和open\_id是否无效和token是否过期,这里采取不同于官网的举荐的用法,次要是api生效了或者是本人没用对办法,总之官网提供的api进行缓存还不如MMKV键值存login json来的切实,也很不便,这里倡议多多应用日志,不便排查谬误

//这里对于uiListener进行了重写,object的作用有点像java外面的匿名类//用到了checkLogin的办法mTencent.checkLogin(object : DefaultUiListener() {    override fun onComplete(response: Any) {        val jsonResp = response as JSONObject        if (jsonResp.optInt("ret", -1) == 0) {            val jsonObject: String? = kv.decodeString("qq_login")            if (jsonObject == null) {                "登录失败".showToast()            } else {                //启动主activity            }        } else {            "登录已过期,请从新登录".showToast()            //启动登录activity        }    }    override fun onError(e: UiError) {        "登录已过期,请从新登录".showToast()        //启动登录activity    }    override fun onCancel() {        "勾销登录".showToast()    }})

2.进入登录界面

在判断session无效的状况下,进入登录界面,对login登录可能呈现的返回码做一下解释阐明

Login.setOnClickListener {    if (!QQLoginTestApplication.mTencent.isSessionValid) {        when (QQLoginTestApplication.mTencent.login(this, "all",iu)) {            0 -> "失常登录".showToast()            1 -> "开始登录".showToast()            -1 -> {                "异样".showToast()                QQLoginTestApplication.mTencent.logout(QQLoginTestApplication.context)            }            2 -> "应用H5登陆或显示下载页面".showToast()            else -> "出错".showToast()        }    }}
  • 1:失常登录

    这个就无需做解决了,间接在回调那里做相干的登录解决即可

  • 0:开始登录

    同失常登录

  • -1:异样登录

    这个须要做一点解决,过后第一次遇到这个状况就是主activity异样耗费退回登录的activity,此时在此点击登录界面的按钮导致了异常情况的呈现,不过这个解决起来还是比拟容易的,执行强制下线操作即可

    "异样".showToast()mTencent.logout(QQLoginTestApplication.context)
  • 2:应用H5登陆或显示下载页面

    通常状况下是未装置QQ等软件导致的,这种状况无需解决,SDK主动封装好了,这种状况会主动跳转QQ下载界面

同样的有呈现UIListener就须要调用回调进行数据的传输

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {    super.onActivityResult(requestCode, resultCode, data)    //腾讯QQ回调    Tencent.onActivityResultData(requestCode, resultCode, data,iu)    if (requestCode == Constants.REQUEST_API) {        if (resultCode == Constants.REQUEST_LOGIN) {            Tencent.handleResultData(data, iu)        }    }}

3.进入主activity

这里须要搁置一个按钮执行下线操作,不便调试,同时这里须要将之前的token移除从新获取token等数据的缓存

button.setOnClickListener {    mTencent.logout(this)    val  kv = MMKV.defaultMMKV()    kv.remove("qq_login")    //返回登录界面的相干操作    "退出登录胜利".showToast()}

至此,其实还有一个很重要的货色没有阐明,那就是token数据的缓存和个人信息数据的获取,这部分我写的登录的那个UIlistener外面了,登录胜利的同时,获取login的response的json数据和个人信息的json数据

4.获取两段重要的json数据

  • login 的json数据

    这个比拟容易,当咱们登录胜利的时候,oncomplete外面的response即咱们想要的数据

    override fun onComplete(response: Any?) {    if (response == null) {        "返回为空,登录失败".showToast()        return    }    val jsonResponse = response as JSONObject    if (jsonResponse.length() == 0) {        "返回为空,登录失败".showToast()        return    }    //这个即利用MMKV进行缓存json数据    kv.encode("qq_login",response.toString())    "登录胜利".showToast()}
  • 个人信息的数据

    这个须要在login无效的前提下能力返回失常的数据

    //首先须要用上一步获取的json数据对mTencent进行赋值,这部分放在doComplete办法中执行private fun doComplete(values: JSONObject?) {    //利用Gson进行格式化成对象    val gson = Gson()    val qqLogin = gson.fromJson(values.toString(), QQLogin::class.java)    mTencent.setAccessToken(qqLogin.access_token, qqLogin.expires_in.toString())    mTencent.openId = qqLogin.openid    Log.e("fund",values.toString())}

    创立一个get\_info办法进行获取,留神这里须要对mTencent设置相干的属性能力获取失常获取数据

    private fun getQQInfo(){    val qqToken = mTencent.qqToken    //这里的UserInfo是sdk自带的类,传入上下文和token即可    val info = UserInfo(context,qqToken)    info.getUserInfo(object :BaseUiListener(mTencent){        override fun onComplete(response: Any?){            //这里对数据进行缓存            kv.encode("qq_info",response.toString())                   }    })}

5.踩坑系列

这里次要吐槽一下对于腾讯的自带的session缓存机制,过后是抱着不必本人实现缓存间接用现成的机制去看的,很遗憾这波偷懒失败,这部分session的设置不晓得具体的缓存机制,只晓得大略是用share preference实现的,外面有saveSession,initSession,loadSession这三个办法,看上去很容易的样子,而后抱着这种心态去尝试了一波,果然不出意外空指针异样,尝试批改了一波回调的程序依然空指针异样,折腾了大略三个多小时,放弃了,心态给搞崩了,最终释然了,为什么要用腾讯提供的办法,这个缓存本人实现也是相当的容易,这时想到了MMKV,两行代码实现读取,最初只批改了多数的代码实现了登录的token的缓存机制,翻看demo外面的实现,外面如同是用这三种办法进行实现的,可能是某个实现机制没有弄明确,其实也不想明确,本人的思路比再去看demo容易多了,只是多了一个json的转对象的过程,其余的没有差异。所以倡议后来者间接本人实现缓存,不必管sdk提供的那些办法,真的有点难用。

五、总结

总之这次实现QQ接入踩了许多的坑,不过幸好最终还是实现了,心愿腾讯互联这个sdk可能上传github让更多的人参加和提供反馈,不然这个文档说是最差sdk体验也不为过。上面附上这次实现QQ登录的demo的github地址以及相干的demo apk供大家进行参考,大略总共就400行代码左右比官网的demo好很多,有问题欢送留言

https://github.com/xyh-fu/QQLoginTest.git