HarmonyOS 第三方登錄之QQ登錄
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
前言
因?yàn)轼櫭上到y(tǒng)剛出不久,官方的第三方登錄SDK還沒出來,下面就介紹下在鴻蒙應(yīng)用中實(shí)現(xiàn)QQ登錄的方法(支持喚起QQ安卓客戶端進(jìn)行授權(quán))
前期準(zhǔn)備
登錄QQ開放平臺(tái) > 應(yīng)用管理 > 創(chuàng)建應(yīng)用 ,創(chuàng)建一個(gè)網(wǎng)站應(yīng)用。
注意:要選擇網(wǎng)站應(yīng)用,移動(dòng)應(yīng)用和小程序不適用該方案。
編寫代碼
判斷是否已登錄
獲取登錄狀態(tài)
在入口AbilitySliceMainAbilitySlice中進(jìn)行判斷。
從數(shù)據(jù)庫(kù)獲取token的值判斷是否已經(jīng)登錄賬號(hào) (已登錄返回token,未登錄返回null)
- // 創(chuàng)建數(shù)據(jù)庫(kù)(這里使用官方提供的“輕量級(jí)數(shù)據(jù)存儲(chǔ)”,相關(guān)文檔:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-preference-guidelines-0000000000030083)
- Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
- // 從數(shù)據(jù)庫(kù)獲取token的值判斷是否已經(jīng)登錄賬號(hào) (已登錄返回token,未登錄返回null)
- String token = preferences.getString("token",null);
進(jìn)行相應(yīng)跳轉(zhuǎn)
已登錄跳轉(zhuǎn)至個(gè)人界面MyAbility,未登錄跳轉(zhuǎn)至登錄界面LoginAbility.
- if(token != null){
- // 已登錄,跳轉(zhuǎn)至MyAbility
- Intent myIntent = new Intent();
- myIntent.setParam("token", token);
- Operation myOperation = new Intent.OperationBuilder()
- .withBundleName("cn.dsttl3.test")
- .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
- .build();
- myIntent.setOperation(myOperation);
- startAbility(myIntent);
- terminateAbility();
- }else {
- // 未登錄,跳轉(zhuǎn)至LoginAbility
- Intent loginIntent = new Intent();
- Operation loginOperation = new Intent.OperationBuilder()
- .withBundleName("cn.dsttl3.test")
- .withAbilityName("cn.dsttl3.qqlogin.LoginAbility")
- .build();
- loginIntent.setOperation(loginOperation);
- startAbility(loginIntent);
- terminateAbility();
- }
登錄界面的操作
申請(qǐng)網(wǎng)絡(luò)訪問權(quán)限
在config.json添加
- "reqPermissions": [
- {
- "name": "ohos.permission.INTERNET"
- }
- ]
登錄界面布局文件ability_login.xml
在布局文件中添加以后webview組件
- <?xml version="1.0" encoding="utf-8"?>
- <DirectionalLayout
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:height="match_parent"
- ohos:width="match_parent"
- ohos:alignment="center"
- ohos:orientation="vertical">
- <ohos.agp.components.webengine.WebView
- ohos:id="$+id:WebView_qqlogin"
- ohos:height="match_parent"
- ohos:width="match_parent"/>
- </DirectionalLayout>
登錄界面的AbilitySlice LoginAbilitySlice.java
需要用到的幾個(gè)常量
- String state = UUID.randomUUID().toString();// 唯一標(biāo)識(shí),成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回。
- String client_id = "101***151";//QQ開放平臺(tái) 應(yīng)用 APP ID
- String redirect_uri = "https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin"; //應(yīng)用 網(wǎng)站回調(diào)域 需進(jìn)行url編碼,授權(quán)成功后會(huì)跳轉(zhuǎn)至該鏈接
- String authorize_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
- "&client_id=" + client_id +
- "&redirect_uri=" + redirect_uri +
- "&state="+ state;
WebView的配置
- WebView myWebView = (WebView) findComponentById(ResourceTable.Id_WebView_qqlogin);
- myWebView.getWebConfig().setJavaScriptPermit(true);//支持JavaScript
- myWebView.getWebConfig().setUserAgent("android");//將UserAgent設(shè)置為安卓,授權(quán)頁(yè)才顯示QQ客戶端一鍵登錄按鈕
自定義WebAgent
當(dāng)WebView即將打開一個(gè)鏈接時(shí)調(diào)用isNeedLoadUrl方法,當(dāng)在網(wǎng)頁(yè)上點(diǎn)擊“一鍵登錄”時(shí),打開QQ客戶端
wtloginmqq是QQ安卓客戶端URL Scheme
- if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
- // 打開QQ客戶端
- Intent qqIntent = new Intent();
- Operation qqOperation = new Intent.OperationBuilder()
- .withAction("android.intent.action.VIEW")
- .withUri(Uri.parse(request.getRequestUrl().toString()))
- .build();
- qqIntent.setOperation(qqOperation);
- startAbility(qqIntent);
因?yàn)槟壳斑€找不到網(wǎng)頁(yè)端喚起鴻蒙應(yīng)用的方法,所以QQ客戶端回調(diào)的code放在自己服務(wù)器處理。
授權(quán)成功后,會(huì)打開之前在QQ開放平臺(tái)設(shè)置的回調(diào)域redirect_uri
示例:https://api.dsttl3.cn/Redis/QQLogin?code=********&state=*****
code:QQ授權(quán)返回的code,用于申請(qǐng)token
state:在webview請(qǐng)求QQ授權(quán)頁(yè)面時(shí)傳入的唯一標(biāo)識(shí),用于判斷用戶身份,方便后續(xù)從服務(wù)器請(qǐng)求token
出于安全考慮 ,請(qǐng)求token操作放在服務(wù)器上執(zhí)行。獲取到token后將token存入數(shù)據(jù)庫(kù),客戶端通過請(qǐng)求https://api.dsttl3.cn/Redis/Get?key= + state來獲取到token
客戶端請(qǐng)求到token后,將token存儲(chǔ)到數(shù)據(jù)庫(kù)
- // 將token存入數(shù)據(jù)庫(kù)
- Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
- preferences.putString("token",token);
- preferences.flush();
token存儲(chǔ)完成后跳轉(zhuǎn)至MyAbility
自定義WebAgent完整代碼
- myWebView.setWebAgent(new WebAgent(){
- // 當(dāng)WebView即將打開一個(gè)鏈接時(shí)調(diào)用該方法
- @Override
- public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
- // request.getRequestUrl().toString() WebView即將打開的鏈接地址
- if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
- // 打開QQ客戶端
- Intent qqIntent = new Intent();
- Operation qqOperation = new Intent.OperationBuilder()
- .withAction("android.intent.action.VIEW")
- .withUri(Uri.parse(request.getRequestUrl().toString()))
- .build();
- qqIntent.setOperation(qqOperation);
- startAbility(qqIntent);
- // 向自己的服務(wù)器請(qǐng)求token
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (true){
- String getTokenURL = "https://api.dsttl3.cn/Redis/Get?key=" + state;
- try {
- OkHttpClient client = new OkHttpClient();
- Request request = new Request.Builder().url(getTokenURL).build();
- String token = client.newCall(request).execute().body().string();
- if (token.length() == 32){
- getUITaskDispatcher().asyncDispatch(new Runnable() {
- @Override
- public void run() {
- // 將token存入數(shù)據(jù)庫(kù)
- Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
- preferences.putString("token",token);
- preferences.flush();
- // 跳轉(zhuǎn)至用戶界面
- Intent myIntent = new Intent();
- Operation myOperation = new Intent.OperationBuilder()
- .withBundleName("cn.dsttl3.test")
- .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
- .build();
- myIntent.setOperation(myOperation);
- startAbility(myIntent);
- terminateAbility();
- }
- });
- break;
- }
- Time.sleep(1500);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }).start();
- return false;
- }
- return true;
- }
- });
加載網(wǎng)頁(yè)
- myWebView.load(authorize_url);
LoginAbilitySlice.java完整代碼
- import cn.dsttl3.qqlogin.ResourceTable;
- import ohos.aafwk.ability.AbilitySlice;
- import ohos.aafwk.content.Intent;
- import ohos.aafwk.content.Operation;
- import ohos.agp.components.webengine.ResourceRequest;
- import ohos.agp.components.webengine.WebAgent;
- import ohos.agp.components.webengine.WebView;
- import ohos.data.DatabaseHelper;
- import ohos.data.preferences.Preferences;
- import ohos.miscservices.timeutility.Time;
- import ohos.utils.net.Uri;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import java.io.IOException;
- import java.util.UUID;
- public class LoginAbilitySlice extends AbilitySlice {
- //QQ開放平臺(tái)登錄授權(quán)文檔 https://wiki.connect.qq.com/%e5%87%86%e5%a4%87%e5%b7%a5%e4%bd%9c_oauth2-0
- String state = UUID.randomUUID().toString();// 唯一標(biāo)識(shí),成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回。
- String client_id = "101547151";//QQ開放平臺(tái) 應(yīng)用 APP ID
- String redirect_uri = "https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin"; //應(yīng)用 網(wǎng)站回調(diào)域 需進(jìn)行url編碼,授權(quán)成功后會(huì)跳轉(zhuǎn)至該鏈接
- String authorize_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
- "&client_id=" + client_id +
- "&redirect_uri=" + redirect_uri +
- "&state="+ state;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_login);
- WebView myWebView = (WebView) findComponentById(ResourceTable.Id_WebView_qqlogin);
- myWebView.getWebConfig().setJavaScriptPermit(true);
- myWebView.getWebConfig().setUserAgent("android");
- myWebView.setWebAgent(new WebAgent(){
- // 當(dāng)WebView即將打開一個(gè)鏈接時(shí)調(diào)用該方法
- @Override
- public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
- // request.getRequestUrl().toString() WebView即將打開的鏈接地址
- if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
- // 打開QQ客戶端
- Intent qqIntent = new Intent();
- Operation qqOperation = new Intent.OperationBuilder()
- .withAction("android.intent.action.VIEW")
- .withUri(Uri.parse(request.getRequestUrl().toString()))
- .build();
- qqIntent.setOperation(qqOperation);
- startAbility(qqIntent);
- // 向自己的服務(wù)器請(qǐng)求token
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (true){
- String getTokenURL = "https://api.dsttl3.cn/Redis/Get?key=" + state;
- try {
- OkHttpClient client = new OkHttpClient();
- Request request = new Request.Builder().url(getTokenURL).build();
- String token = client.newCall(request).execute().body().string();
- if (token.length() == 32){
- getUITaskDispatcher().asyncDispatch(new Runnable() {
- @Override
- public void run() {
- // 將token存入數(shù)據(jù)庫(kù)
- Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
- preferences.putString("token",token);
- preferences.flush();
- // 跳轉(zhuǎn)至用戶界面
- Intent myIntent = new Intent();
- Operation myOperation = new Intent.OperationBuilder()
- .withBundleName("cn.dsttl3.test")
- .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
- .build();
- myIntent.setOperation(myOperation);
- startAbility(myIntent);
- terminateAbility();
- }
- });
- break;
- }
- Time.sleep(1500);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }).start();
- return false;
- }
- return true;
- }
- });
- myWebView.load(authorize_url);
- }
- }
個(gè)人界面
獲取token信息
- Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
- String token = preferences.getString("token",null);
更新Text數(shù)據(jù)
- Text text = findComponentById(ResourceTable.Id_text_helloworld);
- text.setText(token);
后續(xù)操作
獲取用戶信息請(qǐng)參考QQ開放平臺(tái)文檔 https://wiki.connect.qq.com/get_user_info
文章相關(guān)附件可以點(diǎn)擊下面的原文鏈接前往下載
https://harmonyos.51cto.com/resource/1554
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)