如何使用OpenHarmony实现一个模拟应用首次启动

应用首次启动(ArkTS)

介绍

本篇Codelab基于自定义弹框、首选项和页面路由实现一个模拟应用首次启动的案例。需要完成以下功能:

  1. 实现四个页面,启动页、隐私协议页、广告页、应用首页。
  2. 页面之间的跳转。
  3. 实现自定义隐私协议弹窗,点击协议可查看隐私协议具体内容。
  4. 隐私协议状态持久化存储,再次启动时,如果没有保存状态会再次弹出,否则不弹出。

效果如图所示:

相关概念

  • 首选项 :首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。
  • 自定义弹窗 : 通过CustomDialogController类显示自定义弹窗。
  • 页面路由 :提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。

环境搭建

软件要求

  • DevEco Studio 版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板 。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本 :标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  • 完成DevEco Device Tool的安装
  • 完成RK3568开发板的烧录

3.搭建开发环境。

  • 开始前请参考工具准备 ,完成DevEco Studio的安装和开发环境配置。
  • 开发环境配置完成后,请参考使用工程向导 创建工程(模板选择“Empty Ability”)。
  • 工程创建完成后,选择使用真机进行调测 。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets               // 代码区 
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets     // 常量类
│  │  └──utils
│  │     ├──GlobalContext.ets       // 项目工具类
│  │     └──Logger.ets              // 日志打印工具类
│  ├──entryability
│  │  └──EntryAbility.ets           // 程序入口类
│  ├──pages
│  │  ├──AdvertisingPage.ets        // 广告页
│  │  ├──AppHomePage.ets            // 应用首页
│  │  ├──LauncherPage.ets           // 应用启动页
│  │  └──PrivacyPage.ets            // 隐私协议页
│  └──view
│     └──CustomDialogComponent.ets  // 自定义弹窗组件
└──entry/src/main/resources         // 资源文件目录

应用启动页实现

打开应用时进入EntryAbility页面,通过windowStage.loadContent方法加载启动页LauncherPage,然后在LauncherPage的build里面构建启动页组件,效果如图所示:

// LauncherPage.ets
// 启动页组件
build() {Stack() {// 背景图Image($r('app.media.ic_launcher_background')).width(CommonConstants.FULL_WIDTH).height(CommonConstants.FULL_HEIGHT)Column() {// 启动页logoImage($r('app.media.ic_logo')).width($r('app.float.launcher_logo_size')).height($r('app.float.launcher_logo_size')).margin({ top: CommonConstants.LAUNCHER_IMAGE_MARGIN_TOP })// 健康生活文字Text($r('app.string.healthy_life_text')).width($r('app.float.launcher_life_text_width')).height($r('app.float.launcher_life_text_height')).healthyLifeTextStyle(FontWeight.Bold,CommonConstants.LAUNCHER_LIFE_TEXT_SPACING,$r('app.float.launcher_text_title_size'),$r('app.color.launcher_text_title_color')).margin({ top: CommonConstants.LAUNCHER_TEXT_TITLE_MARGIN_TOP })// 健康生活说明Text($r('app.string.healthy_life_introduce')).height(CommonConstants.LAUNCHER_TEXT_INTRODUCE_HEIGHT).healthyLifeTextStyle(FontWeight.Normal,CommonConstants.LAUNCHER_TEXT_INTRODUCE_SPACING,$r('app.float.launcher_text_introduce_size'),$r('app.color.launcher_text_introduce_color')).opacity($r('app.float.launcher_text_opacity')).margin({ top: CommonConstants.LAUNCHER_TEXT_INTRODUCE_MARGIN_TOP })}
.height(CommonConstants.FULL_HEIGHT).width(CommonConstants.FULL_WIDTH)
}
}
// 健康生活字体公共样式
@Extend(Text) function healthyLifeTextStyle (fontWeight: number, textAttribute: number, fontSize: Resource, fontColor: Resource) {.fontWeight(fontWeight).letterSpacing(textAttribute).fontSize(fontSize).fontColor(fontColor)
}

