OpenHarmony开源鸿蒙学习入门–系统相机应用源码解析(一)

一、源码解析的目的:

为什么要去做源码解析这件事?我个人认为,首先可以提高我们对代码书写的能力,毕竟官方系统级的应用,会比demo的写法更专业,让我们更能学到些写法技巧。其次,分析源码是对我们学习开发技术,提升最快的方法之一。

确立认知后,我们做一件事才能更有能力的驱动。

二、准备环境:

开源鸿蒙系统相机应用源码 Gitee地址

用git拉代码到本地即可,不过不能直接运行,因为是系统级应用,不能自动签名。应用里有个文件夹是signature,目测应该是签名文件,后面系统梳理一下,把运行系统应用打包签名写下博客。今天先略过。

系统应用是ets 和 js代码都有的版本,不过我们只需要关注eTS部分就行。

三、熟悉项目结构:

整个相机应用的应用架构分为四层,分别是Product产品层,Feaure业务层,Common通用共享层,和OpenHarmony底层系统接口支持能力。

Product产品层对四种类型的设备UI和逻辑进行了拆分,分为手机,手表,电脑Tablet。

四、解析相机源码:

首先需要明确的是,系统相机应用是API9的工程创建。如果不太了解API8和API9有什么不同,请先看这篇博客 ==》OpenHarmony开源鸿蒙学习入门–API8升级到API9

接下来我们先关注Phone里的代码思路进行拆分学习。

Phone文件夹的结构:

从文件夹命名就发现不同了,有的大驼峰命名,有的全部字母小写。
个人猜测是为了突出重点吧,有明白原因的同学可以留言分享下。

文件夹的分类很清晰明了,比较复杂的部分就是pages UI了。
其他几个文件夹的代码都很简单,有的甚至只是初始化而已。

Application-AbilityStage。

AbilityStage是API9是HAP包的运行时类,类似于Android中的Applicaiton。提供在HAP加载的时候,回调通知状态,可以在此进行该HAP的初始化(如资源预加载,线程创建等)能力。

【不过基本都不会在初始化里做太多耗时操作,因为会非常影响体验,相机应用也没有在onCreate中去初始化worker线程,而是使用单例去做即插即用】

可以看到源码中相机的AbillityStage,啥都没干。

AbilityStage中有特定的AbilityStageContext对象,包含了获取AbilityStage对应的ModuleInfo对象、环境变化对象。

