One, foreword

By before their project account system is not very perfect, so consider this powerful third-party platform access QQ access, the project temporarily use QQ login interface for their early test, this time from building to improve took two whole days, had to ridicule the QQ interconnection of official documents, can be seen from the interface,’t repair for years, I have read a lot of source code and the official demo. This demo can be used as an auxiliary reference. When the API of the official document is invalid, I can find a corresponding replacement from it. Many API seems to be invalid, the author has done some processing and improvement, almost the SDK function list login related API tried, really quite pit, the body is about to start, I hope this article can give some reference and help to the later.

Two, environment configuration

1. Obtain the application ID

This is relatively simple, apply for one to QQ interconnection official website directly, official website address

https://connect.qq.com
Copy the code

When applying for an application, ensure that the application name does not contain any illegal words; otherwise, the application may be rejected

Filling in the application information requires the package name and signature of the current application. Tencent provides an APP to obtain the package name and signature for our developers to use and download the address

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

If you fail to pass the audit, you can only log in using the QQ number of debugging. If you pass the audit, you can face all users. The following are the approved pictures

2. Download the relevant SDK from the official website

Download address

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

I would recommend downloading the latest version of retrofit, but I didn’t understand the update announcement. It said that it fixed a conflict with Retrofit, and then the new project didn’t work, so I added it

3. Introduction of JAR

Place the jar in the lib package and add the following code to build. Gradle at the app level to complete the jar reference

dependencies {
	...
    implementation fileTree(dir: 'libs'.include: '*.jar')... }Copy the code

4. The configuration of the Manifest

Add the following activities and the declaration to start the QQ application under the application node in androidmanifest.xml. There is no need to create additional files for these two activities. The jar introduced has already been handled

 <application
       .    
        <!--You must enable the network access permission and obtain the network status permission. Otherwise, you cannot log in-->
        <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 your 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>
Copy the code

The following code provides a provider for accessing the QQ application. Create an XML file with the name of the provider, and ensure that it is unique. The provider at the bottom of the code was found in the demo. Add a package XML to the RES folder and add the XML file named File_PATHS with the following contents


      
<paths>
    <external-files-path name="opensdk_external" path="Images/tmp"/>
    <root-path name="opensdk_root" path=""/>
</paths>
Copy the code

3. Initial configuration

1. Initialize the SDK

Add the following code under the activtiy create login, otherwise unable to pull up the QQ login screen, as for the official documentation requires the user to choose whether or not authorized equipment information shows that this practice is the application declared within a third-party SDK list, and then explain the SDK used in it related equipment information

Tencent.setIsPermissionGranted(true, Build.MODEL)
Copy the code

2. Create an instance

You are advised to configure these parameters globally so that you can forcibly log out of an abnormal login

/** * APP_ID specifies the ID of the provider. * context specifies the context. */
val mTencent = Tencent.createInstance(APP_ID, context, Authorities)
Copy the code

3. Enable login

Create a UIListener (UIListener, UIListener, UIListener, UIListener, UIListener, UIListener

open class BaseUiListener(private val mTencent: Tencent) : DefaultUiListener() {
    private val kv = MMKV.defaultMMKV()
    override fun onComplete(response: Any?). {
        if (response == null) {
            "Return empty, login failed".showToast()
            return
        }
        val jsonResponse = response as JSONObject
        if (jsonResponse.length() == 0) {
            "Return empty, login failed".showToast()
            return
        }
        "Login successful".showToast()
        doComplete(response)
    }

    private fun doComplete(values: JSONObject?).{}override fun onError(e: UiError) {
        Log.e("fund"."onError: ${e.errorDetail}")}override fun onCancel(a) {
        "Cancel login".showToast()
    }
}
Copy the code

Create a button to listen for login operations

button.setOnClickListener {
    
    if(! mTencent.isSessionValid) {// Determine whether the session is valid
        when (mTencent.login(this."all",iu)) {
            
            // Here are the possible return values for login
            0 -> "Normal Login".showToast()
            1 -> "Start logging in".showToast()
            -1 -> "Abnormal".showToast()
            2 -> "Login or display the download page using H5".showToast()
            else -> "Error".showToast()
        }
    }
}
Copy the code

Login (this, “all”, IU)

mTencent.login(this."all",iu)
// three arguments to the login function of the Tencent instance
//1. For the current context,
//2. Select all permissions, but there is only one open permission
//3. Is the instance object of UIlistener
Copy the code

Still missing the last step, the code to get the result of the callback, the callback of the activity, the display method has been abandoned, I wanted to change it, but I found that to change it, I need to move the source code in the SDK, so I didn’t change it, and so on

override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
    super.onActivityResult(requestCode, resultCode, data)
    // Tencent QQ callback, here iu is still associated with UIlistener
    Tencent.onActivityResultData(requestCode, resultCode, data,iu)
    if (requestCode == Constants.REQUEST_API) {
        if (resultCode == Constants.REQUEST_LOGIN) {
            Tencent.handleResultData(data, iu)
        }
    }
}
Copy the code

At this point, you can log in normally, but there is one thing that we developers care about most. Where is the user’s data? Can I get my QQ number? Below will answer this question for you.

Iv. Access process and relevant codes

By answering the above questions, you can obtain two key PIECES of JSON data. One is obtained during login, which is mainly token related data, and the other is the JSON data of the user’s personal information. These data are processed and obtained in UIListener. The answer to the second question is no, we can only obtain an ID with the same unique mark as the QQ id, namely open_id. Obviously, this is for the sake of users’ privacy and security. Next, I will briefly describe the specific login process

1. Check whether the token cache exists before login

  • If yes, start the main activity directly
  • If no, the login page is displayed

Determines whether there is a cache for login data

// Here we use wechat MMKV to store key data
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
}
Copy the code

