Android QQ 登录接入详细介绍

2023-11-12

e58bd89dcb2c2481a75d8b77023eb35b.png

/   今日科技快讯   /

近日,百度地图发布2022春节出行大数据。迁徙大数据显示,2022年春运迁徙规模较去年农历同期有明显上升。春节期间全国人口迁徙规模日均值为去年农历同期的近两倍。春节前的迁徙规模峰值出现在1月29日(腊月廿七),春节后于2月6日达到峰值。

/   作者简介   /

本篇文章来自wresource的投稿,文章主要分享了他接入AndroidQQ登录的整个过程和心得,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

wresource的博客地址:

https://dreamstudio.blog.csdn.net/

/   前言   /

由于之前自己项目的账号系统不是非常完善,所以考虑接入QQ这个强大的第三方平台的接入,目前项目暂时使用QQ登录的接口进行前期的测试,这次从搭建到完善花了整整两天时间,不得不吐槽一下QQ互联的官方文档,从界面就可以看出了,好几年没维修了,示例代码也写的不是很清楚,翻了好多源代码和官方的demo,这个demo可以作为辅助参考,官方文档的api失效了可以从里面找相应的替代,但它的代码也太多了,一个demo一万行代码,心累,当时把demo弄到可以运行就花了不少时间,很多api好像是失效了,笔者自己做了一些处理和完善,几乎把sdk功能列表的登录相关的api都尝试了一下,真的相当的坑,正文即将开始,希望这篇文章能够给后来者一些参考和帮助。

/   环境配置   /

获取应用ID

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

https://connect.qq.com

申请应用的时候需要注意应用名字不能出现违规词汇,否则可能申请不通过。

应用信息的填写需要当前应用的包名和签名,这个腾讯这边提供了一个获取包名和签名的app供我们开发者使用,下载地址。

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

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

810ca3af334ceef400c6a93092b6d72b.png

官网下载相关的sdk

下载地址

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

推荐直接下载最新版本的,不过着实没看懂最新版本的更新公告,说是修复了retrofit冲突的问题,然后当时新建的项目没有用,结果报错,最后还是加上了,才可以。

ceefdd8ea16c8bd37a638a7d2265437f.png

jar的引入

将jar放入lib包下,然后在app同级的 build.gradle添加以下代码即完成jar的引用。

dependencies {

    ...

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

}

配置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>

/   初始化配置   /

初始化SDK

加入以下代码在创建登录的那个activtiy下,不然无法拉起QQ应用的登录界面,至于官方文档所说的需要用户选择是否授权设备的信息的说明,这里通用的做法是在应用内部声明一个第三方sdk的列表,然后在里面说明SDK用到的相关设备信息的权限。

Tencent.setIsPermissionGranted(true, Build.MODEL)

创建实例

这部分建议放在全局配置,这样可以实现登录异常强制退出等功能。

/**

 * 其中APP_ID是申请到的ID

 * context为全局context

 * Authorities为之前provider里面配置的值

 */

val mTencent = Tencent.createInstance(APP_ID, context, Authorities)

开启登录

在开启登录之前需要自己创建一个 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,显然这是出于用户的隐私安全考虑的,接下来简述一下具体的登录流程。

登录之前检查是否有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()
    }
})
进入登录界面

在判断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)
        }
    }
}
进入主activity

这里需要放置一个按钮执行下线操作,方便调试,同时这里需要将之前的token移除重新获取token等数据的缓存。

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

至此,其实还有一个很重要的东西没有说明,那就是token数据的缓存和个人信息数据的获取,这部分我写的登录的那个UIlistener里面了,登录成功的同时,获取login的response的json数据和个人信息的json数据。

获取两段重要的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有效的前提下才能返回正常的数据。

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

踩坑系列

这里主要吐槽一下关于腾讯的自带的session缓存机制,当时是抱着不用自己实现缓存直接用现成的机制去看的,很遗憾这波偷懒失败,这部分session的设置不知道具体的缓存机制,只知道大概是用share preference实现的,里面有saveSession,initSession,loadSession这三个方法,看上去很容易的样子,然后抱着这种心态去尝试了一波,果然不出意外空指针异常,尝试修改了一波回调的顺序仍然空指针异常,折腾了大概三个多小时,放弃了,心态给搞崩了,最终释然了,为什么要用腾讯提供的方法,这个缓存自己实现也是相当的容易,这时想到了MMKV,两行代码完成读取,最后只修改了少数的代码完成了登录的token的缓存机制,翻看demo里面的实现,里面好像是用这三种方法进行实现的,可能是某个实现机制没有弄明白,其实也不想明白,自己的思路比再去看demo容易多了,只是多了一个json的转对象的过程,其他的没有差别。所以建议后来者直接自己实现缓存,不用管sdk提供的那些方法,真的有点难用。

/   总结   /

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

GitHub地址:

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

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

Android Studio 新特性详解

LiveData为啥连续postValue两次,第一次的值会丢失?

欢迎关注我的公众号

学习技术或投稿

357db9718ac5f712199872fe6bc25b59.png

6bd103bb32e139a71650dca18d5706a6.png

长按上图,识别图中二维码即可关注

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android QQ 登录接入详细介绍 的相关文章