隐私弹窗实现

启动页的隐私协议内容需要用到自定义弹窗,效果如图所示:

// CustomDialogComponent.ets
// 自定义弹窗
@CustomDialog
export default struct CustomDialogComponent {controller: CustomDialogController = new CustomDialogController({'builder': ''});// 不同意按钮回调cancel: Function = () => {}// 同意按钮回调confirm: Function = () => {}build() {Column() {// 弹窗标题Text($r('app.string.dialog_text_title')).width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT).fontColor($r('app.color.dialog_text_color')).fontSize($r('app.float.dialog_text_privacy_size')).textAlign(TextAlign.Center).margin({top: $r('app.float.dialog_text_privacy_top'),bottom: $r('app.float.dialog_text_privacy_bottom')})// 弹窗内容Text($r('app.string.dialog_text_privacy_content')).fontSize($r('app.float.dialog_common_text_size')).width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)// 协议链接Text($r('app.string.dialog_text_privacy_statement')).width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT).fontColor($r('app.color.dialog_text_statement_color')).fontSize($r('app.float.dialog_common_text_size')).onClick(() => {router.pushUrl({url: CommonConstants.PRIVACY_PAGE_URL}).catch((error: Error) => {Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error));});})// 协议声明Text($r('app.string.dialog_text_declaration_prompt')).width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT).fontColor($r('app.color.dialog_text_color')).fontSize($r('app.float.dialog_common_text_size')).opacity($r('app.float.dialog_text_opacity')).margin({ bottom: $r('app.float.dialog_text_declaration_bottom') })// 按钮组件Row() {// 取消按钮 Text($r('app.string.dialog_button_disagree')).fancy().onClick(() => {this.controller.close();this.cancel();})Blank().backgroundColor($r('app.color.dialog_blank_background_color')).width($r('app.float.dialog_blank_width')).height($r('app.float.dialog_blank_height'))// 同意按钮Text($r('app.string.dialog_button_agree')).fancy().onClick(() => {this.controller.close();this.confirm();})}.margin({ bottom: CommonConstants.DIALOG_ROW_MARGIN_BOTTOM })}.width(CommonConstants.DIALOG_WIDTH_PERCENT).borderRadius(CommonConstants.DIALOG_BORDER_RADIUS).backgroundColor(Color.White)}
}// 按钮公共样式抽取
@Extend(Text) function fancy () {.fontColor($r('app.color.dialog_fancy_text_color')).fontSize($r('app.float.dialog_fancy_text_size')).textAlign(TextAlign.Center).fontWeight(FontWeight.Medium).layoutWeight(CommonConstants.COMMON_LAYOUT_WEIGHT)
}

获取隐私协议状态

构建启动页之前,在LauncherPage的生命周期onPageShow方法处,添加一个命名为“myStore”的首选项表,并在“myStore”首选项表读取一个名为“isPrivacy”的字段,获取隐私协议状态。

// LauncherPage.ets
onPageShow() {...// 获取保存数据操作类this.getDataPreferences(this).then((preferences: preferences.Preferences) => {preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true).then((value: preferences.ValueType) => {Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'onPageShow value: ' + value);if (value) {// let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false;let isJumpPrivacy: boolean = (GlobalContext.getContext().getObject('isJumpPrivacy') as boolean) ?? false;if (!isJumpPrivacy) {// 自定义协议弹窗this.dialogController.open();          }} else {// 跳至广告页this.jumpToAdvertisingPage();}});});
}// 获取数据首选项操作
getDataPreferences(common: Object) : Promise<preferences.Preferences>{return preferences.getPreferences(getContext(common), CommonConstants.PREFERENCES_FILE_NAME);
}

保存隐私协议状态

当用户点击隐私协议弹窗同意按钮时,回调onConfirm方法,调用saveIsPrivacy保存隐私协议状态。

