xugenyuan

ref |> 新增一键登录逻辑

Signed-off-by: xugenyuan <xugenyuan@wondertek.com.cn>
1 export { add } from "./src/main/ets/utils/Calc" 1 export { add } from "./src/main/ets/utils/Calc"
2 -export { SettingPasswordParams } from "./src/main/ets/pages/login/SettingPasswordLayout"  
  2 +export { SettingPasswordParams } from "./src/main/ets/pages/login/SettingPasswordLayout"
  3 +
  4 +export { LoginModule } from './src/main/ets/LoginModule'
  1 +import HuaweiAuth from './utils/HuaweiAuth'
  2 +import { JumpInterceptorAction, RouterJumpInterceptor, WDRouterPage } from 'wdRouter'
  3 +import { BusinessError } from '@kit.BasicServicesKit'
  4 +import { router } from '@kit.ArkUI'
  5 +
  6 +class LoginJumpHandler implements JumpInterceptorAction {
  7 +
  8 + /// 说明是调用了跳转 WDRouterPage.loginPage 页面的行为
  9 + on(params?: object | undefined, singleMode?: boolean | undefined): boolean {
  10 +
  11 + HuaweiAuth.sharedInstance().fetchAnonymousPhone().then((anonymousPhone) => {
  12 +
  13 + router.pushUrl({url: WDRouterPage.oneKeyLoginPage.url()})
  14 + }).catch((error: string) => {
  15 + router.pushUrl({url: WDRouterPage.loginPage.url()})
  16 + })
  17 + return true
  18 + }
  19 +}
  20 +
  21 +export class LoginModule {
  22 +
  23 + static startup() {
  24 +
  25 + /// 初始化华为一键登录相关
  26 + if (HuaweiAuth.enable) {
  27 +
  28 + HuaweiAuth.sharedInstance().rePrefetchAnonymousPhone()
  29 + RouterJumpInterceptor.register(WDRouterPage.loginPage, new LoginJumpHandler())
  30 + }
  31 +
  32 + }
  33 +}
@@ -9,6 +9,10 @@ import { WDRouterPage } from 'wdRouter/src/main/ets/router/WDRouterPage'; @@ -9,6 +9,10 @@ import { WDRouterPage } from 'wdRouter/src/main/ets/router/WDRouterPage';
9 import { WDRouterRule } from 'wdRouter/src/main/ets/router/WDRouterRule'; 9 import { WDRouterRule } from 'wdRouter/src/main/ets/router/WDRouterRule';
10 import { Params } from '../../../../../../../commons/wdRouter/oh_modules/wdBean/src/main/ets/bean/content/Params' 10 import { Params } from '../../../../../../../commons/wdRouter/oh_modules/wdBean/src/main/ets/bean/content/Params'
11 import {InterestsHobbiesModel} from '../../../../../../../products/phone/src/main/ets/pages/viewModel/InterestsHobbiesModel' 11 import {InterestsHobbiesModel} from '../../../../../../../products/phone/src/main/ets/pages/viewModel/InterestsHobbiesModel'
  12 +import HuaweiAuth from '../../utils/HuaweiAuth'
  13 +import { loginComponentManager, LoginWithHuaweiIDButton } from '@hms.core.account.LoginComponent'
  14 +import { BusinessError } from '@ohos.base'
  15 +
