服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - 编程技术 - HarmonyOS 第三方登录之QQ登录

HarmonyOS 第三方登录之QQ登录

2021-12-06 23:41鸿蒙社区dsttl3点cn 编程技术

因为鸿蒙系统刚出不久,官方的第三方登录SDK还没出来,下面就介绍下在鸿蒙应用中实现QQ登录的方法(支持唤起QQ安卓客户端进行授权)

HarmonyOS 第三方登录之QQ登录

前言

因为鸿蒙系统刚出不久,官方的第三方登录SDK还没出来,下面就介绍下在鸿蒙应用中实现QQ登录的方法(支持唤起QQ安卓客户端进行授权)

前期准备

登录QQ开放平台 > 应用管理 > 创建应用 ,创建一个网站应用。

注意:要选择网站应用,移动应用和小程序不适用该方案。

编写代码

判断是否已登录

获取登录状态

在入口AbilitySliceMainAbilitySlice中进行判断。

从数据库获取token的值判断是否已经登录账号 (已登录返回token,未登录返回null)

  1. // 创建数据库(这里使用官方提供的“轻量级数据存储”,相关文档:https://developer.harmonyos.com/cn/docs/documentation/doc-guides/database-preference-guidelines-0000000000030083)
  2. Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
  3. // 从数据库获取token的值判断是否已经登录账号 (已登录返回token,未登录返回null)
  4. String token = preferences.getString("token",null);

进行相应跳转

已登录跳转至个人界面MyAbility,未登录跳转至登录界面LoginAbility.

  1. if(token != null){
  2. // 已登录,跳转至MyAbility
  3. Intent myIntent = new Intent();
  4. myIntent.setParam("token", token);
  5. Operation myOperation = new Intent.OperationBuilder()
  6. .withBundleName("cn.dsttl3.test")
  7. .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
  8. .build();
  9. myIntent.setOperation(myOperation);
  10. startAbility(myIntent);
  11. terminateAbility();
  12. }else {
  13. // 未登录,跳转至LoginAbility
  14. Intent loginIntent = new Intent();
  15. Operation loginOperation = new Intent.OperationBuilder()
  16. .withBundleName("cn.dsttl3.test")
  17. .withAbilityName("cn.dsttl3.qqlogin.LoginAbility")
  18. .build();
  19. loginIntent.setOperation(loginOperation);
  20. startAbility(loginIntent);
  21. terminateAbility();
  22. }

登录界面的操作

申请网络访问权限

在config.json添加

  1. "reqPermissions": [
  2. {
  3. "name": "ohos.permission.INTERNET"
  4. }
  5. ]

登录界面布局文件ability_login.xml

在布局文件中添加以后webview组件

  1. "1.0" encoding="utf-8"?>
  2. xmlns:ohos="http://schemas.huawei.com/res/ohos"
  3. ohos:height="match_parent"
  4. ohos:width="match_parent"
  5. ohos:alignment="center"
  6. ohos:orientation="vertical">
  7. ohos:id="$+id:WebView_qqlogin"
  8. ohos:height="match_parent"
  9. ohos:width="match_parent"/>

登录界面的AbilitySlice LoginAbilitySlice.java

需要用到的几个常量

  1. String state = UUID.randomUUID().toString();// 唯一标识,成功授权后回调时会原样带回。
  2. String client_id = "101***151";//QQ开放平台 应用 APP ID
  3. String redirect_uri = "https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin"; //应用 网站回调域 需进行url编码,授权成功后会跳转至该链接
  4. String authorize_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
  5. "&client_id=" + client_id +
  6. "&redirect_uri=" + redirect_uri +
  7. "&state="+ state;

WebView的配置

  1. WebView myWebView = (WebView) findComponentById(ResourceTable.Id_WebView_qqlogin);
  2. myWebView.getWebConfig().setJavaScriptPermit(true);//支持JavaScript
  3. myWebView.getWebConfig().setUserAgent("android");//将UserAgent设置为安卓,授权页才显示QQ客户端一键登录按钮

自定义WebAgent