Application-AbilityStage.tsimport AbilityStage from '@ohos.application.AbilityStage'export default class MyAbilityStage extends AbilityStage {onCreate() {// 当应用创建时调用。console.info('MyAbilityStage onCreate.')}
}

common-ModeConfig.ts

开发内容很简单的根据Video 或者 Photo两种模式传参不同,会返回不同数值的top,bottom内边距。

common-ModeConfig.tsexport class ModeConfig {private photoPadding: PaddingData = { top: 48, bottom: 154 }private videoPadding: PaddingData = { top: 48, bottom: 0 }public getPaddingConfig(mode: string): PaddingData {switch (mode) {case 'PHOTO':return this.photoPaddingcase 'VIDEO':return this.videoPadding}}
}export class PaddingData {top = 48bottom = 154
}

FormAbility-FormAbility.ts

之前介绍过,API9的Stage模型。将Ability分为Ability和ExtensionAbility两大类。
其中ExtensionAbility又被扩展为ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility等等一系列ExtensionAbility,以便满足更多的使用场景。

而FormExtensionAbility 提供了卡片扩展相关接口。可以看到相机源码里,没有创建卡片相关的能力。

FormAbility-FormAbility.tsimport FormExtension from '@ohos.application.FormExtension';import { Log } from '../../../../../../common/src/main/ets/default/Utils/Log'export default class FormAbility extends FormExtension {private TAG: string = '[FormAbility]'onCreate(want) {Log.info(`${this.TAG} form onCreate. want ${JSON.stringify(want)}`);return null;}onCastToNormal(formId) {Log.info(`${this.TAG} onCastToNormal, formId: ${formId}`);}onUpdate(formId) {Log.info(`${this.TAG} onUpdate, formId: ${formId}`);}onVisibilityChange(newStatus) {Log.info(`${this.TAG} onVisibilityChange, newStatus: ${JSON.stringify(newStatus)}`);}onEvent(formId, message) {Log.info(`${this.TAG} onEventA, formId: ${formId}, msg: ${message}`);}onDestroy() {Log.info(`${this.TAG} onDestroy`);}
};

MainAbility-MainAbility.ts

这个类似于Android中Activity,我们会在继承Activity后创建MainActivity一个原理。

相机在初始化时,对context,lunchWant这些对象和配置信息,进行犬奴缓存。globalThis这个东西,你可以理解为一个全局单例对象,你可以把变量,函数都放在这里。用法很简单,globalThis.XX = ‘’ 就是赋值。globalThis.XX 就是取值。

在onCreate中接着创建了一个permissionFlag全局变量,用于记录相机相关的权限 是否授权的状态。

然后在onWindowStageCreate函数中,对窗户属性进行了操作。设置应用全屏,然后对顶部的状态栏,底部的导航栏进行了设置。具体说明可以看下面代码注释。

Want,这个东西很有意思,官方的说法是封装了基本通信组件的能力。目测是分布式相关的东西,可以通过它去启动,互信设备的ability。

MainAbility-MainAbility.tsimport Ability from '@ohos.application.Ability'
import window from '@ohos.window'export default class MainAbility extends Ability {onCreate(want, launchParam) {// want,当前Ability的Want类型信息,包括ability名称、bundle名称等。// launchParam,创建 ability、上次异常退出的原因信息。// Ability创建时回调,执行初始化业务逻辑操作。console.info('Camera MainAbility onCreate.')// 全局上下文对象,类似于Android中Activity中的contextglobalThis.cameraAbilityContext = this.context// Ability启动时的参数。globalThis.cameraAbilityWant = this.launchWant// 相机需要的权限是否已经授权,默认falseglobalThis.permissionFlag = false}onDestroy() {// Ability生命周期回调,在销毁时回调,执行资源清理等操作。console.info('Camera MainAbility onDestroy.')}async onWindowStageCreate(windowStage) {// 当WindowStage创建后调用。console.info('Camera MainAbility onWindowStageCreate.')// 开启WindowStage生命周期变化的监听。此接口仅可在Stage模型下使用。windowStage.on('windowStageEvent', (event) => {console.info('Camera MainAbility onWindowStageEvent: ' + JSON.stringify(event))// 如果窗口是失焦状态。if (event === window.WindowStageEventType.INACTIVE) {//  globalThis?,这里的问号作用是防止空异常,因为globalThis可能在此时还没有创建成功。// 如果globalThis是空,后面的代码都不会继续执行。这种写法在swift,Dart,TypeScript中都很普及了。globalThis?.stopCameraRecording && globalThis.stopCameraRecording()// 这里的写法很有意思, && 表示两者都要满足条件为true。// 全局搜索了stopCameraRecording函数的实现,发现是对视频录制停止的一系列处理。// 而stopCameraRecording并不是变量,而是个方法体。前面也说过了globalThis既可以存变量也可以存方法体。// 所以这句话的意思是说,当 globalThis不为空,并且stopCameraRecording已赋值,调用stopCameraRecording函数的实现。Get.}globalThis.cameraWindowStageEvent = event})//  getMainWindow()是系统接口,提供获取当前窗口对象。// 一般开源鸿蒙提供的异步接口都有两种形态,一种是无返回值,设置callback参数。一种是有返回值,Promise<XXX>。// 而.then的写法,就是对Promise<Window>进行级联处理。拿到返回值后直接走后面函数逻辑。Get.windowStage.getMainWindow().then(// 为了让大家看着方便,我调整了格式(win) => {try {// 设置应用窗口全屏,窗口的布局是否为全屏显示状态,需要注意到的是全屏状态下状态栏、导航栏仍然显示。win.setLayoutFullScreen(true).then(() => {console.info('Camera setFullScreen finished.')// 这里就针对导航栏、状态栏的可见模式进行设置。相机应用设置导航栏显示,状态栏不显示。// setSystemBarEnable 设置状态栏和导航栏是否显示。// 例如,需全部显示,该参数设置为["status", "navigation"];// 不设置,则默认不显示。win.setSystemBarEnable(['navigation']).then(() => {console.info('Camera setSystemBarEnable finished.')})})// 设置窗口内导航栏、状态栏的属性win.setSystemBarProperties({// 设置导航栏颜色为黑色有透明度,导航栏操作按钮颜色为#B3B3B3navigationBarColor: '#00000000', navigationBarContentColor: '#B3B3B3'}).then(() => {console.info('Camera setSystemBarProperties.')})
// 这里应该改写成下面这样
//.then((data)=> {//    console.info('Succeeded in setting the system bar properties. Data: ' + //JSON.stringify(data));
//}).catch((err)=>{//    console.error('Failed to set the system bar properties. Cause: ' + //JSON.stringify(err));
//});globalThis.cameraWinClass = win} catch (err) {console.error('Camera setFullScreen err: ' + err)}})// 当前模式是拍照还是录像,去启动分布式相机的相同模式。if (this.launchWant.parameters.uri === 'capture') {globalThis.cameraFormParam = {action: 'capture',cameraPosition: 'PHOTO',mode: 'PHOTO'}} else if (this.launchWant.parameters.uri === 'video') {globalThis.cameraFormParam = {action: 'video',cameraPosition: 'VIDEO',mode: 'VIDEO'}}// 设置当前stage要展示的UI内容。windowStage.setUIContent(this.context, 'pages/index', null)}onWindowStageDestroy() {// 当WindowStage销毁后调用。console.info('Camera MainAbility onWindowStageDestroy.')}onForeground() {// Ability生命周期回调,当应用从后台转到前台时触发。console.info('Camera MainAbility onForeground.')globalThis?.onForegroundInit && globalThis.onForegroundInit()}onBackground() {// Ability生命周期回调,当应用从前台转到后台时触发。console.info('Camera MainAbility onBackground.')globalThis?.releaseCamera && globalThis.releaseCamera()}onNewWant(want) {// 当ability的启动模式设置为单例时回调会被调用。console.info('Camera MainAbility onNewWant.')globalThis.cameraNewWant = want}

《OpenHarmony开源鸿蒙学习入门》-- 系统相机应用源码解析(一)相关推荐

  1. Flink 全网最全资源(视频、博客、PPT、入门、实战、源码解析、问答等持续更新)...

    Flink 学习 github.com/zhisheng17/- 麻烦路过的各位亲给这个项目点个 star,太不易了,写了这么多,算是对我坚持下来的一种鼓励吧! 本项目结构 博客 1.Flink 从0 ...

  2. Springboot学习交流系统 毕业设计-附源码62600

    摘  要 随着科学技术的飞速发展,社会的方方面面.各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,学习交流系统当然也不能排除在外.学习交流系统是以实际运用为开发背景,运用软件工程原 ...

  3. Laravel 学习笔记之 Query Builder 源码解析(下)

    说明:本文主要学习下Query Builder编译Fluent Api为SQL的细节和执行SQL的过程.实际上,上一篇聊到了\Illuminate\Database\Query\Builder这个非常 ...

  4. Kubernetes学习笔记之Calico Startup源码解析

    女主宣言 我们目前生产k8s和calico使用ansible二进制部署在私有机房,没有使用官方的calico/node容器部署,并且因为没有使用network policy只部署了confd/bird ...

  5. Shiro学习笔记(三)源码解析

    Shiro作为轻量级的权限框架,Shiro的认证流程是怎样的一个过程. 如果没有对Shiro进行了解的话,建议先对Shiro学习笔记(一)学习一下Shiro基本的组 成. 1,几大重要组件解析 1.1 ...

  6. opencv+pythons相机标定源码解析

    相机标定原理,这里不再赘述,一般使用张友正相机标定法.这里只介绍了标定相机内参的方法,即3x3的matrix. import cv2 import numpy as np import glob# 设 ...

  7. Flink从入门到放弃之源码解析系列-第1章 Flink组件和逻辑计划

    >请戳GitHub原文: github.com/wangzhiwubi- 本文参考了网上很多博客,大多数博客都是基于1.1.0版本的,已经严重滞后,本系列文章做了很多订正,欢迎大家指正. 概要和 ...

  8. Ceph学习——Librados与Osdc实现源码解析

    Librados RadosClient类 IoctxImpl AioCompletionImpl OSDC ObjectOperation 封装操作 op_target 封装PG信息 Op 封装操作 ...

  9. 前端学习(2537):vue源码解析2伪数组转换为真数组

    /*1[].slice.call(lis)*//*伪数组 */const lis=document.getElementsByTagName('li')/*判断数组 false*/console.lo ...

最新文章

  1. DedeCMS实现自定义表单提交后发送指定QQ邮箱法
  2. uva 10152 ShellSort
  3. Dos中@符号的使用演示(屏蔽echo off的回显)
  4. 【WebRTC---入门篇】(八)WebRTC核心之RTP Medio 媒体控制与数据统计
  5. numpy zeros矩阵_零矩阵使用numpy.zeros()| 使用Python的线性代数
  6. OSPF高级特性——LSA-3(Network Summary LSA)的过滤、路由协议——管理距离的修改、外部路由的metric值的修改
  7. js插值法的使用_js 实现排序算法 -- 插入排序(Insertion Sort)
  8. c语言输入一串数字存入数组_在Excel中快速输入,竟是输入一串数字?
  9. formvalidation表单验证
  10. android 被自动安装cibn合一,Android v4.2.2 ROOT方法,可能也适用于很多同版系统的安卓电视!...
  11. 具体数学第一章习题题解(8,9,10,11)
  12. Python函数学习心得
  13. 笔记本电脑亮度无法调节问题
  14. Cadence中的电路设计
  15. stm32 步进电机控制,S曲线加减速,匀加速运动
  16. 高性能无线综合测试仪 无线电综合测试仪 ---TFN PM5100 100KHz-1GHz
  17. 科学家研发独特AI算法:用WiFi监测你是否在做梦
  18. leetcode:java.T018_4Sum---给定一个整数数组,找出a + b + c + d = target的唯一解,不能有重复元素组
  19. Invalid bound statement (not found): com.example.demo.mapper.getUser.
  20. ELTEK电源维修SMPS5000SIL易达整流模块维修概述

热门文章

  1. C# 货币金额中文(英文)大写转换方法-工具类
  2. python和c哪个好找工作,Python和c++哪个好就业
  3. 【算法竞赛练习题入门】在进行了多组输入 之后 再多组输出执行结果
  4. matlab和python的特征值函数eig
  5. 克鲁赛德战记php,克鲁赛德战记角色培养误区详解
  6. 索引聚焦如何使 SQL Server高效 -- 设计(ITPUT 讨论汇总)
  7. 欧洲气象中心资料(ERA-interim)下载方法简介
  8. 手写Promise和all、race等方法,附上原理解析
  9. pySpark 运行时出现 Permission denied: (权限问题)
  10. Apache POI使用详解