OpenHarmony开发实例:【仿桌面应用】

devtools/2024/12/22 18:39:59/

 介绍

本示例实现了一个简单桌面应用,实现了以下几点功能:

1.展示了系统安装的应用,实现点击启动、应用上滑弹出卡片、卡片添加到桌面、卡片移除功能。

2.实现桌面数据持久化存储,应用支持卸载、监听应用卸载和安装并显示。

3.实现最近任务管理功能,包括任务卡片加锁、解锁、清理和清理所有任务功能。

4.通过点击应用图标或点击由长按图标弹出的菜单栏中的打开按钮的方式打开应用,是以打开最近任务方式拉起应用Ability。

效果预览

image.png

使用说明

1.安装编译的hap包,使用hdc shell aa start -b ohos.samples.launcher -a MainAbility命令启动应用,应用启动后显示系统安装的应用。

2.点击应用主界面上的应用图标可以启动应用,长按弹出菜单,点击打开可以正常启动应用。

3.图库等支持卡片的应用,长按菜单中有服务卡片,点击进入卡片预览界面,在卡片预览界面点击添加到桌面,返回到桌面并且卡片成功添加到桌面。

4.上滑图库等支持卡片的应用,可以弹出默认上滑卡片,点击上滑卡片右上角的**+**图标,可以添加卡片到桌面。

5.应用在桌面界面,使用hdc install安装一个应用,桌面可以监听到应用安装,并显示新安装的应用到桌面上。

6.应用在桌面界面,使用hdc uninstall 卸载第5步安装的应用,桌面可以监听到卸载,并移除桌面上的应用。

7.在桌面空白处上滑,可以进入最近任务管理界面,下滑任务卡片可以加锁/解锁,上滑卡片可以清理该后台任务,点击垃圾桶可以清除所有后台任务(加锁的应用不会被清理掉)。

代码解读

鸿蒙next开发文档参考了:qr23.cn/AKFP8k点击或者复制转到。

entry/src/main/ets/
|---Application
|   |---MyAbilityStage.ts
|---components
|   |---FormManagerComponent.ets               // 弹窗组件
|---MainAbility
|   |---MainAbility.ts
|---manager
|   |---WindowManager.ts                       // 数据类型
|---pages
|   |---FormPage.ets                           // 首页
|   |---Home.ets                               // 详情页面
|   |---RecentsPage.ets                        // 详情页面

具体实现

搜狗高速浏览器截图20240326151344.png

  • 获取应用功能模块

    • 使用launcherBundleManager模块接口(系统能力:SystemCapability.BundleManager.BundleFramework),获取所有应用信息和给定包名获取应用信息,实现桌面展示所有安装的应用。使用on接口监听应用的安装和卸载从而实现应用安装和卸载刷新桌面。
  • 源码链接:[LauncherAbilityManager.ts]

