本案例使用ArkTS语言实现一个简单的免登录过程,展示基本的cookie管理操作。主要包含以下功能:
- 获取指定url对应的cookie的值。
- 设置cookie。
- 清除所有cookie。
- 免登录访问账户中心。
本案例使用的是在线网页,需添加网络权限:ohos.permission.INTERNET。
1. 案例效果截图
2. 原理说明
本应用旨在说明Web组件中cookie的管理操作。结合应用弹框和界面跳转两种方式进行讲解。
- 应用弹框验证cookie读写
若用户已通过“设置cookie”完成cookie写操作,点击应用首页的“获取cookie”按钮,则应用弹窗中会带有“info=测试cookie写入”的信息。若用户未进行写操作,则弹窗信中无对应信息。
- 界面跳转验证cookie存储
若用户在应用首页完成登录操作,则点击“验证cookies”按钮,界面会跳转至“关于”界面;若用户此前未完成登录操作,则会跳转至登录界面。这里借助真实的登录过程,体现了Web组件自动存储登录后的会话cookie,并在整个应用中生效的能力。
3. 代码结构
├──entry/src/main/ets // 代码区
│ ├──common
│ │ ├──constants
│ │ │ └──CommonConstant.ets // 常量类
│ │ └──utils
│ │ ├──DialogUtil.ets // 弹框工具类
│ │ └──Logger.ets // 日志工具类
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口类
│ ├──pages
│ │ ├──Verify.ets // 免登录验证界面
│ │ └──WebIndex.ets // 应用首页
│ └──view
│ └──LinkButton.ets // 链接按钮组件
└──entry/src/main/resources // 应用资源目录
4. 公共文件与资源
4.1. 本案例涉及到的常量类和工具类
- 通用常量类
// entry/src/main/ets/common/utils/CommonConstants.ets
export class CommonConstants {
static readonly USER_CENTER_URL = 'https://id1.cloud.huawei.com/AMW/portal/userCenter/index.html?' +
'service=http://developer.huawei.com/consumer/cn/#/accountCenter/userCenter'
static readonly USER_ABOUT_URL = 'https://id1.cloud.huawei.com/AMW/portal/userCenter/index.html?' +
'service=http://developer.huawei.com/consumer/cn/#/accountCenter/about'
static readonly NAVIGATOR_SIZE = '20fp'
static readonly TITLE_SIZE = '18fp'
static readonly BUTTON_SIZE = '14fp'
static readonly DIVIDER_MARGIN = 8
static readonly DIVIDER_HEIGHT = '2.2%'
static readonly PAGE_VERIFY = 'pages/Verify'
static readonly PAGE_INDEX = 'pages/WebIndex'
static readonly FULL_WIDTH = '100%'
static readonly FULL_HEIGHT = '100%'
static readonly BACK_WIDTH = '6.7%'
static readonly BACK_HEIGHT = '3.1%'
static readonly WEB_HEIGHT = '70%'
static readonly WEB_WIDTH = '90%'
static readonly PAGE_TITLE_HEIGHT = '3.1%'
static readonly PAGE_TITLE_WIDTH = '25.6%'
static readonly NAVIGATOR_MARGIN_TOP = '1.7%'
static readonly NAVIGATOR_MARGIN_LEFT = '10%'
static readonly FONT_WEIGHT_DEEPER = 500
static readonly APP_TITLE_MARGIN_TOP = '15vp'
static readonly APP_TITLE_MARGIN_LEFT = '26vp'
static readonly WEB_MARGIN_BOTTOM = '30vp'
static readonly SUB_LENGTH: number = 300
}
export enum CookieOperation {
GET_COOKIE = '读取cookie',
SET_COOKIE = '设置cookie',
DELETE_COOKIE = '删除cookie',
VERIFY_COOKIE = '验证cookie'
}
2. 日志类
// entry/src/main/ets/common/utils/Logger.ets
import { hilog } from '@kit.PerformanceAnalysisKit'
class Logger {
private domain: number
private prefix: string
private format: string = '%{public}s, %{public}s'
constructor(prefix: string = 'MyApp', domain: number = 0xFF00) {
this.prefix = prefix
this.domain = domain
}
debug(...args: string[]): void {
hilog.debug(this.domain, this.prefix, this.format, args)
}
info(...args: string[]): void {
hilog.info(this.domain, this.prefix, this.format, args)
}
warn(...args: string[]): void {
hilog.warn(this.domain, this.prefix, this.format, args)
}
error(...args: string[]): void {
hilog.error(this.domain, this.prefix, this.format, args)
}
}
export default new Logger('WebCookie', 0xFF00)
3. 弹框函数
// entry/src/main/ets/common/utils/DialogUtil.ets
import Logger from '../utils/Logger'
import { CommonConstants } from '../constants/CommonConstant'
export function showDialog(message: ResourceStr): void {
let newMessage = message.toString()
if (newMessage.length > CommonConstants.SUB_LENGTH) {
message = newMessage.substring(0, CommonConstants.SUB_LENGTH)
}
AlertDialog.show(
{
title: $r('app.string.dialog_message'),
message: message,
confirm: {
value: $r('app.string.button_confirm'),
action: () => {
Logger.info('Button-clicking callback')
}
},
cancel: () => {
Logger.info('Closed callbacks')
}
}
)
}
4.2. 本案例涉及到的资源文件
- string.json
// entry/src/main/resources/base/element/string.json
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "Web组件"
},
{
"name": "button_confirm",
"value": "确定"
},
{
"name": "dialog_message",
"value": "信息"
},
{
"name": "navigator_name",
"value": "Web组件"
},
{
"name": "title_name",
"value": "Web组件内"
},
{
"name": "write_success",
"value": "写入cookie成功"
},
{
"name": "write_fail",
"value": "写入cookie失败"
},
{
"name": "delete_success",
"value": "删除cookie成功"
},
{
"name": "test_content",
"value": "info=测试cookie写入"
},
{
"name": "load_error",
"value": "加载页面失败:请检查网络连接。"
},
{
"name": "reason",
"value": "Used to initiate network data requests."
}
]
}
2. float.json
// entry/src/main/resources/base/element/float.json
{
"float": [
{
"name": "page_title_margin_top",
"value": "48vp"
},
{
"name": "page_title_margin_bottom",
"value": "28vp"
}
]
}
3. color.json
// entry/src/main/resources/base/element/color.json
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
},
{
"name": "link_blue",
"value": "#007DFF"
},
{
"name": "navigator_black",
"value": "#000000"
},
{
"name": "title_black",
"value": "#182431"
},
{
"name": "page_background_grey",
"value": "#F1F3F5"
}
]
}
其他资源请到源码中获取。
5. Cookie读写操作
5.1. 首页
首次打开应用时,首页的Web组件内呈现的是登录界面。用户完成登录操作后,会跳转至账号中心界面。首页包含“读取cookie”、“设置cookie”和“删除cookie”等多个按钮,可对cookie进行读取、设置和删除等操作。
// entry/src/main/ets/pages/WebIndex.ets
import { webview } from '@kit.ArkWeb'
import { CommonConstants, CookieOperation } from '../common/constants/CommonConstant'
import { LinkButton } from '../view/LinkButton'
import { showDialog } from '../common/utils/DialogUtil'
@Entry
@ComponentV2
struct WebIndex {
// 创建 WebView 控制器,用于管理 Web 视图
controller: webview.WebviewController = new webview.WebviewController()
build() {
Column() {
// 应用导航标题
Text($r('app.string.navigator_name'))
.fontSize(CommonConstants.NAVIGATOR_SIZE)
.fontWeight(CommonConstants.FONT_WEIGHT_DEEPER)
.fontColor($r('app.color.navigator_black'))
.width(CommonConstants.FULL_WIDTH)
.margin({
top: CommonConstants.APP_TITLE_MARGIN_TOP,
left: CommonConstants.APP_TITLE_MARGIN_LEFT
})
// 页面主标题
Text($r('app.string.title_name'))
.fontSize(CommonConstants.TITLE_SIZE)
.fontWeight(CommonConstants.FONT_WEIGHT_DEEPER)
.fontColor($r('app.color.title_black'))
.textAlign(TextAlign.Center)
.width(CommonConstants.WEB_WIDTH)
.height(CommonConstants.PAGE_TITLE_HEIGHT)
.margin({
top: $r('app.float.page_title_margin_top'),
bottom: $r('app.float.page_title_margin_bottom')
})
// 加载 WebView,嵌入用户中心页面
Web({
src: CommonConstants.USER_CENTER_URL, // WebView 加载的 URL
controller: this.controller // 绑定 WebView 控制器
})
.domStorageAccess(true) // 允许访问 DOM 存储
.javaScriptAccess(true) // 允许执行 JavaScript
.height(CommonConstants.WEB_HEIGHT)
.width(CommonConstants.WEB_WIDTH)
.margin({ bottom: CommonConstants.WEB_MARGIN_BOTTOM })
.onErrorReceive((event) => { // 监听 WebView 加载错误事件
if (event?.request.isMainFrame()) { // 检查是否为主框架加载失败
let message = $r('app.string.load_error') // 加载失败提示信息
showDialog(message) // 显示错误对话框
}
})
// 操作按钮区域(获取、设置、删除和验证 Cookie)
Row() {
LinkButton({ buttonType: CookieOperation.GET_COOKIE, isNeedDivider: true }) // 获取 Cookie 按钮
LinkButton({ buttonType: CookieOperation.SET_COOKIE, isNeedDivider: true }) // 设置 Cookie 按钮
LinkButton({ buttonType: CookieOperation.DELETE_COOKIE, isNeedDivider: true }) // 删除 Cookie 按钮
}
.justifyContent(FlexAlign.SpaceBetween)
.width(CommonConstants.WEB_WIDTH)
}
.backgroundColor($r('app.color.page_background_grey'))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
}
}
关键代码说明:
- LinkButton({...})自定义组件,用于实现获取、设置、删除和验证 Cookie。
5.2. LinkButton组件
// entry/src/main/ets/view/LinkButton.ets
import { webview } from '@kit.ArkWeb'
import { router } from '@kit.ArkUI'
import { showDialog } from '../common/utils/DialogUtil'
import { CommonConstants, CookieOperation } from '../common/constants/CommonConstant'
/**
* LinkButton 组件
* 用于执行 Cookie 操作(获取、设置、删除)或导航到验证页面
*/
@ComponentV2
export struct LinkButton {
@Param buttonType?: string = '' // 按钮类型(表示不同的 Cookie 操作)
@Param isNeedDivider?: boolean = true // 是否需要分隔线(用于 UI 视觉分割)
/**
* 组件构建方法
*/
build() {
Row() { // 水平排列按钮和分隔线
// 按钮文本
Text(this.buttonType)
.fontColor($r('app.color.link_blue')) // 设置字体颜色
.fontSize(CommonConstants.BUTTON_SIZE) // 设置字体大小
.textAlign(TextAlign.Center) // 文本居中
.fontWeight(FontWeight.Normal) // 设置字体粗细
.onClick(() => {
this.operationMethod() // 绑定点击事件,执行相应操作
})
// 是否需要分隔线
if (this.isNeedDivider) {
Divider()
.vertical(true) // 竖直分隔线
.margin(CommonConstants.DIVIDER_MARGIN) // 设置分隔线边距
.height(CommonConstants.DIVIDER_HEIGHT) // 设置分隔线高度
}
}
}
/**
* 执行不同类型的 Cookie 操作或页面跳转
*/
operationMethod(): void {
try {
if (this.buttonType === CookieOperation.GET_COOKIE) {
// 获取指定 URL 的 Cookie
let originCookie = webview.WebCookieManager.fetchCookieSync(CommonConstants.USER_CENTER_URL)
showDialog(originCookie) // 显示获取到的 Cookie
} else if (this.buttonType === CookieOperation.SET_COOKIE) {
// 设置 Cookie
webview.WebCookieManager.configCookieSync(CommonConstants.USER_ABOUT_URL, 'info=测试cookie写入')
showDialog($r('app.string.write_success')) // 显示成功写入提示
} else if (this.buttonType === CookieOperation.DELETE_COOKIE) {
// 清除所有 Cookie
webview.WebCookieManager.clearAllCookiesSync()
let deleteMessage = $r('app.string.delete_success')
showDialog(deleteMessage) // 显示删除成功提示
} else {
// 其他情况,执行页面跳转到 Cookie 验证页面
// TODO
}
} catch (error) {
// 捕获异常并显示错误信息
showDialog('Operation failed: ' + JSON.stringify(error))
}
}
}
关键代码说明:
- WebCookieManager.fetchCookieSync:获取指定 URL 的 Cookie。
- WebCookieManager.configCookieSync:设置 Cookie
- WebCookieManager.clearAllCookiesSync:清除所有 Cookie
6. Cookie存储验证
一个应用中的所有Web组件共享一个WebCookie,因此一个应用中Web组件存储的cookie信息,也是可以共享的。当用户在应用内完成登录操作时,Web组件会自动存储登录的会话cookie。应用内其他页面可共享当前会话cookie信息,免去多余的登录操作。
6.1. 首页入口
// entry/src/main/ets/pages/WebIndex.ets
// ...
@Entry
@ComponentV2
struct WebIndex {
// ...
build() {
Column() {
// ...
// 操作按钮区域
Row() {
// ...
// 验证 Cookie 按钮
LinkButton({ buttonType: CookieOperation.VERIFY_COOKIE, isNeedDivider: false })
}
// ...
}
// ...
}
}
6.2. LinkButton组件路由跳转
// entry/src/main/ets/view/LinkButton.ets
// ...
@ComponentV2
export struct LinkButton {
// ...
/**
* 执行不同类型的 Cookie 操作或页面跳转
*/
operationMethod(): void {
try {
if (this.buttonType === CookieOperation.GET_COOKIE) {
// ...
} else {
// 其他情况,执行页面跳转到 Cookie 验证页面
router.pushUrl({
url: CommonConstants.PAGE_VERIFY
})
}
}
// ...
}
}
6.3. cookie验证
// entry/src/main/ets/pages/Verify.ets
import { webview } from '@kit.ArkWeb'
import { showDialog } from '../common/utils/DialogUtil'
import { CommonConstants } from '../common/constants/CommonConstant'
/**
* Verify 组件
* 用于加载 `USER_ABOUT_URL` 页面,并在页面加载完成时尝试获取 Cookie。
*/
@Entry
@ComponentV2
struct Verify {
@Local navPathStack: NavPathStack = new NavPathStack() // 导航路径管理
fileAccess: boolean = true // 是否允许文件访问
controller: webview.WebviewController = new webview.WebviewController() // WebView 控制器
isRedirect: boolean = false // 标记是否已经进行跳转,防止重复操作
/**
* 页面显示时触发
* 重新设置 `isRedirect` 为 false,确保每次进入页面时可以正确获取 Cookie
*/
onPageShow(): void {
this.isRedirect = false
}
/**
* 组件构建方法
*/
build() {
Navigation(this.navPathStack) {
Column() {
Text($r('app.string.title_name'))
.fontSize(CommonConstants.TITLE_SIZE)
.fontWeight(CommonConstants.FONT_WEIGHT_DEEPER)
.fontColor($r('app.color.title_black'))
.width(CommonConstants.PAGE_TITLE_WIDTH)
.height(CommonConstants.PAGE_TITLE_HEIGHT)
.margin({
top: $r('app.float.page_title_margin_top'),
bottom: $r('app.float.page_title_margin_bottom')
})
// WebView 组件
Web({
src: CommonConstants.USER_ABOUT_URL, // 目标网页 URL
controller: this.controller // 绑定 WebView 控制器
})
.height(CommonConstants.WEB_HEIGHT)
.width(CommonConstants.WEB_WIDTH)
.fileAccess(this.fileAccess) // 允许文件访问
.javaScriptAccess(true) // 允许 JavaScript 交互
.onPageEnd(() => {
try {
// 在页面加载完成后尝试获取 Cookie
let originCookie = webview.WebCookieManager.fetchCookieSync(CommonConstants.USER_ABOUT_URL)
if (originCookie === '' || this.isRedirect) {
return // 如果 Cookie 为空或者已经重定向过,则不执行操作
}
this.isRedirect = true // 设置跳转标志,避免重复执行
showDialog(originCookie) // 显示 Cookie 信息
} catch (error) {
// 捕获错误并显示弹窗提示
showDialog('Failed to load the web page. ' + JSON.stringify(error))
}
})
}
.backgroundColor($r('app.color.page_background_grey'))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
}
.titleMode(NavigationTitleMode.Mini)
.title($r('app.string.navigator_name'))
}
}
关键代码解读:
- 在WebView页面加载完成后,同步获取指定URL(USER_ABOUT_URL) 的 Cookie。
- 如果Cookie为空或已经执行过跳转 (isRedirect为true),则不进行任何操作,防止重复执行。否则,将isRedirect置为true。
- 通过showDialog显示获取到的Cookie信息。
7. 结语
专栏持续更新,感谢关注、点赞与收藏。
✋ 需要参加鸿蒙认证的请点击 鸿蒙认证链接