上一篇面试题链接:https://mp.csdn.net/mp_blog/creation/editor/144685078
1. 鸿蒙简单介绍和发展历程
HarmonyOS 是新一代的智能终端操作系统,为不同设备的智能化、互联与协同提供了统一的语言。带来简洁,流畅,连续,安全可靠的全场景交互体验。
鸿蒙操作系统发展历程
- 2019年8月9日 :鸿蒙1.0发布,首次应用于华为荣耀智慧屏产品中,标志着华为正式进军操作系统领域
- 2020年9月10日 :鸿蒙2.0在华为开发者大会上发布,适用于部分手机、车机、智能电视等设备
- 2022年7月27日 :鸿蒙3.0在HarmonyOS3及华为全场景新品发布会上正式发布,支持更多设备加入超级终端,并提升了鸿蒙智联、万能卡片、流畅性能、隐私安全、信息无障碍等方面
- 2023年8月4日: 鸿蒙4.0在华为开发者大会上正式发布,提供了强大的智能互联能力,并在多屏跨设备投屏等方面实现突破
- 2024年1月18日: 鸿蒙Next开发者预览版本发布,将不在兼容安卓应用
2. 鸿蒙使用网络资源的时候,需要申请什么权限
使用网络资源时,需要申请权限ohos.permission.INTERNET
在module.json5文件中加上(也就是在module下面加上requestPermissions)
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"requestPermissions":[
{
"name" : "ohos.permission.INTERNET",
"reason": "$string:reason",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"inuse"
}
}
],
3. 自定义组件的创建和渲染流程
- 自定义组件的创建:自定义组件的实例由ArkUI框架创建。
- 初始化自定义组件的成员变量:通过本地默认值或者构造方法传递参数来初始化自定义组件的成员变量,初始化顺序为成员变量的定义顺序。
- 如果开发者定义了aboutToAppear,则执行aboutToAppear方法。
- 在首次渲染的时候,执行build方法渲染系统组件,如果子组件为自定义组件,则创建自定义组件的实例。在首次渲染的过程中,框架会记录状态变量和组件的映射关系,当状态变量改变时,驱动其相关的组件刷新。
当应用在后台启动时,此时应用进程并没有销毁,所以仅需要执行onPageShow。
4. UiAbility页面启动的方式有哪些?
- singleton (单实例模式)
- multiton(多实例模式)
- specified(指定实例模式)
4.1 singleton启动模式
singleton启动模式为单实例模式,也是默认情况下的启动模式。
每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例。
说明:应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用startAbility()方法启动该UIAbility实例。由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。
使用方法:如果需要使用singleton启动模式,在module.json5配置文件中的launchType字段配置为singleton即可。
4.2multiton启动模式
multiton启动模式为多实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。这种情况下可以将UIAbility配置为multiton(多实例模式)。
使用方法:multiton启动模式的开发使用,在module.json5配置文件中的launchType字段配置为multiton即可。
4.3specified启动模式
specified启动模式为指定实例模式,针对一些特殊场景使用(例如文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例)。
工作原理:
假设应用有两个UIAbility实例,即EntryAbility和SpecifiedAbility。EntryAbility以specified模式启动SpecifiedAbility。基本原理如下:
- EntryAbility调用startAbility()方法,并在Want的parameters字段中设置唯一的Key值,用于标识SpecifiedAbility。
- 系统在拉起SpecifiedAbility之前,会先进入对应的AbilityStage的onAcceptWant()生命周期回调,获取用于标识目标UIAbility的Key值。
- 系统会根据获取的Key值来匹配UIAbility。
- 如果匹配到对应的UIAbility,则会启动该UIAbility实例,并进入onNewWant()生命周期回调。
- 如果无法匹配对应的UIAbility,则会创建一个新的UIAbility实例,并进入该UIAbility实例的onCreate()生命周期回调和onWindowStageCreate()生命周期回调。
使用方法:在SpecifiedAbility中,需要将module.json5配置文件的launchType字段配置为specified。
5. 常用的修饰符有哪些介绍一下
- Entry- 修饰成为页面
- Component -修饰成为组件
- Preview - 让组件可预览
- State - 在组件内部定义响应式数据- 必须给初始值
- Prop- 接收父组件的响应式数据- 可以给初始值 也可以不给
- Builder- 声明轻量复用UI
- BuilderParam - 接收传入的轻量复用UI- 可以给初始值 也可以不给(如果不给的话,调用时需要判断)
- CustomDialog- 修饰自定义弹层
- Styles- 修饰样式复用集合-不允许传参数
- Extend- 修饰某个特定组件的样式复用集合- 允许传参数
- Link- 可以实现父-子的双向绑定- 注意:值得是组件内的双向绑定,同样可以实现和Link绑定(必须不能给初始值)
- LocalStorageProp-单向读取LocalStorage共享的属性(必须给初始值)
- LocalStorageLink -双向读取LocalStorage共享的属性 必须给初始值)
6. 页面栈最大容量是多少
页面栈的最大容量是32个页面
7. 路由模式有几种
路由提供了两种不同的跳转模式
- Standard:无论之前是否添加过,一直添加到页面栈(默认)
- Single:如果目标页面已存在,会将已有的最近同url页面移到栈顶(看情况使用)
8. 模块如何导出导入的
程序可划分为多组编译单元或模块。
每个模块都有其自己的作用域,即,在模块中创建的任何声明(变量、函数、类等)在该模块之外都不可见,除非它们被显式导出。
与此相对,从另一个模块导出的变量、函数、类、接口等必须首先导入到模块中。
- 导出:可以使用关键字export导出顶层的声明。
- 导入:可以使用关键字import导入
9. 说一下你做的这个项目,开发鸿蒙项目的流程是什么
- 创建项目
- 导入一些资源/色值
- 创建一些公共目录-组件库-数据模型-工具类-请求-常量
- 读写首选项工具类
- 封装请求工具类
- 使用泛行工具统一处理响应数据
- 封装组件库-列表-加载-上传-日历-弹出时间-卡片。。。
- 分包
- 发布上线
10.鸿蒙的系统能力你用过哪些,简单讲一下
- 弹窗
- 路由跳转
- 声音播放-av-player(Video)
- 震动
- 打电话
- 定位(需要用户授权)
- 发布通知
- ability通信-传参
- 网络权限
- 首选项
- 文件选择
- 后台订阅闹铃
11.你项目中的权限是如何管理的
- 进入应用-判断token(坑点-只能用首选项获取token)- 跳转到主页/登录页
- 销毁应用
- 进入登录页- 获取token(存储到持久化/首选项)-跳到主页
- token超时- 销毁token(销毁持久化/首选项)-跳回登录页
12. H5和原生是怎么通信的
鸿蒙原生和h5通信有大概两种方式
1.通过消息机制推送**,** 类似于前端的postMessage的跨域通信
- 首先通过原生端的webviewController进行创建通信端口, createMessagePorts, 该方法会创建两个端口,一个用作原生端,一个用作h5端,
- 然后通过webviewController将其中一个端口通过postMessage发送到h5端,h5端用onmessage来接收该端口,并全局缓存,
- 此时,h5端用接收的端口发送消息给原生端,原生端用自己剩余的端口进行onMessage接听消息,此时就可以实现双向通信
2.api调用的形式
- 原生端可以通过javascriptProxy给h5页面注入可用的sdk应用方法集合,在h5完成初始化后,可以直接调用原生的方法,这是h5调用原生
- 原生端也可以直接调用h5端的方法 runJavascript,在这个方法里面传入方法调用传参数就可以
需要注意的点: 如果原生端的sdk方法是个异步方法,在h5端无法及时得到结果,此时需要再用原生反调h5进行传递结果
13. 鸿蒙云服务和微信小程序的区别是什么
本质上很像,因为他们都遵循即用即走的模式,都可以免安装,轻量级的使用。
但是微信小程序本质上是在微信的安卓架构/ios架构上做了一层代码框架的机制,也就是说本质上- 微信使用安卓/ios的开发语言完成,小程序是微信自创的一套小程序的开发语言-类似于Vue的MVVM的框架,然后微信进行了统一的代码编译和代码解释,最终实现如今的小程序的效果
鸿蒙的元服务实现了代码大一统的效果,也就是开发一个鸿蒙应用和鸿蒙元服务本质上都直接使用鸿蒙的arkTS和arkUI来进行,调用通用能力和api方式一致,并且把应用变成元服务变得非常简单,只需要加个参数即可
14. 鸿蒙的刷新机制是怎么样的,多层嵌套时,是从build开始刷新吗
一个组件的渲染: aboutToAppear - build函数(构建UI视图)
当响应式数据发生变化:builde的重新执行
所有的鸿蒙的响应式监测都只能监测到一层
多层嵌套时-执行的顺序 。洋葱圈模式- 一定是先最里面的组件渲染完毕,然后最外层的组件最后渲染。
15.关于列表更新机制的问题
比较机制
列表比较-ForEach-有三个参数, 第三个参数需要返回一个唯一的key, 如果不写,系统会自动帮我们生成一个函数 规则 index_JSON.stringfy(item) { a: 1, b: 2 } => { a: 2: b: 2 }
如果列表中key发生变化,更新机制直接销毁该组件,然后重新创建, 但是反之,你给的key如果没有发生变化,但是数据变化了,就会出现页面不更新现象。
16. 说一下全局存储状态用哪些方式
- LocalStorage- 内存化存储- 局部可用
- AppStorage- 内存化存储- 全局可用
- PersitentStoreage- 写入磁盘(沙箱) 全局可用
- 首选项- 写入磁盘- 全局可用
- 关系型数据库- 写入磁盘
17.你在项目中用过线程通信吗,线程是怎么进行通信的?
emitter和eventHub
都是基于事件总线的
区别是:
- eventHub:当前线程内通信,EventHub不是全局的事件中心,不同的context对象拥有不同的EventHub对象,事件的订阅、取消订阅、触发都作用在某一个具体的EventHub对象上,因此不能用于虚拟机间或者进程间的事件传递
- emitter:同一进程不同线程间,或同一进程同一线程内,发送和处理事件的能力,包括持续订阅事件、单次订阅事件、取消订阅事件,以及发送事件到事件队列的能力
18.你在项目中使用首选项主要用来做什么
存任何持久化的东西都可以,比如token,用户信息等。
首选项有长度限制 每一项的长度8192个字节
19.组件通信的方式有哪些
- 父传子
- 子传父
- 跨层
- 跨ability
- 跨页面
20.弹窗UI是怎么在页面UI中使用的
- CustomtDialogController
- 创建子窗口的形式创建弹层
- 弹层
- bindSheet 半层
- bindContentCover 全层
21.Builder和BuilderParams的区别
- Builder是当前组件的UI复用结构
- BuilderParams是接收父组件传入的UI复用结构, 传过来的类型是UI复用结构类型
- Builder传值 想要响应式必须是对象,如果基础数据类型,不具备响应式
22. 对于一些公共的样式你是怎么做的?有没有什么优化的方式
- 封装组件
- 抽提Builder
- 抽提Styles和Extends
23.共享库之间怎么进行页面跳转
- import动态引入共享库的页面
- 给共享库一个entry的name属性
- 使用pushRouteName
- 不要忘记导入依赖
24.websocker用过吗?说说你在项目中怎么用的
主要用在发消息和接消息,用于客服模块的消息
用过,和前端用法是一样的
const socket = new WebSocket(url)
socket.on("connect", () => {
})
socket.on("message", () => {
})
socket.on("disconnect", () => {
})
socket.send()
25. 项目中有用到多线程嘛,具体说一下多线程的作用,如何使用的
用了,因为我们要提高性能。
自定义组件创建完成之后,在build函数执行之前,将先执行aboutToAppear()生命周期回调函数。此时若在该函数中执行耗时操作,将阻塞UI渲染,增加UI主线程负担。因此,应尽量避免在自定义组件的生命周期内执行高耗时操作。在aboutToAppear()生命周期函数内建议只做当前组件的初始化逻辑,对于不需要等待结果的高耗时任务,可以使用多线程处理该任务,通过并发的方式避免主线程阻塞;也可以把耗时操作改为异步并发或延后处理,保证主线程优先处理组件绘制逻辑。
worker帮我们处理图片压缩处理完成之后再去执行其它任务
26.什么是鸿蒙应用签名
指纹-就是一堆证明当然项目可被agc识别并允许调试到设备的说明文件
- p12
- csr
- cer
- p7b
27.如何引入本地的web页面?
web({ src: $rawfile("index.html"),controller: new weview.WebviewController() })
28.@Provide和@Consume的使用中,消费者修改了值,提供者那边会变化吗?
当然会,因为都是双向的
29.鸿蒙客户端怎么实现长登陆的;再说说token的失效后是如何处理的?
- token是登录之后得到的,如果失效应该去换取token,还应有一个refreshToken,
- refreshToken换取一个新的token
- 如果换取成功-替换原有token-重启发请求
- 如果换取失败-删除token-删除refreshToken-跳转到登页