随机推荐

  • vue2引入Element UI组件去创建新页面的详细步骤--项目阶段2

    目录 一 Element UI介绍 Element UI的特点 二 下载配置Element UI 零 创建vue项目 一 下载Element UI依赖 二 全局文件main js中引入Element UI 三 删除多余的东西 一 删除App
  • ctf.show

    web21 自定义迭代器 先抓个包 发现authorization 授权 后面的basic认证很奇怪 用base64解码看看就是输入的用户名和密码 返回包里出现乱码 但可以看到admin 猜测用户名就叫admin 知道了爆破登录的形式是xx
  • spring与mybatis集成

    Spring 集成 MyBatis 将 MyBatis与 Spring 进行整合 主要解决的问题就是将 SqlSessionFactory 对象交由 Spring来管理 所以 该整合 只需要将 SqlSessionFactory 的对象生成
  • Nodejs+Express中页面控制器及脚本自动加载设计

    Express自身带强大的路由功能 这让我们可以详细拆分项目的需求 设计出优美的restful风格对外API 为了方便实现上述功能 我加入了页面控制器及脚本自动加载设计 比如针对会员模块 我们在app js中指定了模块的路由文件 app u
  • 【Java】你还在使用单线程处理大量数据么?

    Java 结合实际业务场景 使用多线程异步处理大量数据 业务场景 优化方案 多线程的实现 线程池 为什么要使用线程池 线程池的创建 1 Spring配置类 2 手动创建 提交任务 1 execute 2 submit 案例伪代码 后续优化
  • 【Python】OpenCV常用操作函数大全!

    目录 cv2常用类 1 图片加载 显示和保存 2 图像显示窗口创建与销毁 3 图片的常用属性的获取 4 生成指定大小的矩形区域 ROI 5 图片颜色通道的分离与合并 6 两张图片相加 改变对比度和亮度 7 像素运算 1 加减乘除 8 像素运
  • 【Windows】Windows下wget的安装与环境变量配置

    1 wget安装 GNU Wget常用于使用命令行下载网络资源 包括但不限于文件 网页等 GNU Wget官网 GNU Wget GNU Wget for Windows GNU Wget for Windows 安装时首先下载主安装包 C
  • 老王的24天,

    数组元素的反转 数组元素的反转 本来的样子 1 2 3 4 之后的样子 4 3 2 1 要求不能使用新数组 就用原来的一个数组 public class Demo07ArrayReverse public static void main
  • nRF52832 — 多通道ADC接口的使用

    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX 作 者 文化人 XX 联系方式 XX 版权声明 原创文章 欢迎评论和转载 转载时能告诉我一声就最好了 XX 要说的
  • Golang基础(项目结构)

    一 标准的项目结构 在实际开发中不可能只有一个main包 更不可能就只有一个 go文件 不同级别大小的项目中包和文件数量都不同 Go语言中组织单元最大的为项目 项目下包含包 一个包可以有多个文件 包在物理层面上就是文件夹 同一个文件夹中多个
  • iOS App的上架和版本更新流程

    一 前言 作为一名iOSDeveloper 把开发出来的App上传到App Store是必要的 下面就来详细讲解一下具体流程步骤 二 准备 一个已付费的开发者账号 账号类型分为个人 Individual 公司 Company 企业 Ente
  • curl使用总结

    curl使用官网 https curl haxx se docs manpage html 1 查看curl的安装版本以及支持的协议 curl V 2 CURL分析HTTPS请求耗时时间 HTTPS耗时 TCP握手 SSL握手 因为涉及到一
  • 短视频矩阵系统源代码开发搭建分享--代码开源SaaS

    一 什么是短视频矩阵系统 短视频矩阵系统是专门为企业号商家 普通号商家提供帐号运营从流量 到转化成交的一站式服务方案 具体包含 点赞关注评论主动私信 评论区回复 自动潜客户挖掘 矩阵号营销 自动化营销 粉丝 管理等功能 可以帮助企业或商家快
  • stl排序之sort函数

    STL容器的排序 支持随机访问的容器vector deque string没有sort成员 可调用std sort排序 list排序调用自带的list sort 下面是std sort函数 有两个版本 template
  • LED点阵书写显示屏

    LED点阵书写显示屏 题目的大概要求是做一个32 32的点阵书写屏 LED 点阵模块显示屏工作在人眼不易觉察的扫描微亮和人眼可见的 显示点亮模式下 当光笔触及 LED 点阵模块表面时 先由光笔检测触及位置处 LED 点 的扫描微亮以获取其行
  • springboot no tests were found

    springboot单元测试报错 no tests were found 如图所示 原因分析 1 进行单元测试的方法不能有返回值 2 方法不能私有化 以上两个问题都会报 no tests were found 错误 正确写法
  • 华为od机试 Java 【url拼接】

    题目 给定一个URL的前缀和后缀 我们需要将其合并成一个完整的URL 在合并时 请注意以下几点 如果前缀的结尾没有斜线 而后缀的开头也没有斜线 那么在两者之间需要添加一个斜线 如果前缀的结尾和后缀的开头都有斜线 那么需要保留其中的一个 删除
  • Vue-生命周期函数

    Vue 生命周期函数 一 生命周期和生命周期函数 生命周期 Life Cycle 是指一个组件从创建 gt 运行 gt 销毁的整个阶段 强调的是一个时间段 生命周期函数 是由vue 框架提供的内置函数 会伴随着组件的生命周期 自动按次序执行
  • 【js】从数组中随机选一个数,从数组中随机选几个数

    每组中随机选一个 每组中随机选一个 randomFun arr let ri Math floor Math random arr length return arr ri 使用 let arr 1 2 3 4 5 6 7 console
  • Android QQ 登录接入详细介绍

    今日科技快讯 近日 百度地图发布2022春节出行大数据 迁徙大数据显示 2022年春运迁徙规模较去年农历同期有明显上升 春节期间全国人口迁徙规模日均值为去年农历同期的近两倍 春节前的迁徙规模峰值出现在1月29日 腊月廿七 春节后于2月6日达