// LauncherPage.ets
onConfirm(): void {// 保存隐私协议状态this.saveIsPrivacy();...
}saveIsPrivacy(): void {let preferences: Promise<preferences.Preferences> = this.getDataPreferences(this);preferences.then((result: preferences.Preferences) => {let privacyPut = result.put(CommonConstants.PREFERENCES_KEY_PRIVACY, false);result.flush();...});
}

页面跳转

用户在启动页LauncherPage,点击隐私协议弹窗同意按钮onConfirm,在onConfirm方法内开启3秒倒计时,倒计时结束后跳到广告页,当启动页不可见时,清除定时器和启动页,效果如图所示:

// LauncherPage.ets
private isJumpToAdvertising: boolean = false;
onConfirm() :void{...// 跳转到广告页this.jumpToAdvertisingPage();
}jumpToAdvertisingPage() :void{ this.timerId = setTimeout(() => {// 设置跳转标识this.isJumpToAdvertising = true;router.pushUrl({url: CommonConstants.ADVERTISING_PAGE_URL}).catch((error: Error) => {Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'LauncherPage pushUrl error ' + JSON.stringify(error));});}, CommonConstants.LAUNCHER_DELAY_TIME);
}onPageHide(): void {if (this.isJumpToAdvertising) {// 清除页面router.clear();}GlobalContext.getContext().setObject('isJumpPrivacy', true);// 清除定时器clearTimeout(this.timerId);
}

打开广告页AdvertisingPage后,进行2秒倒计时(用户可手动点击跳过),倒计时结束跳转到首页AppHomePage,当广告页不可见时,清除定时器和广告页,效果如图所示:

// AdvertisingPage.ets
@State countDownSeconds: number = CommonConstants.ADVERTISING_COUNT_DOWN_SECONDS;
private timeId: number = 0;
onPageShow() {// 开启2秒倒计时this.timeId = setInterval(() => {if (this.countDownSeconds == 0) {// 跳转到首页this.jumpToAppHomePage();} else {this.countDownSeconds--;}}, CommonConstants.ADVERTISING_INTERVAL_TIME);
}onPageHide() {// 清除页面router.clear();// 清除定时器clearInterval(this.timeId);
}build() {Stack({ alignContent: Alignment.Top }) {Image($r('app.media.ic_advertising_background')).width(CommonConstants.FULL_WIDTH).height(CommonConstants.FULL_HEIGHT)Text($r('app.string.advertising_text_title', this.countDownSeconds))....onClick(() => {this.jumpToAppHomePage();})...}
.width(CommonConstants.FULL_WIDTH).height(CommonConstants.FULL_HEIGHT)
}jumpToAppHomePage(): void {router.pushUrl({url: CommonConstants.APP_HOME_PAGE_URL}).catch((error) => {Logger.error(CommonConstants.ADVERTISING_PAGE_TAG, 'AdvertisingPage pushUrl error ' + JSON.stringify(error));});
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 使用首选项功能实现数据持久化。
  2. 使用CustomDialogController操作自定义弹窗。
  3. 使用router实现通过url跳转指定页面。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频

HarmonyOS教学视频

鸿蒙语法ArkTS、TypeScript、ArkUI等.....视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取白皮书完整版方式请点击《鸿蒙生态应用开发白皮书V2.0PDF》

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ……

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/562761.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

是德科技N9020A信号分析仪

181/2461/8938产品概述&#xff1a; N9020A MXA信号分析仪通过增加针对新一代技术的信号分析和频谱分析能力&#xff0c;具备了中档分析仪的更高性能。它突破了以往分析仪的极限&#xff0c;支持业界更快的信号和频谱分析,实现了速度与性能的更佳优化。 速度 测试速度超过其它…

IAB欧洲发布首张泛欧洲数字零售媒体能力矩阵图

2024年1月18日&#xff0c;互动广告署-欧洲办事处&#xff08;IAB Europe)发布了首张泛欧洲数字零售媒体能力矩阵图。为媒体买家提供的新资源概述了在欧洲运营的零售商提供的现场、场外和数字店内零售媒体广告机会。 2024年1月18日&#xff0c;比利时布鲁塞尔&#xff0c;欧洲领…

docker 和K8S知识分享

docker知识&#xff1a; 比如写了个项目&#xff0c;并且在本地调试没有任务问题&#xff0c;这时候你想在另外一台电脑或者服务器运行&#xff0c;那么你需要在另外一台电脑或者服务器配置相同的软件&#xff0c;比如数据库&#xff0c;web服务器&#xff0c;必要的插件和库等…

【SysBench】OLTP 基准测试示例

前言 本文采用 MySQL 沙盒实例作为测试目标&#xff0c;使用 sysbench-1.20 对其做 OLTP 基准测试。 有关 MySQL 沙盒的更多信息&#xff0c;请参阅 玩转 MySQL Shell 沙盒实例&#xff0c;【MySQL Shell】6.8 AdminAPI MySQL 沙盒 。 1、部署一个 MySQL 沙盒实例 使用 mysq…

JVM本地方法

本地方法接口 NAtive Method就是一个java调用非java代码的接口 本地方法栈&#xff08;Native Method Statck&#xff09; Java虚拟机栈用于管理Java方法的调用&#xff0c;而本地方法栈用于管理本地方法的调用。 本地方法栈&#xff0c;也是线程私有的。 允许被实现成固定或…

jmeter超高并发报错解决方法

1、比如jmeter设置并发量为5000&#xff0c;运行后报错socket closed。原因是客户端与服务端做了三次握手之后&#xff0c;后面不需要握手了&#xff0c;但是jmeter没有这个功能&#xff0c;5000个并发每次发接口请求都是独立的&#xff0c;jmeter端口处理不了这么大量的请求&a…

tcp 协议详解

什么是 TCP 协议 TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制。TCP 是一个传输层的协议。 如下图&#xff1a; 我们接下来在讲解 TCP/IP 协议栈的下三层时都会先解决这两个问题&#xff1a; 报头与有效载荷如何…

【黄啊码】如何用GPT和向量数据库做问答型AI

知识库服务依赖该数据库&#xff0c;Embedding 形式个性化训练 ChatGPT&#xff0c;必不可少的就是向量数据库 因为 qdrant 向量数据库只支持 Docker 部署&#xff0c;所以需要先安装好 Docker 服务。 命令行安装 拉取镜像 docker pull qdrant/qdrant 运行服务 docker run -…

分布式组件 Nacos

1.在之前的文章写过的就不用重复写。 写一些没有写过的新东西 2.细节 2.1命名空间 &#xff1a; 配置隔离 默认&#xff1a; public &#xff08;默认命名空间&#xff09;:默认新增所有的配置都在public空间下 2.1.1 开发 、测试 、生产&#xff1a;有不同的配置文件 比如…

使用Intellij idea编写Spark应用程序(Scala+Maven)

使用Intellij idea编写Spark应用程序(ScalaMaven) 对Scala代码进行打包编译时&#xff0c;可以采用Maven&#xff0c;也可以采用sbt&#xff0c;相对而言&#xff0c;业界更多使用sbt。这里介绍IntelliJ IDEA和Maven的组合使用方法。IntelliJ IDEA和SBT的组合使用方法&#xf…

Day 14 JDBC

JDBC 1、简单入门 Statement2、preparedStatement3、主键回显4、批量操作5、事务6、Druid6.1 工具类V16.2 工具类V26.3 1、简单入门 Statement 步骤: 1、注册驱动 2、创建连接 3、创建 Statement对象 4、编写sql语句 并且发送sql语句获得结果集 5、解析结果集 6、释放资源 注意…

jmeter使用方法---自动化测试

HTTP信息头管理器 一个http请求会发送请求到服务器&#xff0c;请求里面包含&#xff1a;请求头、请求正文、请求体&#xff0c;请求头就是信息头Authorization头的主要用作http协议的认证。 Authorization的作用是当客户端访问受口令保护时&#xff0c;服务器端会发送401状态…