赞
踩
一、源码解析的目的:
为什么要去做源码解析这件事?我个人认为,首先可以提高我们对代码书写的能力,毕竟官方系统级的应用,会比demo的写法更专业,让我们更能学到些写法技巧。其次,分析源码是对我们学习开发技术,提升最快的方法之一。
确立认知后,我们做一件事才能更有能力的驱动。
二、准备环境:
用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.ts
import 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.ts export 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.photoPadding case 'VIDEO': return this.videoPadding } } } export class PaddingData { top = 48 bottom = 154 }
FormAbility-FormAbility.ts
之前介绍过,API9的Stage模型。将Ability分为Ability和ExtensionAbility两大类。
其中ExtensionAbility又被扩展为ServiceExtensionAbility、FormExtensionAbility、DataShareExtensionAbility等等一系列ExtensionAbility,以便满足更多的使用场景。
而FormExtensionAbility 提供了卡片扩展相关接口。可以看到相机源码里,没有创建卡片相关的能力。
FormAbility-FormAbility.ts import 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.ts import 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中的context globalThis.cameraAbilityContext = this.context // Ability启动时的参数。 globalThis.cameraAbilityWant = this.launchWant // 相机需要的权限是否已经授权,默认false globalThis.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({ // 设置导航栏颜色为黑色有透明度,导航栏操作按钮颜色为#B3B3B3 navigationBarColor: '#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 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。