一、前言
因为之前本人我的项目的账号零碎不是十分欠缺,所以思考接入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