/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import installer from '@ohos.bundle.installer';import launcherBundleManager from '@ohos.bundle.launcherBundleManager';import bundleMonitor from '@ohos.bundle.bundleMonitor';import osAccount from '@ohos.account.osAccount'import { AppItemInfo } from '../bean/AppItemInfo'import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'import { CommonConstants } from '../constants/CommonConstants'import { EventConstants } from '../constants/EventConstants'import { ResourceManager } from './ResourceManager'import { Logger } from '../utils/Logger'import type { BusinessError } from '@ohos.base';const TAG: string = 'LauncherAbilityManager'/*** Wrapper class for innerBundleManager and formManager interfaces.*/export class LauncherAbilityManager {private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'private static launcherAbilityManager: LauncherAbilityManager = undefinedprivate readonly mAppMap = new Map<string, AppItemInfo>()private mResourceManager: ResourceManager = undefinedprivate readonly mLauncherAbilityChangeListeners: any[] = []private mUserId: number = 100private context: any = undefinedconstructor(context) {this.context = contextthis.mResourceManager = ResourceManager.getInstance(context)const osAccountManager = osAccount.getAccountManager()osAccountManager.getOsAccountLocalIdFromProcess((err, localId) => {Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)this.mUserId = localId})}/*** Get the application data model object.** @return {object} application data model singleton*/static getInstance(context): LauncherAbilityManager {if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {this.launcherAbilityManager = new LauncherAbilityManager(context)}return this.launcherAbilityManager}/*** get all app List info from BMS** @return 应用的入口Ability信息列表*/async getLauncherAbilityList(): Promise<AppItemInfo[]> {Logger.info(TAG, 'getLauncherAbilityList begin')let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)const appItemInfoList = new Array<AppItemInfo>()if (CheckEmptyUtils.isEmpty(abilityList)) {Logger.info(TAG, 'getLauncherAbilityList Empty')return appItemInfoList}for (let i = 0; i < abilityList.length; i++) {let appItem = await this.transToAppItemInfo(abilityList[i])appItemInfoList.push(appItem)}return appItemInfoList}/*** get AppItemInfo from BMS with bundleName* @params bundleName* @return AppItemInfo*/async getAppInfoByBundleName(bundleName: string): Promise<AppItemInfo | undefined> {let appItemInfo: AppItemInfo | undefined = undefined// get from cacheif (this.mAppMap != null && this.mAppMap.has(bundleName)) {appItemInfo = this.mAppMap.get(bundleName)}if (appItemInfo != undefined) {Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)return appItemInfo}// get from systemlet abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)if (abilityInfos == undefined || abilityInfos.length == 0) {Logger.info(TAG, `${bundleName} has no launcher ability`)return undefined}let appInfo = abilityInfos[0]const data = await this.transToAppItemInfo(appInfo)Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)return data}private async transToAppItemInfo(info): Promise<AppItemInfo> {const appItemInfo = new AppItemInfo()appItemInfo.appName = await this.mResourceManager.getAppNameSync(info.labelId, info.elementName.bundleName, info.applicationInfo.label)appItemInfo.isSystemApp = info.applicationInfo.systemAppappItemInfo.isUninstallAble = info.applicationInfo.removableappItemInfo.appIconId = info.iconIdappItemInfo.appLabelId = info.labelIdappItemInfo.bundleName = info.elementName.bundleNameappItemInfo.abilityName = info.elementName.abilityNameawait this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)this.mAppMap.set(appItemInfo.bundleName, appItemInfo)return appItemInfo}/*** 启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbility(paramAbilityName, paramBundleName) {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)this.context.startAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success')}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)})}/*** 通过桌面图标启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);this.context.startRecentAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success');}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);});}/*** 卸载应用** @params bundleName 应用包名* @params callback 卸载回调*/async uninstallLauncherAbility(bundleName: string, callback): Promise<void> {Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);const bundlerInstaller = await installer.getBundleInstaller();bundlerInstaller.uninstall(bundleName, {userId: this.mUserId,installFlag: 0,isKeepData: false}, (err: BusinessError) => {Logger.info(TAG, `uninstallLauncherAbility result => ${JSON.stringify(err)}`);callback(err);})}/*** 开始监听系统应用状态.** @params listener 监听对象*/registerLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}})bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}AppStorage.Set('isRefresh', true)})}const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index == CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.push(listener)}}}/*** 取消监听系统应用状态.** @params listener 监听对象*/unregisterLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index != CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.splice(index, 1)}if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)}}}private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)}}}
  • 接口参考:[@ohos.bundle.launcherBundleManager]

  • 应用卸载功能模块

  • 使用bundle模块的getBundleInstaller接口获取到BundleInstaller(系统能力:SystemCapability.BundleManager.BundleFramework),调用uninstall接口实现应用卸载功能。

  • 源码链接:[LauncherAbilityManager.ts]

/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import installer from '@ohos.bundle.installer';import launcherBundleManager from '@ohos.bundle.launcherBundleManager';import bundleMonitor from '@ohos.bundle.bundleMonitor';import osAccount from '@ohos.account.osAccount'import { AppItemInfo } from '../bean/AppItemInfo'import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'import { CommonConstants } from '../constants/CommonConstants'import { EventConstants } from '../constants/EventConstants'import { ResourceManager } from './ResourceManager'import { Logger } from '../utils/Logger'import type { BusinessError } from '@ohos.base';const TAG: string = 'LauncherAbilityManager'/*** Wrapper class for innerBundleManager and formManager interfaces.*/export class LauncherAbilityManager {private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'private static launcherAbilityManager: LauncherAbilityManager = undefinedprivate readonly mAppMap = new Map<string, AppItemInfo>()private mResourceManager: ResourceManager = undefinedprivate readonly mLauncherAbilityChangeListeners: any[] = []private mUserId: number = 100private context: any = undefinedconstructor(context) {this.context = contextthis.mResourceManager = ResourceManager.getInstance(context)const osAccountManager = osAccount.getAccountManager()osAccountManager.getOsAccountLocalIdFromProcess((err, localId) => {Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)this.mUserId = localId})}/*** Get the application data model object.** @return {object} application data model singleton*/static getInstance(context): LauncherAbilityManager {if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {this.launcherAbilityManager = new LauncherAbilityManager(context)}return this.launcherAbilityManager}/*** get all app List info from BMS** @return 应用的入口Ability信息列表*/async getLauncherAbilityList(): Promise<AppItemInfo[]> {Logger.info(TAG, 'getLauncherAbilityList begin')let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)const appItemInfoList = new Array<AppItemInfo>()if (CheckEmptyUtils.isEmpty(abilityList)) {Logger.info(TAG, 'getLauncherAbilityList Empty')return appItemInfoList}for (let i = 0; i < abilityList.length; i++) {let appItem = await this.transToAppItemInfo(abilityList[i])appItemInfoList.push(appItem)}return appItemInfoList}/*** get AppItemInfo from BMS with bundleName* @params bundleName* @return AppItemInfo*/async getAppInfoByBundleName(bundleName: string): Promise<AppItemInfo | undefined> {let appItemInfo: AppItemInfo | undefined = undefined// get from cacheif (this.mAppMap != null && this.mAppMap.has(bundleName)) {appItemInfo = this.mAppMap.get(bundleName)}if (appItemInfo != undefined) {Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)return appItemInfo}// get from systemlet abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)if (abilityInfos == undefined || abilityInfos.length == 0) {Logger.info(TAG, `${bundleName} has no launcher ability`)return undefined}let appInfo = abilityInfos[0]const data = await this.transToAppItemInfo(appInfo)Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)return data}private async transToAppItemInfo(info): Promise<AppItemInfo> {const appItemInfo = new AppItemInfo()appItemInfo.appName = await this.mResourceManager.getAppNameSync(info.labelId, info.elementName.bundleName, info.applicationInfo.label)appItemInfo.isSystemApp = info.applicationInfo.systemAppappItemInfo.isUninstallAble = info.applicationInfo.removableappItemInfo.appIconId = info.iconIdappItemInfo.appLabelId = info.labelIdappItemInfo.bundleName = info.elementName.bundleNameappItemInfo.abilityName = info.elementName.abilityNameawait this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)this.mAppMap.set(appItemInfo.bundleName, appItemInfo)return appItemInfo}/*** 启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbility(paramAbilityName, paramBundleName) {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)this.context.startAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success')}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)})}/*** 通过桌面图标启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);this.context.startRecentAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success');}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);});}/*** 卸载应用** @params bundleName 应用包名* @params callback 卸载回调*/async uninstallLauncherAbility(bundleName: string, callback): Promise<void> {Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);const bundlerInstaller = await installer.getBundleInstaller();bundlerInstaller.uninstall(bundleName, {userId: this.mUserId,installFlag: 0,isKeepData: false}, (err: BusinessError) => {Logger.info(TAG, `uninstallLauncherAbility result => ${JSON.stringify(err)}`);callback(err);})}/*** 开始监听系统应用状态.** @params listener 监听对象*/registerLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}})bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}AppStorage.Set('isRefresh', true)})}const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index == CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.push(listener)}}}/*** 取消监听系统应用状态.** @params listener 监听对象*/unregisterLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index != CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.splice(index, 1)}if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)}}}private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)}}}

  • 接口参考:[@ohos.bundle]

  • 添加卡片功能模块

  • 使用formHost接口(系统能力:SystemCapability.Ability.Form),获取应用卡片信息,使用FormComponent组件展示卡片内容,从而实现添加卡片到桌面的功能。

  • 源码链接:[FormManager.ts]

/** Copyright (c) 2022 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import formManagerAbility from '@ohos.app.form.formHost'import { CardItemInfo } from '../bean/CardItemInfo'import { CommonConstants } from '../constants/CommonConstants'import { Logger } from '../utils/Logger'const TAG: string = 'FormManager'/*** Wrapper class for formManager interfaces.*/class FormManagerModel {private readonly CARD_SIZE_1x2: number[] = [1, 2]private readonly CARD_SIZE_2x2: number[] = [2, 2]private readonly CARD_SIZE_2x4: number[] = [2, 4]private readonly CARD_SIZE_4x4: number[] = [4, 4]/*** get all form info** @return Array<CardItemInfo> cardItemInfoList*/public async getAllFormsInfo(): Promise<CardItemInfo[]> {const formList = await formManagerAbility.getAllFormsInfo()const cardItemInfoList = new Array<CardItemInfo>()for (const formItem of formList) {const cardItemInfo = new CardItemInfo()cardItemInfo.bundleName = formItem.bundleNamecardItemInfo.abilityName = formItem.abilityNamecardItemInfo.moduleName = formItem.moduleNamecardItemInfo.cardName = formItem.namecardItemInfo.cardDimension = formItem.defaultDimensioncardItemInfo.description = formItem.descriptioncardItemInfo.formConfigAbility = formItem.formConfigAbilitycardItemInfo.supportDimensions = formItem.supportDimensionscardItemInfo.area = this.getCardSize(cardItemInfo.cardDimension)cardItemInfoList.push(cardItemInfo)}return cardItemInfoList}/*** get card area by dimension** @param dimension* @return number[]*/public getCardSize(dimension: number): number[] {if (dimension == CommonConstants.CARD_DIMENSION_1x2) {return this.CARD_SIZE_1x2} else if (dimension == CommonConstants.CARD_DIMENSION_2x2) {return this.CARD_SIZE_2x2} else if (dimension == CommonConstants.CARD_DIMENSION_2x4) {return this.CARD_SIZE_2x4} else {return this.CARD_SIZE_4x4}}/*** get card dimension bty area** @param dimension* @return number[]*/public getCardDimension(area: number[]) {if (area.toString() === this.CARD_SIZE_1x2.toString()) {return CommonConstants.CARD_DIMENSION_1x2} else if (area.toString() === this.CARD_SIZE_2x2.toString()) {return CommonConstants.CARD_DIMENSION_2x2} else if (area.toString() == this.CARD_SIZE_2x4.toString()) {return CommonConstants.CARD_DIMENSION_2x4} else {return CommonConstants.CARD_DIMENSION_4x4}}/*** get form info by bundleName** @param bundle* @return Array<CardItemInfo> cardItemInfoList*/public async getFormsInfoByApp(bundle: string): Promise<CardItemInfo[]> {Logger.info(TAG, `getFormsInfoByApp bundle: ${bundle}`)const formList = await formManagerAbility.getFormsInfo(bundle)const cardItemInfoList = new Array<CardItemInfo>()for (const formItem of formList) {const cardItemInfo = new CardItemInfo()cardItemInfo.bundleName = formItem.bundleNamecardItemInfo.abilityName = formItem.abilityNamecardItemInfo.moduleName = formItem.moduleNamecardItemInfo.cardName = formItem.namecardItemInfo.cardDimension = formItem.defaultDimensioncardItemInfo.area = this.getCardSize(cardItemInfo.cardDimension)cardItemInfo.description = formItem.descriptioncardItemInfo.formConfigAbility = formItem.formConfigAbilitycardItemInfo.supportDimensions = formItem.supportDimensionscardItemInfoList.push(cardItemInfo)}return cardItemInfoList}}export let FormManager =  new FormManagerModel()
  • 接口参考:[@ohos.app.form.formHost]

  • 桌面数据持久化存储功能模块

    • 使用关系型数据库rdb接口(系统能力:SystemCapability.DistributedDataManager.RelationalStore.Core),实现桌面数据持久化存储,存储应用的位置信息,卡片信息。
  • 源码链接:[RdbManager.ts]

/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import dataRdb from '@ohos.data.relationalStore'import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'import { CommonConstants } from '../constants/CommonConstants'import { GridLayoutItemInfo } from '../bean/GridLayoutItemInfo'import { GridLayoutInfoColumns } from '../bean/GridLayoutInfoColumns'import { Logger } from '../utils/Logger'export const TABLE_NAME: string = 'launcher'export const SQL_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS launcher ' +'(id INTEGER PRIMARY KEY AUTOINCREMENT, ' +'app_name TEXT, ' +'appIcon_id INTEGER, ' +'container INTEGER, ' +'type_id INTEGER, ' +'card_id INTEGER, ' +'card_name TEXT, ' +'badge_number INTEGER, ' +'module_name TEXT, ' +'bundle_name TEXT, ' +'ability_name TEXT, ' +'area TEXT, ' +'page INTEGER, ' +'column INTEGER, ' +'row INTEGER)'export const STORE_CONFIG = { name: 'launcher.db', securityLevel: dataRdb.SecurityLevel.S1 }const TAG: string = 'RdbModel'class RdbManagerModel {private mRdbStore: dataRdb.RdbStore = undefinedconstructor() {}/*** initRdbConfig** @param context*/async initRdbConfig(context): Promise<void> {Logger.info(TAG, 'initRdbConfig start')if (this.mRdbStore === undefined) {this.mRdbStore = await dataRdb.getRdbStore(context, STORE_CONFIG);await this.mRdbStore.executeSql(SQL_CREATE_TABLE);Logger.info(TAG, 'create table end');}}/*** deleteTable** @param tableName*/async deleteTable(tableName: string): Promise<void> {Logger.info(TAG, 'deleteTable start')try {let detelSql = `DELETE FROM ${tableName};`let detelSequenceSql = `UPDATE sqlite_sequence SET seq=0 WHERE name = '${tableName}';`await this.mRdbStore.executeSql(detelSql)await this.mRdbStore.executeSql(detelSequenceSql)Logger.debug(TAG, 'deleteTable end')} catch (e) {Logger.error(TAG, `deleteTable err: ${e}`)}}/*** insertData** @param layoutInfo*/async insertData(layoutInfo: any) {Logger.info(TAG, 'insertGridLayoutInfo start');let result: boolean = trueif (CheckEmptyUtils.isEmpty(layoutInfo)) {Logger.error(TAG, 'insertGridLayoutInfo gridlayoutinfo is empty')result = falsereturn result}try {// delete gridlayoutinfo tableawait this.deleteTable(TABLE_NAME)// insert into gridlayoutinfofor (let i in layoutInfo) {let layout = layoutInfo[i]for (let j in layout) {let element = layout[j]Logger.info(TAG, `insertGridLayoutInfo i= ${i}`)let item = {}if (element.typeId === CommonConstants.TYPE_APP) {item = {'app_name': element.appName,'bundle_name': element.bundleName,'module_name': element.modelName,'ability_name': element.abilityName,'appIcon_id': element.appIconId,'type_id': element.typeId,'area': element.area[0] + ',' + element.area[1],'page': element.page,'column': element.column,'row': element.row,'container': -100}let ret = await this.mRdbStore.insert(TABLE_NAME, item)Logger.debug(TAG, `insertGridLayoutInfo type is app ${i} ret: ${ret}`)} else if (element.typeId === CommonConstants.TYPE_CARD) {item = {'app_name': element.appName,'bundle_name': element.bundleName,'module_name': element.modelName,'ability_name': element.abilityName,'card_id': element.cardId,'card_name': element.cardName,'type_id': element.typeId,'area': element.area[0] + ',' + element.area[1],'page': element.page,'column': element.column,'row': element.row,'container': -100}let ret = await this.mRdbStore.insert(TABLE_NAME, item)Logger.debug(TAG, `insertGridLayoutInfo type is card ${i} ret: ${ret}`)}}}} catch (e) {Logger.error(TAG, `insertGridLayoutInfo error: ${e}`)}return result}async queryLayoutInfo() {Logger.info(TAG, 'queryLayoutInfo start')const resultList: GridLayoutItemInfo[] = []const predicates = new dataRdb.RdbPredicates(TABLE_NAME)predicates.equalTo(GridLayoutInfoColumns.CONTAINER, -100).and().orderByAsc('page').and().orderByAsc('row').and().orderByAsc('column')let resultSet = await this.mRdbStore.query(predicates)Logger.info(TAG, `queryLayoutInfo query,count=${resultSet.rowCount}`)let isLast = resultSet.goToFirstRow()while (isLast) {const layoutInfo: GridLayoutItemInfo = GridLayoutItemInfo.fromResultSet(resultSet)resultList.push(layoutInfo)isLast = resultSet.goToNextRow()}resultSet.close()resultSet = nullreturn resultList}async insertItem(item: GridLayoutItemInfo) {if (CheckEmptyUtils.isEmpty(item)) {return}let element = {'app_name': item.appName,'module_name': item.moduleName,'bundle_name': item.bundleName,'ability_name': item.abilityName,'appIcon_id': item.appIconId,'card_id': item.cardId,'card_name': item.cardName,'type_id': item.typeId,'area': item.area[0] + ',' + item.area[1],'page': item.page,'column': item.column,'row': item.row,'container': -100}let ret = await this.mRdbStore.insert(TABLE_NAME, element)Logger.debug(TAG, `insertGridLayoutInfo ret: ${ret}`)}async deleteItemByPosition(page: number, row: number, column: number) {const predicates = new dataRdb.RdbPredicates(TABLE_NAME);predicates.equalTo('page', page).and().equalTo('row', row).and().equalTo('column', column);let query = await this.mRdbStore.query(predicates);if (query.rowCount > 0) {let ret = await this.mRdbStore.delete(predicates);Logger.debug(TAG, `deleteItem ret: ${ret}`);}}}export let RdbManager = new RdbManagerModel()
  • 接口参考:[@ohos.data.relationalStore]

  • 加锁、解锁、清理后台任务功能模块

    • 使用missionManager模块接口(系统能力:SystemCapability.Ability.AbilityRuntime.Mission),获取最近任务信息,并实现加锁、解锁、清理后台任务的功能。
    • 源码链接:[MissionModel.ts]
    • 接口参考:[@ohos.application.missionManager]
  • 点击桌面应用拉起最近任务至前台功能模块

    • 使用ServiceExtensionContext模块的startRecentAbility接口(系统能力:SystemCapability.Ability.AbilityRuntime.Core),拉起最近任务至前台显示,若应用Ability未启动时,则拉起新创建的应用Ability显示到前台。 源码链接:[LauncherAbilityManager.ts]
 
/** Copyright (c) 2022-2023 Huawei Device Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import installer from '@ohos.bundle.installer';import launcherBundleManager from '@ohos.bundle.launcherBundleManager';import bundleMonitor from '@ohos.bundle.bundleMonitor';import osAccount from '@ohos.account.osAccount'import { AppItemInfo } from '../bean/AppItemInfo'import { CheckEmptyUtils } from '../utils/CheckEmptyUtils'import { CommonConstants } from '../constants/CommonConstants'import { EventConstants } from '../constants/EventConstants'import { ResourceManager } from './ResourceManager'import { Logger } from '../utils/Logger'import type { BusinessError } from '@ohos.base';const TAG: string = 'LauncherAbilityManager'/*** Wrapper class for innerBundleManager and formManager interfaces.*/export class LauncherAbilityManager {private static readonly BUNDLE_STATUS_CHANGE_KEY_REMOVE = 'remove'private static readonly BUNDLE_STATUS_CHANGE_KEY_ADD = 'add'private static launcherAbilityManager: LauncherAbilityManager = undefinedprivate readonly mAppMap = new Map<string, AppItemInfo>()private mResourceManager: ResourceManager = undefinedprivate readonly mLauncherAbilityChangeListeners: any[] = []private mUserId: number = 100private context: any = undefinedconstructor(context) {this.context = contextthis.mResourceManager = ResourceManager.getInstance(context)const osAccountManager = osAccount.getAccountManager()osAccountManager.getOsAccountLocalIdFromProcess((err, localId) => {Logger.debug(TAG, `getOsAccountLocalIdFromProcess localId ${localId}`)this.mUserId = localId})}/*** Get the application data model object.** @return {object} application data model singleton*/static getInstance(context): LauncherAbilityManager {if (this.launcherAbilityManager === null || this.launcherAbilityManager === undefined) {this.launcherAbilityManager = new LauncherAbilityManager(context)}return this.launcherAbilityManager}/*** get all app List info from BMS** @return 应用的入口Ability信息列表*/async getLauncherAbilityList(): Promise<AppItemInfo[]> {Logger.info(TAG, 'getLauncherAbilityList begin')let abilityList = await launcherBundleManager.getAllLauncherAbilityInfo(this.mUserId)const appItemInfoList = new Array<AppItemInfo>()if (CheckEmptyUtils.isEmpty(abilityList)) {Logger.info(TAG, 'getLauncherAbilityList Empty')return appItemInfoList}for (let i = 0; i < abilityList.length; i++) {let appItem = await this.transToAppItemInfo(abilityList[i])appItemInfoList.push(appItem)}return appItemInfoList}/*** get AppItemInfo from BMS with bundleName* @params bundleName* @return AppItemInfo*/async getAppInfoByBundleName(bundleName: string): Promise<AppItemInfo | undefined> {let appItemInfo: AppItemInfo | undefined = undefined// get from cacheif (this.mAppMap != null && this.mAppMap.has(bundleName)) {appItemInfo = this.mAppMap.get(bundleName)}if (appItemInfo != undefined) {Logger.info(TAG, `getAppInfoByBundleName from cache: ${JSON.stringify(appItemInfo)}`)return appItemInfo}// get from systemlet abilityInfos = await launcherBundleManager.getLauncherAbilityInfo(bundleName, this.mUserId)if (abilityInfos == undefined || abilityInfos.length == 0) {Logger.info(TAG, `${bundleName} has no launcher ability`)return undefined}let appInfo = abilityInfos[0]const data = await this.transToAppItemInfo(appInfo)Logger.info(TAG, `getAppInfoByBundleName from BMS: ${JSON.stringify(data)}`)return data}private async transToAppItemInfo(info): Promise<AppItemInfo> {const appItemInfo = new AppItemInfo()appItemInfo.appName = await this.mResourceManager.getAppNameSync(info.labelId, info.elementName.bundleName, info.applicationInfo.label)appItemInfo.isSystemApp = info.applicationInfo.systemAppappItemInfo.isUninstallAble = info.applicationInfo.removableappItemInfo.appIconId = info.iconIdappItemInfo.appLabelId = info.labelIdappItemInfo.bundleName = info.elementName.bundleNameappItemInfo.abilityName = info.elementName.abilityNameawait this.mResourceManager.updateIconCache(appItemInfo.appIconId, appItemInfo.bundleName)this.mAppMap.set(appItemInfo.bundleName, appItemInfo)return appItemInfo}/*** 启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbility(paramAbilityName, paramBundleName) {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`)this.context.startAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success')}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`)})}/*** 通过桌面图标启动应用** @params paramAbilityName Ability名* @params paramBundleName 应用包名*/startLauncherAbilityFromRecent(paramAbilityName, paramBundleName): void {Logger.info(TAG, `startApplication abilityName: ${paramAbilityName}, bundleName: ${paramBundleName}`);this.context.startRecentAbility({bundleName: paramBundleName,abilityName: paramAbilityName}).then(() => {Logger.info(TAG, 'startApplication promise success');}, (err) => {Logger.error(TAG, `startApplication promise error: ${JSON.stringify(err)}`);});}/*** 卸载应用** @params bundleName 应用包名* @params callback 卸载回调*/async uninstallLauncherAbility(bundleName: string, callback): Promise<void> {Logger.info(TAG, `uninstallLauncherAbility bundleName: ${bundleName}`);const bundlerInstaller = await installer.getBundleInstaller();bundlerInstaller.uninstall(bundleName, {userId: this.mUserId,installFlag: 0,isKeepData: false}, (err: BusinessError) => {Logger.info(TAG, `uninstallLauncherAbility result => ${JSON.stringify(err)}`);callback(err);})}/*** 开始监听系统应用状态.** @params listener 监听对象*/registerLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback add bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_ADDED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}})bundleMonitor.on(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE, (bundleChangeInfo) => {Logger.debug(TAG, `mBundleStatusCallback remove bundleName: ${bundleChangeInfo.bundleName},userId: ${bundleChangeInfo.userId}, mUserId ${this.mUserId}`)if (this.mUserId === bundleChangeInfo.userId) {this.notifyLauncherAbilityChange(EventConstants.EVENT_PACKAGE_REMOVED,bundleChangeInfo.bundleName, bundleChangeInfo.userId)}AppStorage.Set('isRefresh', true)})}const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index == CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.push(listener)}}}/*** 取消监听系统应用状态.** @params listener 监听对象*/unregisterLauncherAbilityChangeListener(listener: any): void {if (!CheckEmptyUtils.isEmpty(listener)) {const index = this.mLauncherAbilityChangeListeners.indexOf(listener)if (index != CommonConstants.INVALID_VALUE) {this.mLauncherAbilityChangeListeners.splice(index, 1)}if (this.mLauncherAbilityChangeListeners.length == 0) {bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_ADD)bundleMonitor.off(LauncherAbilityManager.BUNDLE_STATUS_CHANGE_KEY_REMOVE)}}}private notifyLauncherAbilityChange(event: string, bundleName: string, userId: number): void {for (let index = 0; index < this.mLauncherAbilityChangeListeners.length; index++) {this.mLauncherAbilityChangeListeners[index](event, bundleName, userId)}}}

接口参考:[@ohos.app.ability.ServiceExtensionAbility]

鸿蒙开发>鸿蒙开发岗位需要掌握那些核心要领?

目前还有很多小伙伴不知道要学习哪些鸿蒙技术?不知道重点掌握哪些?为了避免学习时频繁踩坑,最终浪费大量时间的。

自己学习时必须要有一份实用的鸿蒙(Harmony NEXT)资料非常有必要。 这里我推荐,根据鸿蒙开发>鸿蒙开发官网梳理与华为内部人员的分享总结出的开发文档。内容包含了:【ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战】等技术知识点。

废话就不多说了,接下来好好看下这份资料。

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习鸿蒙OpenHarmony知识←前往。下面是鸿蒙开发>鸿蒙开发的学习路线图。

针对鸿蒙成长路线打造的鸿蒙学习文档。鸿蒙OpenHarmony )学习手册(共计1236页)与鸿蒙OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

其中内容包含:

鸿蒙开发>鸿蒙开发基础》鸿蒙OpenHarmony知识←前往

  1. ArkTS语言
  2. 安装DevEco Studio
  3. 运用你的第一个ArkTS应用
  4. ArkUI声明式UI开发
  5. .……

鸿蒙开发>鸿蒙开发进阶》鸿蒙OpenHarmony知识←前往

  1. Stage模型入门
  2. 网络管理
  3. 数据管理
  4. 电话服务
  5. 分布式应用开发
  6. 通知与窗口管理
  7. 多媒体技术
  8. 安全技能
  9. 任务管理
  10. WebGL
  11. 国际化开发
  12. 应用测试
  13. DFX面向未来设计
  14. 鸿蒙系统>鸿蒙系统移植和裁剪定制
  15. ……

鸿蒙开发>鸿蒙开发实战》鸿蒙OpenHarmony知识←前往

  1. ArkTS实践
  2. UIAbility应用
  3. 网络案例
  4. ……

最后

鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发>鸿蒙开发,这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发>鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!


http://www.ppmy.cn/devtools/1770.html

相关文章

Qt | 事件第一节(QApplication、QGuiApplication、QCoreApplication)

一、QApplication、QGuiApplication、QCoreApplication 简介 1、继承关系见下图,其中左侧为顶级父类 2、一个程序中只能有一个 QCoreApplication 及其子类的对象。 3、QCoreApplication:主要提供无 GUI 程序的事件循环。 4、QGuiApplication:用于管理 GUI 程序的控制流和…

备忘录模式:恢复对象状态的智能方式

在软件开发中&#xff0c;备忘录模式是一种行为型设计模式&#xff0c;它允许捕获并外部化对象的内部状态&#xff0c;以便在未来某个时刻可以将对象恢复到此状态。这种模式是撤销操作或者回滚操作的关键实现机制。本文将详细介绍备忘录模式的定义、实现、应用场景以及优缺点。…

量子时代加密安全与区块链应用的未来

量子时代加密安全与区块链应用的未来 现代密码学仍然是一门相对年轻的学科&#xff0c;但其历史却显示了一种重要的模式。大多数的发展都是基于几年甚至几十年前的研究。而这种缓慢的发展速度也是有原因的&#xff0c;就像药物和疫苗在进入市场之前需要经过多年的严格测试一样&…

MySQL--表的操作

目录 创建表 查看表结构 修改表 新增列 修改列类型 修改列名 修改表名&#xff1a; 删除列 删除表 创建表 语法&#xff1a; CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引…

蓝桥杯2024年第十五届省赛真题-爬山

贪心优先队列的题&#xff0c;贪心会漏一个情况&#xff0c;不知道怎么处理&#xff0c;这里直接打表了 2 1 1 48 49 答案是30&#xff0c;贪心是31 专有名词&#xff1a;hack-有新的测试点过不了 #include<bits/stdc.h> using namespace std; #define endl \n #define …

【北京迅为】《iTOP-3588开发板系统编程手册》第5章 文件IO缓存

RK3588是一款低功耗、高性能的处理器&#xff0c;适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用&#xff0c;RK3588支持8K视频编解码&#xff0c;内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

AutoCAD之DWF三维信息提取---linux编译篇

1. 权限 1.1 给文件添加执行权限 chmod x autogen.sh1.2.给当前文件下的所有文件改变为读写执行权限 chmod 777 * -R 2.环境安装 2.1安装automake 1.4.1 安装链接 安装中遇到的问题及解决 2.2安装autoconf 2.3 安装libtool 2.4 安装Cmake(CMake包含) cmake安装在cent…

qt对json文件下,qdatetime时间的正确读写方式

qt 对json文件下qdatetime时间的正确读写方式 被搞了很长时间&#xff0c;最后发现是需要控制格式。 正确方式 // read QByteArray localBytes mapJson["playTime"].toString().toLocal8Bit(); char* char_time localBytes.data(); std::string str_time char_…