12 @Extend(Row) 16 @Extend(Row)
13 function otherStyle() { 17 function otherStyle() {
14 .backgroundImageSize(ImageSize.Cover) 18 .backgroundImageSize(ImageSize.Cover)
@@ -56,7 +60,6 @@ struct LoginPage { @@ -56,7 +60,6 @@ struct LoginPage {
56 }) 60 })
57 loginViewModel = new LoginViewModel() 61 loginViewModel = new LoginViewModel()
58 @State isProtocol:boolean=false 62 @State isProtocol:boolean=false
59 -  
60 onCodeSend() { 63 onCodeSend() {
61 Logger.debug(TAG, "isCodeSend:" + this.isCodeSend + "") 64 Logger.debug(TAG, "isCodeSend:" + this.isCodeSend + "")
62 if (this.isCodeSend) { 65 if (this.isCodeSend) {
@@ -15,6 +15,7 @@ struct LoginProtocolWebview { @@ -15,6 +15,7 @@ struct LoginProtocolWebview {
15 userProtocol = "https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1005.html" 15 userProtocol = "https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1005.html"
16 privateProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1001.html' 16 privateProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1001.html'
17 logoutProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1003.html' 17 logoutProtocol = 'https://cdnpeoplefrontuat.aikan.pdnews.cn/rmrb/rmrb-protocol-zh-web/0.0.1/app/protocol-1003.html'
  18 + huaweiAuthProtocol = 'https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN'
18 19
19 async aboutToAppear() { 20 async aboutToAppear() {
20 if (router.getParams()) { 21 if (router.getParams()) {
@@ -30,6 +31,9 @@ struct LoginProtocolWebview { @@ -30,6 +31,9 @@ struct LoginProtocolWebview {
30 }else if(params.contentID == "3"){ //注销协议 31 }else if(params.contentID == "3"){ //注销协议
31 this.webUrl = await SPHelper.default.get(SpConstants.LOGOUT_PROTOCOL, this.logoutProtocol) as string 32 this.webUrl = await SPHelper.default.get(SpConstants.LOGOUT_PROTOCOL, this.logoutProtocol) as string
32 this.webviewController.loadUrl(this.webUrl) 33 this.webviewController.loadUrl(this.webUrl)
  34 + } else if(params.contentID == "4"){ //华为用户认证协议
  35 + this.webUrl = this.huaweiAuthProtocol
  36 + this.webviewController.loadUrl(this.webUrl)
33 } 37 }
34 } 38 }
35 39
  1 +import { router } from '@kit.ArkUI'
  2 +import { Params } from 'wdBean/Index'
  3 +import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'
  4 +import HuaweiAuth from '../../utils/HuaweiAuth'
  5 +import { BusinessError } from '@kit.BasicServicesKit'
  6 +
  7 +@Entry
  8 +@Component
  9 +struct OneKeyLoginPage {
  10 + anonymousPhone: string = ''
  11 + @State agreeProtocol: boolean = false
  12 +
  13 + aboutToAppear(): void {
  14 + this.anonymousPhone = HuaweiAuth.sharedInstance().anonymousPhone||""
  15 + }
  16 +
  17 + build() {
  18 + Column() {
  19 + this.CloseRow()
  20 +
  21 + Image($r("app.media.login_logo"))
  22 + .width(120)
  23 + .height(66)
  24 + .margin({ top: 78, bottom: 74})
  25 + .align(Alignment.Center)
  26 +
  27 + Text(this.anonymousPhone)
  28 + .fontSize(30)
  29 + .fontWeight(600)
  30 + .fontColor("#222222")
  31 + .margin({bottom: 10})
  32 + .align(Alignment.Center)
  33 +
  34 + this.ProtocolRow()
  35 +
  36 + Row() {
  37 + Button("华为账号一键登录")
  38 + .type(ButtonType.Normal)
  39 + .height(48)
  40 + .backgroundColor(!this.agreeProtocol ? Color.Grey : Color.Red)
  41 + .width("100%")
  42 + .onClick((event) => {
  43 + if (!this.agreeProtocol) {
  44 + return
  45 + }
  46 + HuaweiAuth.sharedInstance().oneKeyLogin().then((authorizeCode) => {
  47 +
  48 + //TODO: 调用服务端接口登录
  49 + }).catch((error: BusinessError) => {
  50 +
  51 + })
  52 + })
  53 + }
  54 + .padding({ left: 25, right: 25 })
  55 + .margin({top: 15})
  56 +
  57 + Button("其他手机号登录")
  58 + .type(ButtonType.Normal)
  59 + .align(Alignment.Center)
  60 + .foregroundColor("#666666")
  61 + .backgroundColor(Color.White)
  62 + .onClick((event) => {
  63 + router.replaceUrl({url: WDRouterPage.loginPage.url()})
  64 + })
  65 + }
  66 + }
  67 +
  68 + @Builder ProtocolRow() {
  69 + Row({space: 4}) {
  70 + Image(this.agreeProtocol ? $r('app.media.login_checkbox_select') : $r('app.media.login_checkbox_unselected'))
  71 + .width(15)
  72 + .height(15)
  73 + .onClick(() => {
  74 + this.agreeProtocol = !this.agreeProtocol
  75 + })
  76 + Text() {
  77 + Span("我已阅读并同意").fontColor("#999999").fontSize(12)
  78 + Span("《用户协议》").fontColor("#ED2800").fontSize(12).onClick(() => {
  79 + let bean = { contentID: "1", pageID: "" } as Params
  80 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  81 + })
  82 + Span("、").fontColor("#999999").fontSize(12)
  83 + Span("《隐私政策》").fontColor("#ED2800").fontSize(12).onClick(() => {
  84 + let bean = { contentID: "2", pageID: "" } as Params
  85 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  86 + })
  87 + Span("和").fontColor("#999999").fontSize(12)
  88 + Span("《华为账号用户认证协议》").fontColor("#ED2800").fontSize(12).onClick(() => {
  89 + let bean = { contentID: "4", pageID: "" } as Params
  90 + WDRouterRule.jumpWithPage(WDRouterPage.loginProtocolPage, bean)
  91 + })
  92 + }
  93 + .layoutWeight(1)
  94 + }
  95 + .margin({top: 15})
  96 + .padding({ left: 25, right: 25 })
  97 + .width('100%')
  98 + }
  99 +
  100 + @Builder CloseRow() {
  101 + Row() {
  102 + Blank()
  103 + Image($r('app.media.login_closed'))
  104 + .width(24)
  105 + .height(24)
  106 + .onClick(() => router.back())
  107 + }.margin({ top: 15, right: 15 })
  108 + .width("100%")
  109 + }
  110 +}
  1 +import { authentication, extendService } from '@kit.AccountKit';
  2 +import { Logger } from 'wdKit/Index';
  3 +import { util } from '@kit.ArkTS';
  4 +import { DEFAULT } from '@ohos/hypium';
  5 +import { BusinessError } from '@kit.BasicServicesKit';
  6 +
  7 +const TAG = "HuaweiOneKeyAuth"
  8 +
  9 +export default class HuaweiAuth {
  10 +
  11 + // 是否开启
  12 + static enable = false
  13 + // 匿名手机号
  14 + private _anonymousPhone?: string
  15 + get anonymousPhone() {
  16 + return this._anonymousPhone
  17 + }
  18 +
  19 + private static instance: HuaweiAuth
  20 + static sharedInstance(): HuaweiAuth {
  21 + if (!HuaweiAuth.instance) {
  22 + HuaweiAuth.instance = new HuaweiAuth()
  23 + }
  24 + return HuaweiAuth.instance
  25 + }
  26 +
  27 + // 重新预取手机号(App启动未登录、回前台未登录、和退出登录 时调用提前取号)
  28 + rePrefetchAnonymousPhone() {
  29 + this._anonymousPhone = undefined
  30 + this.fetchAnonymousPhone()
  31 + }
  32 +
  33 + // 要登录时,先调用。如果获取到手机号了 则弹起一键登录页面
  34 + fetchAnonymousPhone() : Promise<string> {
  35 +
  36 + return new Promise((resolve, fail) => {
  37 + if (this.anonymousPhone) {
  38 + resolve(this.anonymousPhone)
  39 + return
  40 + }
  41 +
  42 + let authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();
  43 + // 权限有 phone 、email、realTimePhone、quickLoginMobilePhone,这里用获取匿名手机号
  44 + authRequest.scopes = ['quickLoginAnonymousPhone'];
  45 + authRequest.state = util.generateRandomUUID();
  46 + authRequest.forceAuthorization = false;
  47 + let controller = new authentication.AuthenticationController(getContext(this));
  48 + try {
  49 + controller.executeRequest(authRequest).then((response: authentication.AuthorizationWithHuaweiIDResponse) => {
  50 + let anonymousPhone = response.data?.extraInfo?.quickLoginAnonymousPhone;
  51 + if (anonymousPhone) {
  52 + Logger.info(TAG, 'get anonymousPhone, ' + JSON.stringify(response));
  53 + this._anonymousPhone = anonymousPhone as string
  54 + resolve(this._anonymousPhone)
  55 + return;
  56 + }
  57 +
  58 + Logger.info(TAG, 'get anonymousPhone is empty. ' + JSON.stringify(response));
  59 + fail("获取匿名手机号为空")
  60 + }).catch((err: BusinessError) => {
  61 + Logger.error(TAG, 'get anonymousPhone failed. ' + JSON.stringify(err));
  62 + fail("获取匿名手机号失败")
  63 + })
  64 + } catch (err) {
  65 + Logger.error(TAG, 'get anonymousPhone fail. ' + JSON.stringify(err));
  66 + fail("获取匿名手机号失败")
  67 + }
  68 + })
  69 + }
  70 +
  71 + // 华为账号一键登录授权
  72 + // 返回结果为 Authorization Code
  73 + oneKeyLogin() : Promise<string> {
  74 +
  75 + let loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest();
  76 + // 当用户未登录华为帐号时,是否强制拉起华为帐号登录界面
  77 + loginRequest.forceLogin = true;
  78 + loginRequest.state = util.generateRandomUUID();
  79 +
  80 + return new Promise((resolve, fail) => {
  81 +
  82 + try {
  83 + let controller = new authentication.AuthenticationController(getContext(this));
  84 + controller.executeRequest(loginRequest, (err, data) => {
  85 + if (err) {
  86 + Logger.error(TAG, 'login fail, ' + JSON.stringify(err))
  87 + fail(err)
  88 + return;
  89 + }
  90 + let loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse;
  91 + let state = loginWithHuaweiIDResponse.state;
  92 + if (state != undefined && loginRequest.state != state) {
  93 + Logger.error(TAG, 'login fail, The state is different' + JSON.stringify(loginWithHuaweiIDResponse))
  94 + fail({
  95 + code: 99999,
  96 + name: "一键登录",
  97 + message:"状态错误:" + `请求状态 ${loginRequest.state}, 结果状态 ${state}`
  98 + } as BusinessError)
  99 + return;
  100 + }
  101 +
  102 + Logger.info(TAG, 'login success, ' + JSON.stringify(loginWithHuaweiIDResponse));
  103 + let loginWithHuaweiIDCredential = loginWithHuaweiIDResponse.data!;
  104 + let authorizationCode = loginWithHuaweiIDCredential.authorizationCode;
  105 + resolve(authorizationCode!)
  106 + });
  107 + } catch (error) {
  108 + Logger.error(TAG, 'login fail, ' + JSON.stringify(error))
  109 + fail(error)
  110 + }
  111 + });
  112 + }
  113 +
  114 + // 打开账户中心
  115 + openAccountCenter() {
  116 + try {
  117 + extendService.startAccountCenter(getContext(this), (err, data) => {
  118 + if (err) {
  119 + Logger.info(TAG, 'startAccountCenterWithCallback fail,error: ' + JSON.stringify(err));
  120 + return;
  121 + }
  122 + Logger.info(TAG, 'startAccountCenterWithCallback success');
  123 + });
  124 + } catch (error) {
  125 + Logger.error(TAG, 'startAccountCenterWithCallback fail,error: ' + JSON.stringify(error));
  126 + }
  127 + }
  128 +}
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 "pages/login/LoginProtocolWebview", 6 "pages/login/LoginProtocolWebview",
7 "pages/login/SettingPasswordPage", 7 "pages/login/SettingPasswordPage",
8 "pages/login/SettingPasswordLayout", 8 "pages/login/SettingPasswordLayout",
9 - "pages/guide/GuidePages" 9 + "pages/guide/GuidePages",
  10 + "pages/login/OneKeyLoginPage"
10 ] 11 ]
11 } 12 }