当WebView即将打开一个链接时调用isNeedLoadUrl方法,当在网页上点击“一键登录”时,打开QQ客户端

wtloginmqq是QQ安卓客户端URL Scheme

  1. if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
  2. // 打开QQ客户端
  3. Intent qqIntent = new Intent();
  4. Operation qqOperation = new Intent.OperationBuilder()
  5. .withAction("android.intent.action.VIEW")
  6. .withUri(Uri.parse(request.getRequestUrl().toString()))
  7. .build();
  8. qqIntent.setOperation(qqOperation);
  9. startAbility(qqIntent);

因为目前还找不到网页端唤起鸿蒙应用的方法,所以QQ客户端回调的code放在自己服务器处理。

授权成功后,会打开之前在QQ开放平台设置的回调域redirect_uri

示例:https://api.dsttl3.cn/Redis/QQLogin?code=********&state=*****

code:QQ授权返回的code,用于申请token

state:在webview请求QQ授权页面时传入的唯一标识,用于判断用户身份,方便后续从服务器请求token

出于安全考虑 ,请求token操作放在服务器上执行。获取到token后将token存入数据库,客户端通过请求https://api.dsttl3.cn/Redis/Get?key= + state来获取到token

客户端请求到token后,将token存储到数据库

  1. // 将token存入数据库
  2. Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
  3. preferences.putString("token",token);
  4. preferences.flush();

token存储完成后跳转至MyAbility

自定义WebAgent完整代码

  1. myWebView.setWebAgent(new WebAgent(){
  2. // 当WebView即将打开一个链接时调用该方法
  3. @Override
  4. public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
  5. // request.getRequestUrl().toString() WebView即将打开的链接地址
  6. if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
  7. // 打开QQ客户端
  8. Intent qqIntent = new Intent();
  9. Operation qqOperation = new Intent.OperationBuilder()
  10. .withAction("android.intent.action.VIEW")
  11. .withUri(Uri.parse(request.getRequestUrl().toString()))
  12. .build();
  13. qqIntent.setOperation(qqOperation);
  14. startAbility(qqIntent);
  15. // 向自己的服务器请求token
  16. new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. while (true){
  20. String getTokenURL = "https://api.dsttl3.cn/Redis/Get?key=" + state;
  21. try {
  22. OkHttpClient client = new OkHttpClient();
  23. Request request = new Request.Builder().url(getTokenURL).build();
  24. String token = client.newCall(request).execute().body().string();
  25. if (token.length() == 32){
  26. getUITaskDispatcher().asyncDispatch(new Runnable() {
  27. @Override
  28. public void run() {
  29. // 将token存入数据库
  30. Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
  31. preferences.putString("token",token);
  32. preferences.flush();
  33. // 跳转至用户界面
  34. Intent myIntent = new Intent();
  35. Operation myOperation = new Intent.OperationBuilder()
  36. .withBundleName("cn.dsttl3.test")
  37. .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
  38. .build();
  39. myIntent.setOperation(myOperation);
  40. startAbility(myIntent);
  41. terminateAbility();
  42. }
  43. });
  44. break;
  45. }
  46. Time.sleep(1500);
  47. } catch (IOException e) {
  48. e.printStackTrace();
  49. }
  50. }
  51. }
  52. }).start();
  53. return false;
  54. }
  55. return true;
  56. }
  57. });

加载网页

  1. myWebView.load(authorize_url);

