一、介紹
基于鴻蒙Next模擬賬號(hào)一鍵登錄,免去賬號(hào)注冊(cè)環(huán)節(jié)
二、場(chǎng)景需求
- 用戶(hù)場(chǎng)景
新用戶(hù): 需要快速注冊(cè)并登錄,以體驗(yàn)華為的服務(wù)。
老用戶(hù): 希望快速登錄,不用每次輸入用戶(hù)名和密碼。
三、業(yè)務(wù)步驟
第一步:點(diǎn)擊“一鍵登錄”,獲取登錄信息
第二步:拉起授權(quán)彈窗
第三步:獲取授權(quán),獲取用戶(hù)信息
第四步:展示用戶(hù)信息,顯示功能選項(xiàng)
四、開(kāi)發(fā)準(zhǔn)備
配置Client ID
1.登錄AppGallery Connect平臺(tái),在“我的項(xiàng)目”中選擇目標(biāo)應(yīng)用,在“項(xiàng)目設(shè)置 > 常規(guī) > 應(yīng)用”區(qū)域獲取“OAuth 2.0客戶(hù)端ID(憑據(jù))”處的Client ID。

2.在工程中entry模塊的module.json5文件中,新增metadata,配置name為client_id,value為上一步獲取的Client ID的值,如下所示:

配置scope權(quán)限
具體配置步驟大家可以移步官網(wǎng)查看配置scope權(quán)限
華為賬號(hào)服務(wù)需要遵循華為登錄UX設(shè)計(jì)規(guī)范。

