因?yàn)?a target="_blank">鴻蒙系統(tǒng)剛出不久,官方的第三方登錄 SDK 還沒(méi)出來(lái),下面就介紹下在鴻蒙應(yīng)用中實(shí)現(xiàn) QQ 登錄的方法(支持喚起 QQ 安卓客戶端進(jìn)行授權(quán))。
前期準(zhǔn)備
登錄 QQ 開(kāi)放平臺(tái)→應(yīng)用管理→創(chuàng)建應(yīng)用 ,創(chuàng)建一個(gè)網(wǎng)站應(yīng)用。
https://connect.qq.com/index.html注意:要選擇網(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) Preferencespreferences=newDatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME"); //從數(shù)據(jù)庫(kù)獲取token的值判斷是否已經(jīng)登錄賬號(hào)(已登錄返回token,未登錄返回null) Stringtoken=preferences.getString("token",null);
進(jìn)行相應(yīng)跳轉(zhuǎn):已登錄跳轉(zhuǎn)至個(gè)人界面 MyAbility,未登錄跳轉(zhuǎn)至登錄界面 LoginAbility。
if(token!=null){ //已登錄,跳轉(zhuǎn)至MyAbility IntentmyIntent=newIntent(); myIntent.setParam("token",token); OperationmyOperation=newIntent.OperationBuilder() .withBundleName("cn.dsttl3.test") .withAbilityName("cn.dsttl3.qqlogin.MyAbility") .build(); myIntent.setOperation(myOperation); startAbility(myIntent); terminateAbility(); }else{ //未登錄,跳轉(zhuǎn)至LoginAbility IntentloginIntent=newIntent(); OperationloginOperation=newIntent.OperationBuilder() .withBundleName("cn.dsttl3.test") .withAbilityName("cn.dsttl3.qqlogin.LoginAbility") .build(); loginIntent.setOperation(loginOperation); startAbility(loginIntent); terminateAbility(); }
②登錄界面的操作
申請(qǐng)網(wǎng)絡(luò)訪問(wèn)權(quán)限:在 config.json 添加。
"reqPermissions":[ { "name":"ohos.permission.INTERNET" } ]
登錄界面布局文件 ability_login.xml,在布局文件中添加以后 webview 組件。
登錄界面的 AbilitySlice LoginAbilitySlice.java,需要用到的幾個(gè)常量如下:
Stringstate=UUID.randomUUID().toString();//唯一標(biāo)識(shí),成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回。 Stringclient_id="101***151";//QQ開(kāi)放平臺(tái)應(yīng)用APPID Stringredirect_uri="https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin";//應(yīng)用網(wǎng)站回調(diào)域需進(jìn)行url編碼,授權(quán)成功后會(huì)跳轉(zhuǎn)至該鏈接 Stringauthorize_url="https://graph.qq.com/oauth2.0/authorize?response_type=code"+ "&client_id="+client_id+ "&redirect_uri="+redirect_uri+ "&state="+state;
WebView 的配置:
WebViewmyWebView=(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 即將打開(kāi)一個(gè)鏈接時(shí)調(diào)用 isNeedLoadUrl 方法,當(dāng)在網(wǎng)頁(yè)上點(diǎn)擊“一鍵登錄”時(shí),打開(kāi) QQ 客戶端。
wtloginmqq 是 QQ 安卓客戶端 URL Scheme:
if(request.getRequestUrl().toString().startsWith("wtloginmqq")){ //打開(kāi)QQ客戶端 IntentqqIntent=newIntent(); OperationqqOperation=newIntent.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ì)打開(kāi)之前在 QQ 開(kāi)放平臺(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ù),客戶端通過(guò)請(qǐng)求 https://api.dsttl3.cn/Redis/Get?key= + state 來(lái)獲取到 token。
客戶端請(qǐng)求到 token 后,將 token 存儲(chǔ)到數(shù)據(jù)庫(kù):
//將token存入數(shù)據(jù)庫(kù) Preferencespreferences=newDatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME"); preferences.putString("token",token); preferences.flush();
token 存儲(chǔ)完成后跳轉(zhuǎn)至 MyAbility,自定義 WebAgent 完整代碼:
myWebView.setWebAgent(newWebAgent(){ //當(dāng)WebView即將打開(kāi)一個(gè)鏈接時(shí)調(diào)用該方法 @Override publicbooleanisNeedLoadUrl(WebViewwebView,ResourceRequestrequest){ //request.getRequestUrl().toString()WebView即將打開(kāi)的鏈接地址 if(request.getRequestUrl().toString().startsWith("wtloginmqq")){ //打開(kāi)QQ客戶端 IntentqqIntent=newIntent(); OperationqqOperation=newIntent.OperationBuilder() .withAction("android.intent.action.VIEW") .withUri(Uri.parse(request.getRequestUrl().toString())) .build(); qqIntent.setOperation(qqOperation); startAbility(qqIntent); //向自己的服務(wù)器請(qǐng)求token newThread(newRunnable(){ @Override publicvoidrun(){ while(true){ StringgetTokenURL="https://api.dsttl3.cn/Redis/Get?key="+state; try{ OkHttpClientclient=newOkHttpClient(); Requestrequest=newRequest.Builder().url(getTokenURL).build(); Stringtoken=client.newCall(request).execute().body().string(); if(token.length()==32){ getUITaskDispatcher().asyncDispatch(newRunnable(){ @Override publicvoidrun(){ //將token存入數(shù)據(jù)庫(kù) Preferencespreferences=newDatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME"); preferences.putString("token",token); preferences.flush(); //跳轉(zhuǎn)至用戶界面 IntentmyIntent=newIntent(); OperationmyOperation=newIntent.OperationBuilder() .withBundleName("cn.dsttl3.test") .withAbilityName("cn.dsttl3.qqlogin.MyAbility") .build(); myIntent.setOperation(myOperation); startAbility(myIntent); terminateAbility(); } }); break; } Time.sleep(1500); }catch(IOExceptione){ e.printStackTrace(); } } } }).start(); returnfalse; } returntrue; } });
加載網(wǎng)頁(yè):
myWebView.load(authorize_url);
LoginAbilitySlice.java 完整代碼:
importcn.dsttl3.qqlogin.ResourceTable; importohos.aafwk.ability.AbilitySlice; importohos.aafwk.content.Intent; importohos.aafwk.content.Operation; importohos.agp.components.webengine.ResourceRequest; importohos.agp.components.webengine.WebAgent; importohos.agp.components.webengine.WebView; importohos.data.DatabaseHelper; importohos.data.preferences.Preferences; importohos.miscservices.timeutility.Time; importohos.utils.net.Uri; importokhttp3.OkHttpClient; importokhttp3.Request; importjava.io.IOException; importjava.util.UUID; publicclassLoginAbilitySliceextendsAbilitySlice{ //QQ開(kāi)放平臺(tái)登錄授權(quán)文檔https://wiki.connect.qq.com/%e5%87%86%e5%a4%87%e5%b7%a5%e4%bd%9c_oauth2-0 Stringstate=UUID.randomUUID().toString();//唯一標(biāo)識(shí),成功授權(quán)后回調(diào)時(shí)會(huì)原樣帶回。 Stringclient_id="101547151";//QQ開(kāi)放平臺(tái)應(yīng)用APPID Stringredirect_uri="https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin";//應(yīng)用網(wǎng)站回調(diào)域需進(jìn)行url編碼,授權(quán)成功后會(huì)跳轉(zhuǎn)至該鏈接 Stringauthorize_url="https://graph.qq.com/oauth2.0/authorize?response_type=code"+ "&client_id="+client_id+ "&redirect_uri="+redirect_uri+ "&state="+state; @Override publicvoidonStart(Intentintent){ super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_login); WebViewmyWebView=(WebView)findComponentById(ResourceTable.Id_WebView_qqlogin); myWebView.getWebConfig().setJavaScriptPermit(true); myWebView.getWebConfig().setUserAgent("android"); myWebView.setWebAgent(newWebAgent(){ //當(dāng)WebView即將打開(kāi)一個(gè)鏈接時(shí)調(diào)用該方法 @Override publicbooleanisNeedLoadUrl(WebViewwebView,ResourceRequestrequest){ //request.getRequestUrl().toString()WebView即將打開(kāi)的鏈接地址 if(request.getRequestUrl().toString().startsWith("wtloginmqq")){ //打開(kāi)QQ客戶端 IntentqqIntent=newIntent(); OperationqqOperation=newIntent.OperationBuilder() .withAction("android.intent.action.VIEW") .withUri(Uri.parse(request.getRequestUrl().toString())) .build(); qqIntent.setOperation(qqOperation); startAbility(qqIntent); //向自己的服務(wù)器請(qǐng)求token newThread(newRunnable(){ @Override publicvoidrun(){ while(true){ StringgetTokenURL="https://api.dsttl3.cn/Redis/Get?key="+state; try{ OkHttpClientclient=newOkHttpClient(); Requestrequest=newRequest.Builder().url(getTokenURL).build(); Stringtoken=client.newCall(request).execute().body().string(); if(token.length()==32){ getUITaskDispatcher().asyncDispatch(newRunnable(){ @Override publicvoidrun(){ //將token存入數(shù)據(jù)庫(kù) Preferencespreferences=newDatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME"); preferences.putString("token",token); preferences.flush(); //跳轉(zhuǎn)至用戶界面 IntentmyIntent=newIntent(); OperationmyOperation=newIntent.OperationBuilder() .withBundleName("cn.dsttl3.test") .withAbilityName("cn.dsttl3.qqlogin.MyAbility") .build(); myIntent.setOperation(myOperation); startAbility(myIntent); terminateAbility(); } }); break; } Time.sleep(1500); }catch(IOExceptione){ e.printStackTrace(); } } } }).start(); returnfalse; } returntrue; } }); myWebView.load(authorize_url); } }
個(gè)人界面,獲取 token 信息:
Preferencespreferences=newDatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME"); Stringtoken=preferences.getString("token",null);
更新 Text 數(shù)據(jù):
Texttext=findComponentById(ResourceTable.Id_text_helloworld); text.setText(token);
后續(xù)操作
獲取用戶信息請(qǐng)參考 QQ 開(kāi)放平臺(tái)文檔:
https://wiki.connect.qq.com/get_user_info
附件下載:
https://harmonyos.51cto.com/posts/9448
原文標(biāo)題:在鴻蒙上實(shí)現(xiàn)QQ第三方登錄!
文章出處:【微信公眾號(hào):HarmonyOS技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
數(shù)據(jù)庫(kù)
+關(guān)注
關(guān)注
7文章
3763瀏覽量
64274 -
SDK
+關(guān)注
關(guān)注
3文章
1026瀏覽量
45775 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2307瀏覽量
42737
原文標(biāo)題:在鴻蒙上實(shí)現(xiàn)QQ第三方登錄!
文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論