Check whether the token and open_id are valid and whether the token has expired. The recommended usage is different from that of the official API. In short, the API provided by the official is not as effective as the MMKV key value stored login JSON. You are advised to use logs to troubleshoot errors

// uiListener is overwritten. Object acts like an anonymous class in Java
// the checkLogin method is used
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) {
                "Login failed".showToast()

            } else {
                // Start the main activity}}else {
            "Login has expired. Please log in again.".showToast()
            // Start the login activity}}override fun onError(e: UiError) {
        "Login has expired. Please log in again.".showToast()
        // Start the login activity

    }

    override fun onCancel(a) {
        "Cancel login".showToast()
    }
})
Copy the code

2. The login page is displayed

After checking that the session is valid, go to the login page and explain the return codes that may occur during login

Login.setOnClickListener {
    if(! QQLoginTestApplication.mTencent.isSessionValid) {when (QQLoginTestApplication.mTencent.login(this."all",iu)) {
            0 -> "Normal Login".showToast()
            1 -> "Start logging in".showToast()
            -1- > {"Abnormal".showToast()
                QQLoginTestApplication.mTencent.logout(QQLoginTestApplication.context)
            }
            2 -> "Login or display the download page using H5".showToast()
            else -> "Error".showToast()
        }
    }
}
Copy the code
  • 1: Normal login

    There is no need to do this, just do the relevant login processing in the callback

  • 0: The login starts

    Same as normal login

  • -1: indicates an abnormal login

    This needs to be handled a little bit. At that time, the first time I encountered this situation was that the main activity abnormally consumes the activity to return to the login interface. At this time, clicking the button on the login interface caused the abnormal situation

    "Abnormal".showToast()
    mTencent.logout(QQLoginTestApplication.context)
    Copy the code
  • 2: Use H5 to login or display the download page

    Usually, it is not caused by the installation of QQ and other software. There is no need to deal with this situation. The SDK is automatically packaged, and this situation will automatically jump to the QQ download interface

Similarly, if a UIListener occurs, you need to call a callback to transfer data

override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
    super.onActivityResult(requestCode, resultCode, data)
    // Tencent QQ callback
    Tencent.onActivityResultData(requestCode, resultCode, data,iu)
    if (requestCode == Constants.REQUEST_API) {
        if (resultCode == Constants.REQUEST_LOGIN) {
            Tencent.handleResultData(data, iu)
        }
    }
}
Copy the code

3. Enter the main activity

A button needs to be placed to perform offline operation to facilitate debugging. Meanwhile, the previous token needs to be removed to retrieve the cache of data such as the token

button.setOnClickListener {
    mTencent.logout(this)
    val  kv = MMKV.defaultMMKV()
    kv.remove("qq_login")
    // Return to the login page
    "Logged out successfully".showToast()
}
Copy the code

So far, there is a very important thing that has not been explained, that is, the cache of token data and the acquisition of personal information data. This part I wrote in the login UIlistener, when the login succeeds, the JSON data of login response and the JSON data of personal information are obtained

4. Obtain two important PIECES of JSON data

  • Json data for login

    This is easy, when we log in successfully, the response in onComplete is the data we want

    override fun onComplete(response: Any?). {
        if (response == null) {
            "Return empty, login failed".showToast()
            return
        }
        val jsonResponse = response as JSONObject
        if (jsonResponse.length() == 0) {
            "Return empty, login failed".showToast()
            return
        }
        // This uses MMKV to cache json data
        kv.encode("qq_login",response.toString())
        "Login successful".showToast()
    }
    Copy the code
  • Personal information data

    This returns normal data only if login is valid

    // First you need to use the JSON data obtained in the previous step to assign to mTencent, which is executed in the doComplete method
    private fun doComplete(values: JSONObject?). {
        // Use Gson to format objects
        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())
    }
    Copy the code

    Create a get_info method to get the data. Note that you need to set the properties of mTencent to get the normal data

    private fun getQQInfo(a){
        val qqToken = mTencent.qqToken
        // UserInfo is a class that comes with the SDK, just pass in the context and token
        val info = UserInfo(context,qqToken)
        info.getUserInfo(object :BaseUiListener(mTencent){
            override fun onComplete(response: Any?).{
                // Data is cached here
                kv.encode("qq_info",response.toString())           
            }
        })
    }
    Copy the code

5. Step pit series

Here I would like to make a joke about Tencent’s own session caching mechanism. At that time, WE looked at the existing mechanism directly instead of implementing the caching by ourselves. It is a pity that this wave of laziness failed. There are three methods saveSession, initSession and loadSession, which look very easy. Then I tried a wave of null-pointer exceptions with this mentality, and sure enough, nothing happened. I tried to modify the sequence of a wave of callback and still null-pointer exceptions, and gave up after about three hours. Mentality to get shot, finally figured out, why want to use the method of tencent provides, the cache implementation itself is quite easy, the thought of MMKV, complete read two lines of code, only changed a few code to complete the login token caching mechanism, through the inside of the demo, there seems to be implemented by these three methods, Maybe some implementation mechanism did not understand, in fact, do not want to understand, their own ideas than to see the demo is much easier, just more than a JSON object conversion process, other no difference. It is recommended that newcomers implement caching themselves, regardless of the methods provided by the SDK, which is really difficult to use.

Five, the summary

In short, the completion of QQ access was a lot of pit, but fortunately it was finally achieved, I hope the SDK of Tencent Internet can upload Github to allow more people to participate in and provide feedback, otherwise this document is the worst SDK experience. The following is attached the GIthub address of the DEMO for QQ login and the relevant demo APK for your reference, about 400 lines of code in total, much better than the official demo, welcome to leave a message if you have any questions

https://github.com/xyh-fu/QQLoginTest.git
Copy the code