3.導(dǎo)入Account Kit的authentication模塊及相關(guān)公共模塊
import { authentication } from '@kit.AccountKit';
import { util } from '@kit.ArkTS';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
4.調(diào)用authentication模塊的AuthorizationWithHuaweiIDRequest請(qǐng)求獲取華為賬號(hào)用戶(hù)的UnionID、OpenID、匿名手機(jī)號(hào)。匿名手機(jī)號(hào)用于登錄頁(yè)面展示。
getQuickLoginAnonymousPhone() {
// 創(chuàng)建授權(quán)請(qǐng)求,并設(shè)置參數(shù)
const authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();
// 獲取匿名手機(jī)號(hào)需傳quickLoginAnonymousPhone這個(gè)scope,傳參之前需要先申請(qǐng)“華為賬號(hào)一鍵登錄”權(quán)限
authRequest.scopes = ['quickLoginAnonymousPhone'];
// 用于防跨站點(diǎn)請(qǐng)求偽造
authRequest.state = util.generateRandomUUID();
// 一鍵登錄場(chǎng)景該參數(shù)必須設(shè)置為false
authRequest.forceAuthorization = false;
const controller = new authentication.AuthenticationController();
try {
controller.executeRequest(authRequest).then((response: authentication.AuthorizationWithHuaweiIDResponse) => {
// 獲取到UnionID、OpenID、匿名手機(jī)號(hào)
const unionID = response.data?.unionID;
const openID = response.data?.openID;
const anonymousPhone = response.data?.extraInfo?.quickLoginAnonymousPhone as string;
if (anonymousPhone) {
hilog.info(0x0000, 'testTag', 'Succeeded in authentication.');
const quickLoginAnonymousPhone: string = anonymousPhone;
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in authentication. AnonymousPhone is empty.');
// 未獲取到匿名手機(jī)號(hào)需要跳轉(zhuǎn)到應(yīng)用自定義的登錄頁(yè)面
}).catch((error: BusinessError) => {
this.dealAllError(error);
})
} catch (error) {
this.dealAllError(error);
}
}
// 錯(cuò)誤處理
dealAllError(error: BusinessError): void {
hilog.error(0x0000, 'testTag',
`Failed to get quickLoginAnonymousPhone, errorCode is ${error.code}, errorMessage is ${error.message}`);
}
4.將獲取到的匿名手機(jī)號(hào)設(shè)置給下面QuickLoginButtonComponent組件示例代碼中的quickLoginAnonymousPhone變量,調(diào)用LoginWithHuaweiIDButton組件,實(shí)現(xiàn)應(yīng)用自己的登錄頁(yè)面,并展示華為賬號(hào)一鍵登錄按鈕和華為賬號(hào)用戶(hù)認(rèn)證協(xié)議(Account Kit提供跳轉(zhuǎn)鏈接,應(yīng)用需實(shí)現(xiàn)協(xié)議跳轉(zhuǎn),參見(jiàn)約束與限制第2點(diǎn)),用戶(hù)同意協(xié)議并點(diǎn)擊一鍵登錄按鈕后,可獲取到Authorization Code,將該值傳給應(yīng)用服務(wù)器用于獲取用戶(hù)信息(完整手機(jī)號(hào)、UnionID、OpenID)。
import { loginComponentManager, LoginWithHuaweiIDButton } from '@kit.AccountKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { promptAction, router } from '@kit.ArkUI';
import { connection } from '@kit.NetworkKit';
@Component
struct QuickLoginButtonComponent {
logTag: string = 'QuickLoginButtonComponent';
domainId: number = 0x0000;
// 第二步獲取的匿名化手機(jī)號(hào)傳到此處
@State quickLoginAnonymousPhone: string = '';
// 是否勾選協(xié)議
@State isSelected: boolean = false;
// 華為賬號(hào)用戶(hù)認(rèn)證協(xié)議鏈接,此處僅為示例,實(shí)際開(kāi)發(fā)過(guò)程中,出于可維護(hù)性、安全性等方面考慮,域名不建議硬編碼在本地
private static USER_AUTHENTICATION_PROTOCOL: string =
'https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN';
private static USER_SERVICE_TAG = '用戶(hù)服務(wù)協(xié)議';
private static PRIVACY_TAG = '隱私協(xié)議';
private static USER_AUTHENTICATION_TAG = '華為賬號(hào)用戶(hù)認(rèn)證協(xié)議';
// 定義LoginWithHuaweiIDButton展示的隱私文本,展示應(yīng)用的用戶(hù)服務(wù)協(xié)議、隱私協(xié)議和華為賬號(hào)用戶(hù)認(rèn)證協(xié)議
privacyText: loginComponentManager.PrivacyText[] = [{
text: '已閱讀并同意',
type: loginComponentManager.TextType.PLAIN_TEXT
}, {
text: '《用戶(hù)服務(wù)協(xié)議》',
tag: QuickLoginButtonComponent.USER_SERVICE_TAG,
type: loginComponentManager.TextType.RICH_TEXT
}, {
text: '《隱私協(xié)議》',
tag: QuickLoginButtonComponent.PRIVACY_TAG,
type: loginComponentManager.TextType.RICH_TEXT
}, {
text: '和',
type: loginComponentManager.TextType.PLAIN_TEXT
}, {
text: '《華為賬號(hào)用戶(hù)認(rèn)證協(xié)議》',
tag: QuickLoginButtonComponent.USER_AUTHENTICATION_TAG,
type: loginComponentManager.TextType.RICH_TEXT
}, {
text: '。',
type: loginComponentManager.TextType.PLAIN_TEXT
}];
// 構(gòu)造LoginWithHuaweiIDButton組件的控制器
controller: loginComponentManager.LoginWithHuaweiIDButtonController =
new loginComponentManager.LoginWithHuaweiIDButtonController()
/**
* 當(dāng)應(yīng)用使用自定義的登錄頁(yè)時(shí),如果用戶(hù)未同意協(xié)議,需要設(shè)置協(xié)議狀態(tài)為NOT_ACCEPTED,當(dāng)用戶(hù)同意協(xié)議后再設(shè)置
* 協(xié)議狀態(tài)為ACCEPTED,才可以使用華為賬號(hào)一鍵登錄功能
*/
.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED)
.onClickLoginWithHuaweiIDButton((error: BusinessError | undefined,
response: loginComponentManager.HuaweiIDCredential) => {
this.handleLoginWithHuaweiIDButton(error, response);
})
.onClickEvent((error: BusinessError, clickEvent: loginComponentManager.ClickEvent) => {
if (error) {
this.dealAllError(error);
return;
}
hilog.info(this.domainId, this.logTag, `onClickEvent clickEvent: ${clickEvent}`);
});
agreementDialog: CustomDialogController = new CustomDialogController({
builder: AgreementDialog({
privacyText: this.privacyText,
cancel: () => {
this.agreementDialog.close();
this.controller.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED);
},
confirm: () => {
this.agreementDialog.close();
this.isSelected = true;
this.controller.setAgreementStatus(loginComponentManager.AgreementStatus.ACCEPTED);
// 調(diào)用此方法,同意協(xié)議與登錄一并完成,無(wú)需再次點(diǎn)擊登錄按鈕
this.controller.continueLogin((error: BusinessError) => {
if (error) {
hilog.error(this.domainId, this.logTag,
`Failed to login with agreementDialog. errCode is ${error.code}, errMessage is ${error.message}`);
} else {
hilog.info(this.domainId, this.logTag,
'Succeeded in clicking agreementDialog continueLogin.');
}
});
},
clickHyperlinkText: () => {
this.agreementDialog.close();
this.jumpToPrivacyWebView();
}
}),
autoCancel: false,
alignment: DialogAlignment.Center,
});
// 傳遞頁(yè)面渲染所需的數(shù)據(jù),如匿名手機(jī)號(hào)等
aboutToAppear(): void {
}
// Toast提示
showToast(resource: string) {
try {
promptAction.showToast({
message: resource,
duration: 2000
});
} catch (error) {
const message = (error as BusinessError).message
const code = (error as BusinessError).code
hilog.error(this.domainId, this.logTag, `showToast args errCode is ${code}, errMessage is ${message}`);
}
}
// 跳轉(zhuǎn)華為賬號(hào)用戶(hù)認(rèn)證協(xié)議頁(yè),該頁(yè)面需在工程main_pages.json文件配置
jumpToPrivacyWebView() {
try {
// 需在module.json5中配置“ohos.permission.GET_NETWORK_INFO”權(quán)限
const checkNetConn = connection.hasDefaultNetSync();
if (!checkNetConn) {
this.showToast('服務(wù)或網(wǎng)絡(luò)異常,請(qǐng)稍后重試');
return;
}
} catch (error) {
const message = error.message as string;
const code = error.code as string;
hilog.error(0x0000, 'testTag', `Failed to hasDefaultNetSync, errCode is ${code}, errMessage is ${message}`);
}
router.pushUrl({
// 需在module.json5配置“ohos.permission.INTERNET”網(wǎng)絡(luò)權(quán)限
url: 'pages/WebPage',
params: {
isFromDialog: true,
url: QuickLoginButtonComponent.USER_AUTHENTICATION_PROTOCOL,
}
}, (err) => {
if (err) {
hilog.error(this.domainId, this.logTag,
`Failed to jumpToPrivacyWebView, errCode is ${err.code}, errMessage is ${err.message}`);
}
});
}
handleLoginWithHuaweiIDButton(error: BusinessError | undefined,
response: loginComponentManager.HuaweiIDCredential) {
if (error) {
hilog.error(this.domainId, this.logTag,
`Failed to login with LoginWithHuaweiIDButton. errCode is ${error.code}, errMessage is ${error.message}`);
if (error.code === ErrorCode.ERROR_CODE_NETWORK_ERROR) {
AlertDialog.show(
{
message: "網(wǎng)絡(luò)未連接,請(qǐng)檢查網(wǎng)絡(luò)設(shè)置。",
offset: { dx: 0, dy: -12 },
alignment: DialogAlignment.Bottom,
autoCancel: false,
confirm: {
value: "知道了",
action: () => {
}
}
}
);
} else if (error.code === ErrorCode.ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED) {
// 未同意協(xié)議,彈出協(xié)議彈框,推薦使用該回調(diào)方式
this.agreementDialog.open();
} else if (error.code === ErrorCode.ERROR_CODE_LOGIN_OUT) {
// 華為賬號(hào)未登錄提示
this.showToast("華為賬號(hào)未登錄,請(qǐng)重試");
} else if (error.code === ErrorCode.ERROR_CODE_NOT_SUPPORTED) {
// 不支持該scopes或permissions提示
this.showToast("該scopes或permissions不支持");
} else if (error.code === ErrorCode.ERROR_CODE_PARAMETER_ERROR) {
// 參數(shù)錯(cuò)誤提示
this.showToast("參數(shù)錯(cuò)誤");
} else {
// 其他提示系統(tǒng)或服務(wù)異常
this.showToast('服務(wù)或網(wǎng)絡(luò)異常,請(qǐng)稍后重試');
}
return;
}
try {
if (this.isSelected) {
if (response) {
hilog.info(this.domainId, this.logTag, 'Succeeded in clicking LoginWithHuaweiIDButton.');
// 開(kāi)發(fā)者根據(jù)實(shí)際業(yè)務(wù)情況使用以下信息
const authCode = response.authorizationCode;
const openID = response.openID;
const unionID = response.unionID;
const idToken = response.idToken;
}
} else {
this.agreementDialog.open();
}
} catch (err) {
hilog.error(this.domainId, this.logTag,
`Failed to login with LoginWithHuaweiIDButton, errCode: ${err.code}, errMessage: ${err.message}`);
AlertDialog.show(
{
message: '服務(wù)或網(wǎng)絡(luò)異常,請(qǐng)稍后重試',
offset: { dx: 0, dy: -12 },
alignment: DialogAlignment.Bottom,
autoCancel: false,
confirm: {
value: '知道了',
action: () => {
}
}
}
);
}
}
// 錯(cuò)誤處理
dealAllError(error: BusinessError): void {
hilog.error(this.domainId, this.logTag,
`Failed to login, errorCode is ${error.code}, errorMessage is ${error.message}`);
}
build() {
Scroll() {
Column() {
Column() {
Column() {
Image($r('app.media.app_icon'))
.width(48)
.height(48)
.draggable(false)
.copyOption(CopyOptions.None)
.onComplete(() => {
hilog.info(this.domainId, this.logTag, 'appIcon loading success.');
})
.onError(() => {
hilog.error(this.domainId, this.logTag, 'appIcon loading fail.');
})
Text($r('app.string.app_name'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.fontWeight(FontWeight.Bold)
.maxFontSize($r('sys.float.ohos_id_text_size_headline8'))
.minFontSize($r('sys.float.ohos_id_text_size_body1'))
.maxLines(1)
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.constraintSize({ maxWidth: '100%' })
.margin({
top: 12,
})
Text('應(yīng)用描述')
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontColor($r('sys.color.ohos_id_color_text_secondary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_regular'))
.fontWeight(FontWeight.Regular)
.constraintSize({ maxWidth: '100%' })
.margin({
top: 8,
})
}.margin({
top: 100
})
Column() {
Text(this.quickLoginAnonymousPhone)
.fontSize(36)
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Bold)
.lineHeight(48)
.textAlign(TextAlign.Center)
.maxLines(1)
.constraintSize({ maxWidth: '100%', minHeight: 48 })
Text('華為賬號(hào)綁定號(hào)碼')
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontColor($r('sys.color.ohos_id_color_text_secondary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_regular'))
.fontWeight(FontWeight.Regular)
.lineHeight(19)
.textAlign(TextAlign.Center)
.maxLines(1)
.constraintSize({ maxWidth: '100%' })
.margin({
top: 8
})
}.margin({
top: 64
})
Column() {
LoginWithHuaweiIDButton({
params: {
// LoginWithHuaweiIDButton支持的樣式
style: loginComponentManager.Style.BUTTON_RED,
// 賬號(hào)登錄按鈕在登錄過(guò)程中展示加載態(tài)
extraStyle: {
buttonStyle: new loginComponentManager.ButtonStyle().loadingStyle({
show: true
})
},
// LoginWithHuaweiIDButton的邊框圓角半徑
borderRadius: 24,
// LoginWithHuaweiIDButton支持的登錄類(lèi)型
loginType: loginComponentManager.LoginType.QUICK_LOGIN,
// LoginWithHuaweiIDButton支持按鈕的樣式跟隨系統(tǒng)深淺色模式切換
supportDarkMode: true,
// verifyPhoneNumber:如果華為賬號(hào)用戶(hù)在過(guò)去90天內(nèi)未進(jìn)行短信驗(yàn)證,是否拉起Account Kit提供的短信驗(yàn)證碼頁(yè)面
verifyPhoneNumber: true
},
controller: this.controller
})
}
.height(40)
.margin({
top: 56
})
Column() {
Button({
type: ButtonType.Capsule,
stateEffect: true
}) {
Text('其他方式登錄')
.fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.focusable(true)
.focusOnTouch(true)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(1)
.padding({ left: 8, right: 8 })
}
.fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.backgroundColor($r('sys.color.ohos_id_color_button_normal'))
.focusable(true)
.focusOnTouch(true)
.constraintSize({ minHeight: 40 })
.width('100%')
.onClick(() => {
hilog.info(this.domainId, this.logTag, 'click optionalLoginButton.');
})
}.margin({ top: 16 })
}.width('100%')
Row() {
Row() {
Checkbox({ name: 'privacyCheckbox', group: 'privacyCheckboxGroup' })
.width(24)
.height(24)
.focusable(true)
.focusOnTouch(true)
.margin({ top: 0 })
.select(this.isSelected)
.onChange((value: boolean) => {
if (value) {
this.isSelected = true;
this.controller.setAgreementStatus(loginComponentManager.AgreementStatus.ACCEPTED);
} else {
this.isSelected = false;
this.controller.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED);
}
hilog.info(this.domainId, this.logTag, `agreementChecked: ${value}`);
})
}
Row() {
Text() {
ForEach(this.privacyText, (item: loginComponentManager.PrivacyText) => {
if (item?.type == loginComponentManager.TextType.PLAIN_TEXT && item?.text) {
Span(item?.text)
.fontColor($r('sys.color.ohos_id_color_text_secondary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_regular'))
.fontWeight(FontWeight.Regular)
.fontSize($r('sys.float.ohos_id_text_size_body3'))
} else if (item?.type == loginComponentManager.TextType.RICH_TEXT && item?.text) {
Span(item?.text)
.fontColor($r('sys.color.ohos_id_color_text_primary_activated'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.fontSize($r('sys.float.ohos_id_text_size_body3'))
.focusable(true)
.focusOnTouch(true)
.onClick(() => {
// 應(yīng)用需要根據(jù)item.tag實(shí)現(xiàn)協(xié)議頁(yè)面的跳轉(zhuǎn)邏輯
hilog.info(this.domainId, this.logTag, `click privacy text tag: ${item.tag}`);
// 華為賬號(hào)用戶(hù)認(rèn)證協(xié)議
if (item.tag === QuickLoginButtonComponent.USER_AUTHENTICATION_TAG) {
this.jumpToPrivacyWebView();
}
})
}
}, (item: string) => item)
}
.width('100%')
}
.margin({ left: 12 })
.layoutWeight(1)
.constraintSize({ minHeight: 24 })
}
.alignItems(VerticalAlign.Top)
.margin({
top:16,
bottom: 16
})
}
.justifyContent(FlexAlign.SpaceBetween)
.constraintSize({ minHeight: '100%' })
.margin({
left: 16,
right: 16
})
}
.width('100%')
.height('100%')
}
}
@CustomDialog
export struct AgreementDialog {
logTag: string = 'AgreementDialog';
domainId: number = 0x0000;
dialogController?: CustomDialogController;
cancel: () => void = () => {
};
confirm: () => void = () => {
};
clickHyperlinkText: () => void = () => {
};
privacyText: loginComponentManager.PrivacyText[] = [];
private static USER_AUTHENTICATION_TAG = '華為賬號(hào)用戶(hù)認(rèn)證協(xié)議';
build() {
Column() {
Row() {
Text('用戶(hù)協(xié)議與隱私條款')
.id('loginPanel_agreement_dialog_privacy_title')
.maxFontSize($r('sys.float.ohos_id_text_size_headline8'))
.minFontSize($r('sys.float.ohos_id_text_size_body1'))
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(2)
}
.alignItems(VerticalAlign.Center)
.constraintSize({ minHeight: 56, maxWidth: 400 })
.margin({
left: $r('sys.float.ohos_id_max_padding_start'),
right: $r('sys.float.ohos_id_max_padding_start')
})
Row() {
Text() {
ForEach(this.privacyText, (item: loginComponentManager.PrivacyText) => {
if (item?.type == loginComponentManager.TextType.PLAIN_TEXT && item?.text) {
Span(item?.text)
.fontSize($r('sys.float.ohos_id_text_size_body1'))
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.fontFamily($r('sys.string.ohos_id_text_font_family_regular'))
.fontWeight(FontWeight.Regular)
} else if (item?.type == loginComponentManager.TextType.RICH_TEXT && item?.text) {
Span(item?.text)
.fontSize($r('sys.float.ohos_id_text_size_body1'))
.fontColor('#CE0E2D')
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.focusable(true)
.focusOnTouch(true)
.onClick(() => {
// 應(yīng)用需要根據(jù)item.tag實(shí)現(xiàn)協(xié)議頁(yè)面的跳轉(zhuǎn)邏輯
hilog.info(this.domainId, this.logTag, `click privacy text tag: ${item.tag}`);
// 華為賬號(hào)用戶(hù)認(rèn)證協(xié)議
if (item.tag === AgreementDialog.USER_AUTHENTICATION_TAG) {
hilog.info(this.domainId, this.logTag, 'AgreementDialog click.');
this.clickHyperlinkText();
}
})
}
}, (item: string) => item)
}
.width('100%')
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(10)
.textAlign(TextAlign.Start)
.focusable(true)
.focusOnTouch(true)
.padding({ left: 24, right: 24 })
}.width('100%')
Flex({
direction: FlexDirection.Row
}) {
Button('取消',
{ type: ButtonType.Capsule, stateEffect: true })
.id('loginPanel_agreement_cancel_btn')
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.backgroundColor(Color.Transparent)
.fontWeight(FontWeight.Medium)
.focusable(true)
.focusOnTouch(true)
.constraintSize({ minHeight: 40, maxWidth: 400 })
.width('50%')
.onClick(() => {
hilog.info(this.domainId, this.logTag, 'AgreementDialog cancel.');
this.cancel();
})
Button('同意并登錄',
{ type: ButtonType.Capsule, stateEffect: true })
.id('loginPanel_agreement_dialog_huawei_id_login_btn')
.fontColor(Color.White)
.backgroundColor('#CE0E2D')
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
.fontWeight(FontWeight.Medium)
.focusable(true)
.focusOnTouch(true)
.constraintSize({ minHeight: 40, maxWidth: 400 })
.width('50%')
.onClick(() => {
hilog.info(this.domainId, this.logTag, 'AgreementDialog confirm.');
this.confirm();
})
}
.margin({
top: 8,
left: $r('sys.float.ohos_id_elements_margin_horizontal_l'),
right: $r('sys.float.ohos_id_elements_margin_horizontal_l'),
bottom: 16
})
}.backgroundColor($r('sys.color.ohos_id_color_dialog_default_bg'))
.padding({
left: 16,
right: 16
})
}
}
export enum ErrorCode {
// 賬號(hào)未登錄
ERROR_CODE_LOGIN_OUT = 1001502001,
// 該賬號(hào)不支持一鍵登錄,如海外賬號(hào)
ERROR_CODE_NOT_SUPPORTED = 1001500003,
// 網(wǎng)絡(luò)錯(cuò)誤
ERROR_CODE_NETWORK_ERROR = 1001502005,
// 用戶(hù)未同意用戶(hù)協(xié)議
ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED = 1005300001,
// 參數(shù)錯(cuò)誤
ERROR_CODE_PARAMETER_ERROR = 401
}
以下是華為賬號(hào)用戶(hù)認(rèn)證協(xié)議展示頁(yè)示例代碼:
import { webview } from '@kit.ArkWeb';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { router } from '@kit.ArkUI';
// 華為賬號(hào)用戶(hù)認(rèn)證協(xié)議展示頁(yè)
@Entry
@Component
struct WebPage {
@State webUrl?: string = '';
@State progress: number = 0;
logTag: string = 'WebPage';
domainId: number = 0x0000;
controller: webview.WebviewController = new webview.WebviewController();
build() {
Column() {
Column() {
Button({ type: ButtonType.Normal }) {
Image($r('sys.media.ohos_ic_compnent_titlebar_back'))
.backgroundColor(Color.Transparent)
.borderRadius(20)
.width(24)
.height(24)
.draggable(false)
.autoResize(false)
.focusable(true)
.fillColor($r('sys.color.ohos_id_color_titlebar_icon'))
.matchTextDirection(true)
}
.alignSelf(ItemAlign.Start)
.backgroundColor($r('sys.color.ohos_id_color_button_normal'))
.borderRadius(20)
.width(40)
.height(40)
.onClick(() => {
router.back();
})
}
.height(56)
.width('100%')
.justifyContent(FlexAlign.Center)
.margin({
top: 36,
left: 16
})
Progress({ value: this.progress, type: ProgressType.Linear })
.width('100%')
.visibility(this.progress <= 99 ? Visibility.Visible : Visibility.None)
Web({ src: this.webUrl ?? '', controller: this.controller })
.backgroundColor(Color.Transparent)
.margin({ bottom: 60 })
.onProgressChange((event) => {
hilog.info(this.domainId, this.logTag,
'onProgressChange: ', (event !== undefined ? event.newProgress : -1));
this.progress = event !== undefined ? event.newProgress : 0;
})
.darkMode(WebDarkMode.Auto)
.forceDarkAccess(true)
.onLoadIntercept((event) => {
hilog.info(this.domainId, this.logTag, 'onLoadIntercept');
return false;
})
.onErrorReceive((event) => {
if (event) {
hilog.error(this.domainId, this.logTag, `onErrorReceive,errorInfo: ${event?.error?.getErrorInfo()}`);
}
})
}
.alignItems(HorizontalAlign.Start)
.padding({ left: 12, right: 12, bottom: 60 })
.width('100%')
.height('100%')
}
aboutToAppear(): void {
hilog.info(0x0000, 'testTag', 'aboutToAppear');
const params = router.getParams() as Record<string, string>;
this.webUrl = params.url ?? '';
hilog.info(0x0000, 'testTag', `webUrl: ${this.webUrl}`);
}
aboutToDisappear(): void {
hilog.info(0x0000, 'testTag', 'aboutToDisappear');
if (this.webUrl) {
this.controller.stop();
}
}
}