LoginAbilitySlice.java完整代码

  1. import cn.dsttl3.qqlogin.ResourceTable;
  2. import ohos.aafwk.ability.AbilitySlice;
  3. import ohos.aafwk.content.Intent;
  4. import ohos.aafwk.content.Operation;
  5. import ohos.agp.components.webengine.ResourceRequest;
  6. import ohos.agp.components.webengine.WebAgent;
  7. import ohos.agp.components.webengine.WebView;
  8. import ohos.data.DatabaseHelper;
  9. import ohos.data.preferences.Preferences;
  10. import ohos.miscservices.timeutility.Time;
  11. import ohos.utils.net.Uri;
  12. import okhttp3.OkHttpClient;
  13. import okhttp3.Request;
  14. import java.io.IOException;
  15. import java.util.UUID;
  16. public class LoginAbilitySlice extends AbilitySlice {
  17. //QQ开放平台登录授权文档 https://wiki.connect.qq.com/%e5%87%86%e5%a4%87%e5%b7%a5%e4%bd%9c_oauth2-0
  18. String state = UUID.randomUUID().toString();// 唯一标识,成功授权后回调时会原样带回。
  19. String client_id = "101547151";//QQ开放平台 应用 APP ID
  20. String redirect_uri = "https%3A%2F%2Fapi.dsttl3.cn%2FRedis%2FQQLogin"; //应用 网站回调域 需进行url编码,授权成功后会跳转至该链接
  21. String authorize_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
  22. "&client_id=" + client_id +
  23. "&redirect_uri=" + redirect_uri +
  24. "&state="+ state;
  25. @Override
  26. public void onStart(Intent intent) {
  27. super.onStart(intent);
  28. super.setUIContent(ResourceTable.Layout_ability_login);
  29. WebView myWebView = (WebView) findComponentById(ResourceTable.Id_WebView_qqlogin);
  30. myWebView.getWebConfig().setJavaScriptPermit(true);
  31. myWebView.getWebConfig().setUserAgent("android");
  32. myWebView.setWebAgent(new WebAgent(){
  33. // 当WebView即将打开一个链接时调用该方法
  34. @Override
  35. public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
  36. // request.getRequestUrl().toString() WebView即将打开的链接地址
  37. if (request.getRequestUrl().toString().startsWith("wtloginmqq")){
  38. // 打开QQ客户端
  39. Intent qqIntent = new Intent();
  40. Operation qqOperation = new Intent.OperationBuilder()
  41. .withAction("android.intent.action.VIEW")
  42. .withUri(Uri.parse(request.getRequestUrl().toString()))
  43. .build();
  44. qqIntent.setOperation(qqOperation);
  45. startAbility(qqIntent);
  46. // 向自己的服务器请求token
  47. new Thread(new Runnable() {
  48. @Override
  49. public void run() {
  50. while (true){
  51. String getTokenURL = "https://api.dsttl3.cn/Redis/Get?key=" + state;
  52. try {
  53. OkHttpClient client = new OkHttpClient();
  54. Request request = new Request.Builder().url(getTokenURL).build();
  55. String token = client.newCall(request).execute().body().string();
  56. if (token.length() == 32){
  57. getUITaskDispatcher().asyncDispatch(new Runnable() {
  58. @Override
  59. public void run() {
  60. // 将token存入数据库
  61. Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
  62. preferences.putString("token",token);
  63. preferences.flush();
  64. // 跳转至用户界面
  65. Intent myIntent = new Intent();
  66. Operation myOperation = new Intent.OperationBuilder()
  67. .withBundleName("cn.dsttl3.test")
  68. .withAbilityName("cn.dsttl3.qqlogin.MyAbility")
  69. .build();
  70. myIntent.setOperation(myOperation);
  71. startAbility(myIntent);
  72. terminateAbility();
  73. }
  74. });
  75. break;
  76. }
  77. Time.sleep(1500);
  78. } catch (IOException e) {
  79. e.printStackTrace();
  80. }
  81. }
  82. }
  83. }).start();
  84. return false;
  85. }
  86. return true;
  87. }
  88. });
  89. myWebView.load(authorize_url);
  90. }
  91. }

个人界面

获取token信息

  1. Preferences preferences = new DatabaseHelper(getApplicationContext()).getPreferences("DATA_NAME");
  2. String token = preferences.getString("token",null);

更新Text数据

  1. Text text = findComponentById(ResourceTable.Id_text_helloworld);
  2. text.setText(token);

后续操作

获取用户信息请参考QQ开放平台文档 https://wiki.connect.qq.com/get_user_info

文章相关附件可以点击下面的原文链接前往下载

https://harmonyos.51cto.com/resource/1554

原文链接:https://harmonyos.51cto.com

延伸 · 阅读

精彩推荐