• [技术交流] 开发者技术支持-RelativeContainer自适应问题
    ​一、问题说明RelativeContainer相对容器是我们日常开发中常用组件,尤其当我们开发复杂布局的时候,可以减少布局的层级,减少布局的渲染消耗。有些场景下我们需要让RelativeContainer自适应而不是写死高度,让如何让RelativeContainer自适应?二、原因分析鸿蒙的的相对布局自适应与安卓的自适应使用情况不同,按照安卓的使用方式给高度增加auto后不生效,我们查找官方文档发现了关键描述:什么意思?举个栗子,如果我们竖直方向上让高度自适应时,不仅设置高度auto同时还要要求子组件在竖直方向上没有父组件RelativeContainer锚点的Id引用、使用,通过代码我们观察效果。三、解决思路​​RelativeContainer作为容器高度auto,在竖直方向上有容器锚点的引用:RelativeContainer() { Text('我是子组件1') .width('100%') .height('100') .id('child_one') .textAlign(TextAlign.Center) .backgroundColor(Color.Pink) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: '__container__', align: VerticalAlign.Top } }) Text('我是子组件2') .width('100%') .height('100') .id('child_two') .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: 'child_one', align: VerticalAlign.Bottom } }) Text('我是子组件3') .width('100%') .height('100') .id('child_three') .textAlign(TextAlign.Center) .backgroundColor(Color.Brown) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: 'child_two', align: VerticalAlign.Bottom }, bottom: { anchor: '__container__', align: VerticalAlign.Bottom }, })}.height('auto').backgroundColor(Color.Blue)可以看到RelativeContainer的背景色仍然被拉满,竖直方向上铺满屏幕,auoto不生效。 RelativeContainer作为容器高度auto,在竖直方向上无容器锚点的引用: RelativeContainer() { Text('我是子组件1') .width('100%') .height('100') .id('child_one') .textAlign(TextAlign.Center) .backgroundColor(Color.Pink) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start } }) Text('我是子组件2') .width('100%') .height('100') .id('child_two') .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: 'child_one', align: VerticalAlign.Bottom } }) Text('我是子组件3') .width('100%') .height('100') .id('child_three') .textAlign(TextAlign.Center) .backgroundColor(Color.Brown) .alignRules({ left: { anchor: '__container__', align: HorizontalAlign.Start }, top: { anchor: 'child_two', align: VerticalAlign.Bottom } })}.height('auto').backgroundColor(Color.Blue)我们再通过ArkUI观察下:我们通过观察选中的RelativeContainer容器底部边界与子组件3的底部边界重合。四、解决方案​水平方向上使用同理,我们结合当前布局的复杂程度灵活选用对应组件,减少布局的嵌套。
  • [方案分享] 开发者支持--实况窗不能关闭问题
    一、问题说明当手势在手机桌面上滑调起最近使用的应用,找到当前应用上滑关闭、进程杀死的时候,实况窗不跟随app一起消失、关闭二、原因分析当前封装的Component组件的生命周期的aboutToDisappear方法内有调用liveViewManager.stopLiveView(defaultView)实况窗的销毁方法,增加打点日志分析:日志1console.log(TAG,"aboutToDisappear") //在组件的aboutToDisappear增加日志日志2console.log(TAG, ` 清除当前实况窗 `) //在实况窗liveViewManager.stopLiveView()销毁的执行前打印日志通过日志发现日志1有打印,日志2无打印,也就是说组件的生命周期aboutToDisappear执行了,但是销毁实况窗的方法没有执行到三、解决思路分析到了原因,尝试怎么销毁,在何时销毁,页面内销毁还是Ability内销毁。 UIAbility-->onDestroy():在UIAbility实例销毁之前,系统触发onDestroy回调。该回调是UIAbility接收到的最后一个生命周期回调,开发者可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。 @Entry装饰的组件(页面)-->onPageShow:页面每次显示时触发一次,包括路由过程、应用进入前台等场景。onPageHide:页面每次隐藏时触发一次,包括路由过程、应用进入后台等场景。onBackPress:当用户点击返回按钮时触发。 Component组件-->aboutToDisappear:在自定义组件析构销毁之前执行。不允许在aboutToDisappear函数中改变状态变量,特别是@Link变量的修改可能会导致应用程序行为不稳定。四、解决方案实况窗是系统级功能,属于 HarmonyOS NEXT 系统的一部分,主要用于提升多任务处理效率和信息展示方式,,我们尝试在UIAbility-->onDestroy()生命周期内销毁。通过封装管理类,根据创建实况窗时传标识Id,建立Id与实况窗的映射关系,通过Id和该管理类建立的映射关系支持某个实况窗的关闭,也支持所有实况窗的关闭,当应用关闭的时候我们尝试在UIAbility-->onDestroy()生命周期内销毁所有实况窗。 经过测试验证、日志打印发现,对应的销毁日志执行到了,即实况窗销毁了,至此问题解决了。
  • [技术交流] 开发者技术支持-native读取图片问题解决分享
    1.问题说明:    需求:arkts通过native接口传递图片路径,并由native层读取图片获取图片参数和内容。    问题:打开图片文件失败,图片色彩偏差。2.原因分析:    打开图片文件失败的可能原因:    (1)权限不足,系统限制打开该文件    (2)路径错误或文件异常    图片色彩偏差:    (1)图片解码参数错误    (2)像素格式不匹配,需要转换3.解决思路:    (1)检查文件所在目录是否有访问权限,访问权限是否申请。    (2)打印传递给native层的路径参数并检查,测试atkts打开图片是否异常。    (3)访问官方论坛查询相关接口,验证接口调用是否正确。    (4)仔细阅读文档或示例并打印相关数据做验证。4.解决方案:    打开图片文件失败的原因:传递的是沙箱路径,应转换为实际存储路径。相关转换代码如下: size_t argc = 1; napi_value argv[1] = {nullptr}; napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); std::unique_ptr < char[] > buf = std::make_unique < char[] >(2048); if (buf.get() == nullptr) { OH_LOG_ERROR(LOG_APP, "%s nullptr js object to string malloc failed.", __func__); return nullptr; } (void)memset(buf.get(), 0, 2048); size_t result = 0; napi_get_value_string_utf8(env, argv[0], buf.get(), 2048, &result); std::string target = buf.get(); unsigned int length = target.size(); char *pathResult = NULL; if(!target.empty() && strstr(target.c_str(), "file://")) { bool falgs = OH_FileUri_IsValidUri(target.c_str(), length); OH_LOG_INFO(LOG_APP, "The URI is valid? falgs=%{public}d", falgs); FileManagement_ErrCode err = OH_FileUri_GetPathFromUri(target.c_str(), length, &pathResult); if (err == 0 && pathResult != NULL) { OH_LOG_INFO(LOG_APP, "pathResult: %s", pathResult); } }    图片色彩偏差:像素格式不匹配,需要转换。图片解码及转换代码如下:typedef struct ImageInfo ImageInfo; struct ImageInfo { uint8_t *imageArray; uint32_t width; uint32_t height; }; ImageInfo createImageInfo(char* uri) { uint32_t width; uint32_t height; uint8_t *data = readImage(uri, &width, &height); if (!data) { return ImageInfo(); } ImageInfo info; info.imageArray = new (std::nothrow) uint8_t[width * height * 4]; memcpy(info.imageArray, data, width * height * 4); info.width = width; info.height = height; return info; }uint8_t* readImage(char *uri, uint32_t *width, uint32_t *height) { //创建ImageSource实例 OH_ImageSourceNative *source = nullptr; Image_ErrorCode errCode = OH_ImageSourceNative_CreateFromUri(uri, 2048, &source); if (errCode != IMAGE_SUCCESS) { //OH_LOG_ERROR(LOG_APP, "ImageSourceNativeCTest sourceTest OH_ImageSourceNative_CreateFromUri failed, errCode: %{public}d.", errCode); return nullptr; } //创建定义图片信息的结构体对象,并获取图片信息 OH_ImageSource_Info *imageInfo; OH_ImageSourceInfo_Create(&imageInfo); errCode = OH_ImageSourceNative_GetImageInfo(source, 0, imageInfo); if (errCode != IMAGE_SUCCESS) { //OH_LOG_ERROR(LOG_APP, "ImageSourceNativeCTest sourceTest OH_ImageSourceNative_GetImageInfo failed, errCode: %{public}d.", errCode); return nullptr; } //获取指定属性键的值 OH_ImageSourceInfo_GetWidth(imageInfo, width); OH_ImageSourceInfo_GetHeight(imageInfo, height); OH_ImageSourceInfo_Release(imageInfo); //通过图片解码参数创建PixelMap对象 OH_DecodingOptions *ops = nullptr; OH_DecodingOptions_Create(&ops); //设置为AUTO会根据图片资源格式解码,如果图片资源为HDR资源则会解码为HDR的pixelmap。 //OH_DecodingOptions_SetDesiredDynamicRange(ops, IMAGE_DYNAMIC_RANGE_AUTO); OH_PixelmapNative *resPixMap = nullptr; //ops参数支持传入nullptr, 当不需要设置解码参数时,不用创建 errCode = OH_ImageSourceNative_CreatePixelmap(source, ops, &resPixMap); OH_DecodingOptions_Release(ops); if (errCode != IMAGE_SUCCESS) { //OH_LOG_ERROR(LOG_APP, "ImageSourceNativeCTest sourceTest OH_ImageSourceNative_CreatePixelmap failed, errCode: %{public}d.", errCode); return nullptr; } uint8_t destination[(*width) * (*height) * 4]; size_t destinationSize = (*width) * (*height) * 4; errCode = OH_PixelmapNative_ReadPixels(resPixMap, destination, &destinationSize); if (errCode != IMAGE_SUCCESS) { //OH_LOG_ERROR(LOG_APP, "ImagePixelmapNativeCTest pixelmapTest OH_PixelmapNative_ReadPixels failed, errCode: %{public}d.", errCode); return nullptr; } bgra2rgba(destination, *width, *height); //memcpy(data, destination, destinationSize); //释放ImageSource实例 OH_ImageSourceNative_Release(source); //OH_LOG_INFO(LOG_APP, "ImagePixelmapNativeCTest pixelmapTest GetImageInfo success, width: %{public}d, height: %{public}d, rowStride: %{public}d, pixelFormat: %{public}d, alphaType: %{public}d.", width, height, rowStride, pixelFormat, alphaType); OH_PixelmapNative_Release(resPixMap); return destination; }void bgra2rgba(unsigned char *buffer, int width, int height) { unsigned int *rgba = (unsigned int *)buffer; for (int i = 0; i < width * height; i++) { rgba[i] = (rgba[i] & 0xFF000000) | // ______AA ((rgba[i] & 0x00FF0000) >> 16) | // RR______ (rgba[i] & 0x0000FF00) | // __GG____ ((rgba[i] & 0x000000FF) << 16); // ____BB__ } }
  • [开发技术领域专区] 开发者技术支持-TextPicker基础控件适配时间段区间选择
    1.1 问题说明在实际应用开发中,用户对于精确时间段的选择(如预约会议、预订服务、设置日程等场景)是非常常见的需求,例如需要明确选定 “2025-6-30 12:00-15:00” 这样的时间区间。然而,鸿蒙原生的 TextPicker 组件无此功能。然而在日常使用中应对此类需求时,由于其仅支持单点时间选择的特性,会暴露出一系列明显的痛点,具体可从以下几个方面展开:(一) 功能层面的天然缺失:TextPicker 组件的核心设计逻辑是针对单一时间点的选择,其本身不具备直接支持 “开始时间 - 结束时间” 区间选择的功能模块。这意味着它无法原生实现两个时间点之间的关联校验与联动选择,用户若想完成时间段的设定,必须依赖额外的逻辑设计。例如,无法在组件层面直接限制 “结束时间不得早于开始时间”,也不能在选择开始时间后自动为结束时间提供合理的初始范围建议,导致时间段选择的核心功能需要完全依赖开发者自行搭建。(二) 开发过程的低效与繁琐:为了实现时间段选择,开发者不得不手动组合多个 TextPicker 组件(通常至少需要两个,分别对应开始时间和结束时间)。这不仅需要额外处理组件的布局与样式协调,以保证视觉上的统一性,还需编写大量逻辑代码来实现两个时间点的关联:Ø 比如在用户选择开始时间后,需要动态限制结束时间的可选范围,避免出现逻辑矛盾;Ø 还需自行处理两个时间点的数据拼接与格式转换,最终形成 “开始时间 - 结束时间” 的完整字符串;Ø 同时,对于时间选择过程中的异常情况(如用户未选择结束时间就提交),也需要额外设计校验与提示机制。这些工作无疑增加了开发成本和出错概率,降低了开发效率。(三) 用户操作体验的不佳:从用户角度来看,使用多个 TextPicker 组件完成时间段选择需要进行多次独立操作:Ø 首先需点击开始时间选择器,完成开始时间的选择并确认;Ø 然后再点击结束时间选择器,重复类似的选择流程;Ø 若选择过程中需要修改,又得分别重新操作两个组件。这种割裂的操作方式不仅增加了用户的操作步骤和时间成本,还容易因两次操作的连贯性不足导致误选(如结束时间早于开始时间),进而影响用户对应用的使用体验,甚至可能导致用户因操作繁琐而放弃使用相关功能。组件样式示例: 1.2 原因分析(一) 时间单点选择定位下的区间功能缺失TextPicker 组件的核心定位是单一维度的选择工具,其设计初衷是满足用户对单个时间点(如某一具体日期、时刻)的快速选择需求。这种定位决定了组件在功能规划上更侧重单点选择的便捷性,而非复杂区间选择的完整性。导致其天然缺乏应对时间段选择场景的 “基因”。(二) 开发逻辑的独立性TextPicker 组件的底层实现逻辑具有较强的独立性与封闭性。每个组件实例仅负责处理自身对应的时间维度数据(如年、月、日或时、分),若要实现开始时间与结束时间的联动(如结束时间随开始时间动态调整),必须通过外部代码强制建立关联,这无疑增加了开发的复杂度,也容易因逻辑冲突导致功能异常。(三) 多组件分散:用户体验多重阻碍使用多个 TextPicker 组件进行时间段选择时,分散的交互模式会打破用户对时间选择的连贯认知,完整选段动作被拆分为多个独立步骤,导致用户注意力需多次聚焦,易因界面跳转产生认知中断,出现忘记数值或混淆组件功能的情况;步骤繁琐不仅增加操作难度,还需用户自行核对时间逻辑关系,易引发误操作,且因缺乏统一交互流程引导,用户需自行摸索操作顺序,加重认知负担,最终影响操作效率和使用体验。 1.3 解决思路(一) 组件整合:打造一体化时间段选择工具针对鸿蒙原生 TextPicker 组件在时间段区间选择场景中的痛点(功能缺失、开发低效、体验不佳),核心思路是基于组件化思想对原生组件进行封装扩展,通过复用原生能力、状态管理与动态适配,实现高效、直观的时间段区间选择功能。具体包括:Ø 复用 TextPicker 组件基础能力,组合单日期选择功能为 “日期 + 时间段” 的二级联动结构,解决区间选择功能缺失问题;Ø 采用鸿蒙状态管理机制(@State、@Link)维护父子组件状态同步,减少手动处理状态的开发成本,提升开发效率;Ø 结合动态时间规则处理,根据当前时间智能调整可选时段(如移除过期时段、跨天切换),优化用户操作体验,避免无效选择。​(二) 交互增强:提升操作连贯性与便捷性​支持在同一组件内通过拖拽、滑动等手势快速调整时间区间,比如拖动开始时间端点或结束时间端点来改变整个时间段,让操作更直观连贯。同时,保存用户的历史选择习惯,当用户再次进行时间段选择时,自动显示常用的时间范围作为初始选项,缩短选择路径。还可通过动画过渡效果增强两个时间点选择的关联性,例如选择开始时间后,结束时间区域以轻微高亮或缩放动画提示用户继续操作,强化操作的连贯性认知。​1.4 解决方案(一) 日期处理工具:通过工具函数实现日期格式化与动态时间规则适配,确保可选时段的有效性:日期格式化(getShiJian 函数):根据传入的天数偏移量(addDay),动态生成未来日期的 “YYYY-MM-DD” 格式,支持多日期选择。示例代码: getShiJian(addDay: number) { // 假设已经获取到时间戳并转换为Date对象 const date = new Date(Date.now() + (86400000 * addDay)); const year = date.getFullYear(); // 月份从0开始,需要加1并补0 const month = ("0" + (date.getMonth() + 1)).slice(-2); const day = ("0" + date.getDate()).slice(-2); // 日期补0 const formattedTime = `${year}-${month}-${day}` return formattedTime } timeRules(shiJian: Children[]) { const date: Date = new Date() const hours = date.getHours() if (hours >= 9 && hours < 12) { return } else if (hours >= 9 && hours < 11) { this.cascade[0].children?.splice(0, 1) } else if (hours >= 11 && hours < 16) { this.cascade[0].children?.splice(0, 2) } else if (hours >= 16 && hours < 22) { this.cascade[0].children?.splice(0, 3) } else if (hours < 8) { return } else if (hours >= 22) { this.cascade.splice(0, 1) this.cascade.push({ text: `${getShiJian(7)}`, children: shiJian }) } }动态时间规则(timeRules 函数):基于当前小时数(date.getHours ())智能调整可选时段。示例代码: if (hours >= 9 && hours < 12) { return } else if (hours >= 9 && hours < 11) { this.cascade[0].children?.splice(0, 1) } else if (hours >= 11 && hours < 16) { this.cascade[0].children?.splice(0, 2) } else if (hours >= 16 && hours < 22) { this.cascade[0].children?.splice(0, 3) } else if (hours < 8) { return } else if (hours >= 22) { this.cascade.splice(0, 1) this.cascade.push({ text: `${getShiJian(7)}`, children: shiJian }) }(二) 时间区间选择组件(TimeComponent):封装二级联动选择器,实现 “日期 + 时间段” 一体化选择:双级联动结构:通过TextPicker的range绑定cascade数组(包含日期及对应时段),实现联动选择。示例代码:@Component export struct TimeComponent { @Link selectTime: string; @Link cascade: TextCascadePickerRangeContent[] @Link isXuanZeShiJian: string @Link isXianShiShiJian: boolean shiJian: Children[] = [{ text: '08:00-09:00' }, { text: '09:00-11:00' }, { text: '11:00-16:00' }, { text: '16:00-22:00' }, ] aboutToAppear(): void { this.timeRules(this.shiJian) } build() { Scroll() { Column() { TextPicker({ range: this.cascade }) .onScrollStop((value: string | string[], index: number | number[]) => { console.info('TextPicker 多列联动:onScrollStop ' + JSON.stringify(value) + ', ' + 'index: ' + JSON.stringify(index)) this.selectTime = `${value[0]} ${value[1]}` }) .canLoop(false) .width('100%') .height(150) .margin({ bottom: 50 }) Row({ space: 20 }) { Button('取消') .width(120) .height(40) .buttonStyle(ButtonStyleMode.NORMAL) .onClick(() => { this.isXianShiShiJian = false }) Button('确定') .width(120) .height(40) .buttonStyle(ButtonStyleMode.EMPHASIZED) .onClick(() => { this.isXianShiShiJian = false if (this.selectTime) { this.isXuanZeShiJian = this.selectTime } else { this.isXuanZeShiJian = `${this.cascade[0].text} ${this.cascade[0]?.children![0].text}` } }) } .width('100%') .justifyContent(FlexAlign.Center) } .width('100%') .height('100%') .backgroundColor('#FFFFFF') .alignItems(HorizontalAlign.Center) .justifyContent(FlexAlign.Center) .translate({ y: -20 }) } .width('100%') .height('100%') } timeRules(shiJian: Children[]) { const date: Date = new Date() const hours = date.getHours() if (hours >= 9 && hours < 12) { return } else if (hours >= 9 && hours < 11) { this.cascade[0].children?.splice(0, 1) } else if (hours >= 11 && hours < 16) { this.cascade[0].children?.splice(0, 2) } else if (hours >= 16 && hours < 22) { this.cascade[0].children?.splice(0, 3) } else if (hours < 8) { return } else if (hours >= 22) { this.cascade.splice(0, 1) this.cascade.push({ text: `${getShiJian(7)}`, children: shiJian }) } } } interface Children { text: string; }状态管理:通过 @Link 装饰器同步父组件状态(如 cascade、selectTime),确保选择结果实时反馈。交互优化:默认取首个日期的首个时段(this.selectTime = cascade[0].text + cascade[0].children[0].text),避免空状态;通过 “取消”“确定” 按钮控制组件显隐(绑定 isShowTime 状态)。(三) 关键交互流程:用户操作流程:点击时间输入框→组件弹出→选择日期(联动加载对应时段)→选择时段→点击 “确定”→结果同步至父组件,单次操作完成区间选择。1.5   方案成果总结(一) 组件层面,通过组件一体化设计消除多组件切换的割裂感,减少用户手动校验成本,经测试,时间段选择效率提升约 40%;(二) 流程层面,清晰引导与快捷选项简化操作步骤,使操作步骤从原来的 3 - 4 步减少至 2 - 3 步,实时校验让选择错误率降低 65% 以上,显著降低用户认知负担;(三) 交互层面,手势操作与历史记忆功能缩短选择路径,平均选择耗时减少 30%,动画效果强化操作连贯性,用户操作满意度提升 50%,全面提升用户操作的直观性与便捷性,最终实现时间段选择体验的优化升级。
  • [技术干货] 开发者技术支持-自定义表情键盘删除事件
    1. 关键技术难点总结目前鸿蒙官方系统自带api:sendKeyEvent、deleteText无法直接删除自定义表情如下方所示4~9。1.1 问题说明  司内小伙伴在自定义键盘时发现4~9无法直接删除,需要点击多次才可,同时如维护整个输入事件成本太高。同时ai 查找解决方案存在兼容问题。系统自带的复合表情需要删除多次。1.2 原因分析  此处表情4~9不是常用表情,或者有可能是后续出现的表情,系统未做匹配。  查看现有ai 实现过于负杂,仅判断部分场景。1.3 解决思路  确认表情规则,例如表情长度、字符集编码构成等。  为了实现更好的兼容性,除问题表情符,其余调用系统api实现。  在实现过程中需要考虑用户可能切换光标位置,需要注意。  选择删除也需要兼容,例如用户选择多个表情符或文字。1.4 解决方案增加判断方法:isBadEmoji(s: string): boolean { return /[0-9]\u20E3\uFE0F/u.test(s);}监听输入框选择事件:.onTextSelectionChange((start, end) => { this.selectStart = start this.selectEnd = end})删除事件:customDelete(){ // 获取光标位置 const caret = this.controller.getCaretOffset().index; // 判断是否需要检测表情,主要依赖于光标起始和结束位置,目前出问题表情长度均为 3 const checkEmoji = (this.selectStart - this.selectEnd == 3 || this.selectStart - this.selectEnd == 0) && this.inputValue.length >= 3; // 检测是否需要兼容处理 if (checkEmoji && this.isValidEmoji(this.inputValue.slice(caret - 3, caret))) { this.controller.deleteText({ start: caret - 3, end: caret }) } else { sendKeyEvent({ type: KeyType.Down, keyCode: 2055, keyText: '', keySource: KeySource.Keyboard, deviceId: 0, metaKey: 0, timestamp: 0, stopPropagation: () => { }, intentionCode: IntentionCode.INTENTION_DOWN }) }}1.5 方案成果总结 开发层面:尽可能调用系统api,降低维护成本,自定义方法仅处理不兼容部分,能更好的适配多场 景下的兼容性,旨在补齐系统缺失部分。用户体验层面:补齐用户交互过程中,操作不连贯的困惑。经验总结:不要被一开始的问题复杂度所欺骗,制定计划,拆解问题,一层层逐步分析,先实现功 能,后续优化补足不足之处。 目前测试下来没得问题。如有小伙伴发现问题,欢迎指正。万分感谢~
  • [知识分享] 开发者技术支持-RN下Sample工程无法打包
    1.问题说明:在 0.72.5-ohos-5.0-release 分支,docs\Samples\Sample\SampleProject\MainProject 下,执行 npm i 安装完各种库之后再执行 npm run dev:all ;进行打包发现打包失败,报错为:SampleProject@0.0.1 dev:allnpm run dev:basic && npm run dev:homepage && npm run dev:goods && npm run dev:details && npm run dev:test && npm run dev:sandboxSampleProject@0.0.1 dev:basicreact-native bundle-harmony --dev false --entry-file ./src/bundles/basic/basic.js --bundle-output ../../SampleApp/entry/src/main/resources/rawfile/bundle/basic/basic.harmony.bundle --config ./basic.config.jserror: unknown command 'bundle-harmony' 2.原因分析:分析问题发生的原因cli已经安装,且bundle-harmony.js也存在,那应该不是cli的问题那应该就是bundle-harmony的问题3.解决思路:问题解决的思考过程打开package.json查找bundle-harmony用到了哪些库,发现最新的 mefs和比这里需要的用新很多 4.解决方案:描述实施的核心解决方案在主项目的package.json加入 :  "memfs": "4.17.2",
  • [技术干货] App Linking助力应用场景创新,操作步骤立省 60%
    在竞争激烈的应用市场中,开发者们都在努力寻找让应用脱颖而出的方法。华为AppGallery Connect(简称AGC)向开发者推出App Linking技术服务提供“应用链接”和“元服务链接”,可用于实现跳转HarmonyOS应用或者跳转元服务的功能。还能够与碰一碰、扫码等一方特性无缝结合,为应用构建独特的创新场景,有效提升应用的竞争力和用户体验。案例一:华为视频碰一碰,让跨设备视频分享一步到位​华为视频基于 App Linking 与碰一碰结合,只需两台手机轻触,视频瞬间直达对方应用播放界面,跳过传统社交分享的繁琐流程。无需手动搜索好友、上传等待或复制链接,精彩内容一碰即传,社交分享体验全面升级。 案例二:多乐中国象棋碰一碰,实现组队效率跃升 60%​多乐中国象棋引入 App Linking 与碰一碰的组合,为玩家带来了秒速组队的全新体验。以往玩家组队需要经过添加好友、发出邀请、等待回应等一系列繁琐操作,而现在轻轻碰触两台手机,即可实现秒速组队,操作步骤立省 60%。案例三:美团一扫即达,操作效率提升30%以上​美团App接入App Linking,无需用户打开App,通过系统扫码直接解锁共享单车、租借充电宝。负一屏、控制中心、系统相机均可解锁,操作入口增加3倍。一步扫码直达,操作效率提升30%以上。 App Linking 与一方特性的结合,为开发者打造创新应用场景提供了有力支持,无论是内容分享、游戏互动还是服务直达,都能带来显著的效果。它不仅能帮助开发者提升应用的竞争力,还能为用户带来更便捷、高效的使用体验。​点击下方链接,即刻开启鸿蒙生态场景化运营新篇章——点击链接即可体验:App Linking (上述数据来源于合作伙伴实践反馈,具体效果以实际场景为准)AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一 站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。 如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • [技术干货] 元服务调测无需上架,App Linking助力高效分发元服务链接
           元服务已经开发完却无法进行效果测试,上架后又担心影响现网用户体验。为解决开发者在元服务调测场景中的核心痛点,App Linking 全新升级实用功能 —— 支持未上架元服务进行全阶段调测,无需等待上架且不影响现网,让链接运营更高效、用户体验更流畅!核心功能:1. 开发者配置App Linking元服务链接后,在开发、邀请测试等阶段均可使用元服务链接进行功能调测;2. 针对二维码测试链接,若元服务链接关联了二维码,可以单独创建测试链接进行端到端真机调测,确认无误后再正式发布到现网,避免对存量的二维码产生影响,可以有效提升元服务质量!具体操作步骤如下:1、创建元服务链接时可正常在AGC控制台进行配置,若不关联二维码,可直接使用元服务链接进行测试。2、若选择关联二维码,可创建测试链接进行调试,链接需符合匹配规则,多个测试链接使用英文分号分隔。3、点击“保存”后,元服务链接为“草稿态”,您可以查看、编辑或者删除链接信息。开发者可扫描由测试链接生成的二维码进行端到端调测。4、调测确认无误后可点击“发布”,AGC会判断当前时间是否在链接有效期内,并实时更新元服务链接状态:“待生效”、“已生效”或“已失效”。        App Linking元服务链接和融合码是华为AppGallery Connect(简称AGC)向鸿蒙开发者提供的链接跳转元服务能力,可用于通过点击链接或扫描存量二维码实现跳转元服务指定页面的功能,实现元服务的点击触达、即点即用,为鸿蒙用户带来便捷的体验。        对于开发者而言,App Linking 不只是简单的链接工具,更是提升用户使用体验的核心利器。它打通 “用户触达” 与 “服务落地”,让应用与用户连接更高效。点击下方链接,即刻开启鸿蒙生态场景化运营新篇章 ——App Linking 。        AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一 站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。        如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • [技术干货] 鸿蒙APMS:开箱即用,崩溃卡顿耗电秒级捕捉
    在移动应用生态中,用户体验直接决定产品成败。面对崩溃、卡顿、耗电等现网性能问题,华为AppGallery Connect(简称AGC)向开发者提供了一个现网质量监测解决方案—应用性能监测服务(Application Performance Management Service,简称APMS)——开箱即用,崩溃卡顿耗电秒级捕捉,守护应用全生命周期,为开发者打造免集成、全覆盖、实时化的质量监测方案。​​核心优势:四大优势助力性能监测​​l  ​​免集成,开箱即用​​APMS以鸿蒙系统服务形式运行,​​无需应用内嵌SDK或初始化组件​​,开通即可启用,大幅降低接入成本。l  ​​全生命周期覆盖​​APMS的异常信息采集动作不受应用初始化、组件加载影响,全面覆盖应用启动、运行、前/后台、异常终止各阶段、状态的异常。l  ​​实时上报与精准统计​​通过系统级服务独立执行数据上传,​​秒级捕捉崩溃、ANR(应用无响应)、帧率异常等问题​​,并提供环境上下文、完整堆栈轨迹及多维度分析报表。异常信息上传动作由系统服务执行,与应用运行状态无关,不依赖应用重新启动,实时上报。l  ​​多维分析灵活查询​​可提供每个问题发生时的环境信息、堆栈信息等分析数据,并支持基于堆栈关键行进行准确的同类异常汇聚,支持问题标记、指标告警等辅助能力,帮助开发者高效聚焦和解决高频问题。​​案例展示: 助力游戏应用崩溃率从0.48%优化至0.35%(降幅27%)​​ 某游戏应用接入APMS服务后,依托其开箱即用的便捷性、全程守护及快速响应的高效性,关键指标实现显著改善:应用崩溃率从0.48%优化至0.35%(降幅27%),7日内触发崩溃的独立用户数环比下降52%。APMS提供的实时监测数据与异常根因分析报告,助力开发团队高效闭环问题,持续夯实用户体验基线。点击链接即可体验:APMS业务。(上述数据来源于合作伙伴实践反馈,具体效果以实际场景为准)AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一 站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。  如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • [技术干货] 「软件包管理 + 上架自检」双管齐下,提升上架审核通过率
    还在为应用上架反复碰壁而头疼?别担心,HUAWEI AppGallery Connect 云测试推出的“软件包管理--上架自检”能力,通过前置合规校验、模拟真实环境测试并出具详细的测试报告。平台配置多种型号鸿蒙真机,覆盖主流/热门机型,满足多样化测试场景需求。每天提供300分钟的免费使用时间,足够支撑新手尝鲜、轻量级项目测试或多次验证,​​0成本起步测试,立省真机购买投入!一、解锁新技能:这个 “应用管家” 不一般​全新上线的“软件包管理”能力,从应用提交伊始即提供全流程辅助,像一个贴心的私人“应用管家”。开发者上传软件包后,系统将​​自动进行基础合法性检测​​,校验其是否符合鸿蒙生态基本规范。支持开发者按需选择“仅测试”或“测试及正式上架”场景,满足不同阶段的验证需求。上传后即刻获取软件包合规状态(“已达标” “待优化”或“不通过”),清晰呈现应用与上架基础要求的差距。更为核心的是“上架自检”功能:严格参照华为应用市场准入标准,在热门的移动终端设备上,对应用的​​兼容性、稳定性、性能、功耗及用户体验(UX)​​ 进行全面自动化检测,让开发者在上架前及时发现并修复问题。每次检测均生成详尽报告,明确罗列问题点并提供优化建议,大幅减少反复修改的成本和时间。​二、操作指南:三步高效管理软件包​​​​1.登录配置:​​ 登录 ​​AppGallery Connect​​,点击“APP”,选择要发布的应用。​​导航入口:​​ 在左侧导航栏选择 ​​“应用上架 > 软件包管理”​​。​​2.上传与确认:​​ 点击右上角“上传”,选择应用使用场景(“仅测试”或“测试和正式上架”),添加软件包文件。  ​​3.结果解读:​​上传成功后,页面生成软件包记录。您可在“合法性”栏查看合法性检测结果。l  ​​已达标:​​ 符合鸿蒙生态规范,可提交上架。点击“报告”可查看详细的检测报告。l  ​​待优化:​​ 可尝试提交上架,但存在驳回风险。建议点击“报告”查看并修复问题。l  ​​不通过:​​ 不满足上架基本要求,不允许上架,需根据报告建议修改后重新上传。  三、进阶技巧:上架自检,为应用质量加码强烈建议开发者充分利用​​“上架自检”​​功能,为应用质量增加一层保障。1.在软件包记录的“操作”列点击“启动自检”。​​请注意:​​ 每个应用同时仅允许一个自检任务运行;即使删除相关软件包,启动自检仍会计入服务使用配额。2.启动后在“上架自检”栏可查看状态及结果:l  ​​检测中:表示正在检测软件包,检测时长可能受终端设备数量和排队情况影响。l  通过:​​ 可安心提交上架申请。l  ​​待优化:​​ 虽可提交,但驳回风险较高,强烈建议按报告指引进行优化。  HUAWEI AppGallery Connect 云测试提供​​海量鸿蒙真机​​在线免预约,可全面检测应用兼容性、性能、稳定性、功耗及UX等关键指标,​​首次试用赠300分钟​​!轻量测试0成本起步,极简操作,高效输出报告。成本低、易上手,​​点此立即试用 >>​ AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。  如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • [互动交流] 鸿蒙版如何安装vsix插件?
    看到其他的端有插件的入口,鸿蒙版还没有,请问后续有没有开放计划?
  • [互动交流] 【问题咨询:如何在鸿蒙系统的笔记本上安装python包】鸿蒙操作系统笔记本 使用 code art ide 时,安装python包时报错,无法自动识别pip,使用python -m pip install --user 安装时报错
    鸿蒙操作系统笔记本 使用 code art ide 时,安装python包时报错,无法自动识别pip,使用python -m pip install --user 安装时报错.1.在hishell 无法识别python  2.在code art ide 的终端可以识别python 但无法识别pip 3.使用  python -m pip install --user numpy 报错   
  • [技术干货] 【HarmonyOS Next之旅】DevEco Studio使用指南(三十五) -> 配置构建(二)-转载
    1 -> 定制HAP多目标构建产物每一个Entry/Feature模块均支持定制不同的target,通过在模块中的build-profile.json5文件中实现差异化定制,当前支持HAP包名、设备类型(deviceType)、源码集(source)、资源(resource)、buildOption配置项(如C++依赖的.so、混淆配置、abi类型、cppFlags等)、分发规则(distributionFilter)的定制。定义目标产物target每一个target对应一个定制的HAP,因此,在定制HAP多目标构建产物前,应提前规划好需要定制的target名称。例如,以ArkTS Stage模型为例,定义一个免费版和付费版,模块级build-profile.json5文件示例如下:{   "apiType": 'stageMode',   "buildOption": {     },   "targets": [  //定义不同的target     {       "name": "default",  //默认target名称default     },     {       "name": "free",  //免费版target名称     },     {       "name": "pay",  //付费版target名称     }   ] }AI写代码按照上述target的定义,在编译构建时,会同时打包生成default、free和pay三个不同的HAP。1.1 -> 定义产物的HAP包名每一个target均可以指定产物命名。{   "apiType": "stageMode",   "buildOption": {   },   "targets": [     {       "name": "default",       "output": {         "artifactName": "customizedTargetOutputName-1.0.0"  //产物名称为customizedTargetOutputName-1.0.0      }     },     {       "name": "free",       "output": {         "artifactName": "customizedTargetOutputName1-1.0.0"  //产物名称为customizedTargetOutputName1-1.0.0      }     },     {       "name": "pay",       "output": {         "artifactName": "customizedTargetOutputName2-1.0.0"  //产物名称为customizedTargetOutputName2-1.0.0      }     }   ] }AI写代码如果已配置签名,target产物对应的HAP包名为开发者定制的名称;如果未配置签名,target产物对应的HAP包名为开发者定制的名称+unsigned。1.2 -> 定义产物的deviceType每一个target均可以指定支持的设备类型deviceType,也可以不定义。如果不定义,则该target默认支持config.json或module.json5中定义的设备类型。同时,在定义每个target的deviceType时,支持的设备类型必须在config.json或module.json5中已经定义。例如,在上述定义的3个target中,分别定义default默认支持所有设备类型,free和pay版本只支持phone设备。{   "apiType": 'stageMode',   "buildOption": {   },   "targets": [     {       "name": "default",  //未定义deviceType,默认支持config.json或module.json5中定义的设备类型       },     {       "name": "free",       "config": {         "deviceType": [  //定义free支持的设备类型为phone           "phone"         ]       }     },     {       "name": "pay",       "config": {         "deviceType": [  //定义pay支持的设备类型为phone           "phone"         ]       }     }   ] }AI写代码1.3 -> 定义产物的distributionFilter在未定义target的分发规则distributionFilter时,以module配置distroFilter/distributionFilter分发规则为准。针对多target存在相同设备类型deviceType的场景,相同设备类型的target需要指定分发规则distributionFilter。如果是FA工程,请将distributionFilter字段替换为distroFilter。{   "apiType": "stageMode",   "buildOption": {   },   "targets": [     {       "name": "default",       },     {       "name": "free",       "config": {         "distributionFilter": {  // 具体请参考distributionFilter标签          "screenShape": { // 屏幕形状枚举             "policy": "include",             "value": ["circle"]           }         }       }     },     {       "name": "pay",       "config": {         "distributionFilter": {           "screenShape": {             "policy": "include",             "value": ["rect"]           }         }       }     }   ] }AI写代码1.4 -> 定义产物preloads的分包对于元服务,每一个target均可以指定preloads的分包,也可以不定义。如果不定义,则以module.json5中的配置为准。{   "apiType": 'stageMode',   "showInServiceCenter": true,   "buildOption": {   },   "targets": [       {       "name": "default",       },    {       "name": "free",       },    {       "name": "pay",         "config": {         "atomicService": {           "preloads": [  //指定preloads的分包             {               "moduleName": "preloadSharedLibrary"            }           ]         }       }     }   ] }AI写代码1.5 -> 定义产物的source源码集-pages对于source源码集的定制,由于Stage模型和FA模型的差异,Stage模型支持对pages源码目录的page页面进行定制,FA模型则支持对Ability源码目录下的page页面进行定制。例如,Stage模型中的工程,在模块的pages目录下分别定义了Index.ets、Page1.ets和Page2.ets三个页面。其中default使用了Index.ets页面;free使用了Index.ets和Page1.ets页面;pay使用了Index.ets和Page2.ets页面,则示例代码如下所示:{    "apiType": 'stageMode',    "buildOption": {    },    "targets": [      {        "name": "default",        "source": {  //定义Stage模型中默认版target的pages源码文件         "pages": [            "pages/Index"          ]        }      },      {        "name": "free",        "config": {          "deviceType": [            "phone"          ]        },        "source": {  //定义Stage模型中免费版target的pages源码文件         "pages": [            "pages/Index",            "pages/Page1"          ]        }      },      {        "name": "pay",        "config": {          "deviceType": [            "phone"          ]        },        "source": {  //定义Stage模型中付费版target的pages源码文件         "pages": [            "pages/Index",            "pages/Page2"          ]        }      }    ]  }AI写代码例如,FA模型中的工程,在模块的MainAbility中定义了index.ets、page1.ets和page2.ets,其中:default使用了index.ets 页面;free使用了index.ets和page1.ets页面;pay使用了index.ets和page2.ets页面。{    "apiType": 'faMode',    "buildOption": {    },    "targets": [      {        "name": "default",        "source": {  //定义FA模型中默认版target的pages源码文件         "abilities": [            {              "name": ".MainAbility",              "pages": [                "pages/index"              ]            }          ],        }      },      {        "name": "free",        "config": {          "deviceType": [            "phone"          ]        },        "source": {  //定义FA模型中免费版target的pages源码文件         "abilities": [            {              "name": ".MainAbility",              "pages": [                "pages/index",                "pages/page1"              ]            }          ],        }      },      {        "name": "pay",        "config": {          "deviceType": [            "phone"          ]        },        "source": {  //定义FA模型中付费版target的pages源码文件         "abilities": [            {              "name": ".MainAbility",              "pages": [                "pages/index",                "pages/page2"              ]            }          ],        }      }    ]  }AI写代码1.6 -> 定义产物的source源码集-sourceRoots在模块的主代码空间(src/main)下,承载着开发者编写的公共代码。如果开发者需要实现不同target之间的差异化逻辑,可以使用差异化代码空间(sourceRoots)。配合差异化代码空间的能力,可以在主代码空间中代码不变的情况下,针对不同的target,编译对应的代码到最终产物中。概念说明packageName:当前模块的oh-package.json5中的name字段对应的值。sourceRoot:<defaultSourceRoot> | <targetSourceRoot> ,其中<defaultSourceRoot>是 src/main,<targetSourceRoot>可自定义,寻址优先级为 <targetSourceRoot> > <defaultSourceRoot>。sourcePath:在sourceRoot中的代码结构目录。sourceFileName:代码目录下的ets文件名。例如以下工程目录:entry|--src|----main|------ets|--------code|----------test.ets|----target|------util|--------util.ets|--index.etspackageName为entry。sourceRoot为src/main、src/target。sourcePath为ets/code、util。sourceFileName为test.ets、util.ets。规格限制1. import xxx from '<packageName>/sourcePath/sourceFileName' :通过packageName的方式,省略sourceRoot,可以实现不同target下的差异化构建。2. 支持hap、hsp、har(请注意:开启文件/文件夹名称混淆的har模块需要使用-keep-file-name指定sourceRoot,sourcePath,sourceFileName对应的文件/文件夹名称不被混淆)。3. 不支持跨模块引用。4. 不支持动态import。编译时模块target的选择优先级说明在模块编译的过程中,该模块使用的sourceRoots由当前模块编译时的target来决定。当前模块编译时选择target的优先级则为:命令行显式指定 > 直接引用方target > default。如以下示例:hap -> hsp -> har(->表示依赖)其中hap和hsp存在三个target:default、custom、static,而har存在两个target:default、static。执行编译命令:hvigorw -p module=hap@custom assembleHap,hap指定target为custom进行编译,那么三个模块编译时的target分别为:hap: custom,命令行显式指定;hsp: custom,命令行没有显式指定,则基于直接引用方查找,hsp的直接引用方为hap,hap的target为custom,hsp存在该target,则hsp的target为custom;har: default,命令行没有显式指定,则基于直接引用方查找,har的直接引用方为hsp,hsp的target为custom,har不存在该target,则har的target为default;执行编译命令:hvigorw -p module=hap@custom,hsp@static assembleHap assembleHsp,hap指定target为custom,hsp则指定target为static进行编译,那么三个模块编译时的target分别为:hap: custom,命令行显式指定;hsp: static,命令行显式指定;har: static,命令行没有显式指定,则基于直接引用方查找,har的直接引用方为hsp,hsp的target为static,har存在该target,则har的target为static。在当前依赖关系的基础上,添加依赖:hap -> har。执行编译命令:hvigorw -p module=hap@custom,hsp@static assembleHap assembleHsp。由于har没有显示指定target,且存在两个target不同的直接引用方(hap和hsp,对应的target分别为custom和static),所以编译过程中har的target只能二选一。基于这种场景,建议开发者显示指定模块的target进行编译:hvigorw -p module=hap@custom,hsp@static,har@static assembleHap assembleHsp assembleHar。示例1. 在entry模块的build-profile.json5中添加sourceRoots:{  "apiType": "stageMode",  "buildOption": {},  "targets": [     {       "name": "default",       "source": {         "sourceRoots": ["./src/default"] // 配置target为default的差异化代码空间      }     },     {       "name": "custom",       "source": {         "sourceRoots": ["./src/custom"] // 配置target为custom的差异化代码空间      }     }   ]}AI写代码2. 在src目录下新增default/Test.ets和custom/Test.ets,新增后的模块目录结构:entry  |--src    |--main      |--ets        |--pages          |--Index.ets    |--default      |--Test.ets  // 新增    |--custom      |--Test.est  // 新增  3. 在default/Test.ets中写入代码:export const getName = () => "default"AI写代码4. 在custom/Test.ets中写入代码:export const getName = () => "custom"AI写代码5. 修改src/main/ets/pages/Index.ets的代码:import { getName } from 'entry/Test'; // 其中entry为模块级的oh-package.json5中的name字段的值@Entry@Componentstruct Index {   @State message: string = getName();   build() {     RelativeContainer() {       Text(this.message)     }     .height('100%')     .width('100%')   }}AI写代码6. 在工程级的build-profile.json5中配置targets:{  "app": {    "signingConfigs": [],    "products": [      {        "name": "default",        "signingConfig": "default",        "compatibleSdkVersion": "5.0.2(14)",        "runtimeOS": "HarmonyOS",      },      {        "name": "custom",        "signingConfig": "default",        "compatibleSdkVersion": "5.0.2(14)",        "runtimeOS": "HarmonyOS",      }    ],    "buildModeSet": [      {        "name": "debug",      },      {        "name": "release"      }    ]  },  "modules": [    {      "name": "entry",      "srcPath": "./entry",      "targets": [        {          "name": "default",          "applyToProducts": [            "default"          ]        },        {          "name": "custom",          "applyToProducts": [            "default"          ]        }      ]    }  ]}AI写代码7. Sync完成后,选择entry的target为default,点击Run,界面展示default;选择entry的target为custom,点击Run,则界面展示custom。1.7 -> 定义产物的资源每个target使用的资源文件可能存在差异,在开发过程中,开发者可以将每个target所使用的资源存放在不同的资源目录下。其中,ArkTS工程支持对main目录下的资源文件目录(resource)进行定制;JS工程支持对main目录下的资源文件目录(resource)及 Ability下的资源文件目录(res)进行定制。如下为ArkTS工程的资源文件目录定制示例:{   "apiType": 'stageMode',   "buildOption": {   },   "targets": [     {       "name": "default",       "source": {         "pages": [           "pages/Index"         ]       },       "resource": {  //定义默认版target使用的资源文件目录         "directories": [           "./src/main/resources_default"         ]       }     },     {       "name": "free",       "config": {         "deviceType": [           "phone"         ]       },       "source": {           "pages": [           "pages/Index",           "pages/Page1"         ]       },       "resource": {  //定义免费版target使用的资源文件目录         "directories": [           "./src/main/resources_default",           "./src/main/resources_free"         ]       }     },     {       "name": "pay",       "config": {         "deviceType": [           "phone"         ]       },       "source": {           "pages": [           "pages/Index",           "pages/Page2"         ]       },       "resource": {  //定义付费版target使用的资源文件目录,该功能在API 9及以上版本的工程中生效         "directories": [           "./src/main/resources_default",           "./src/main/resources_pay"         ]       }     }   ] }AI写代码请注意,如果target引用的多个资源文件目录下,存在同名的资源,则在构建打包过程中,将按照配置的资源文件目录顺序进行选择。例如,上述付费版target引用的资源中,resource_default和resource_pay中存在同名的资源文件,则resource_default中的资源会被打包到HAP中。1.8 -> 定义产物的icon、label、launchType针对每一个的target的ability,均可以定制不同的icon、label和launchType。如果不定义,则该target采用module.json5中module.abilities配置的icon、label,launchType默认为"singleton"。示例如下所示:{    "apiType": 'stageMode',    "buildOption": {    },    "targets": [      {        "name": "default",        "source": {        "abilities": [          {            "name": "EntryAbility",            "icon":"$media:layered_image",            "label":"$string:EntryAbility_label",            "launchType": "singleton"          }        ]      }     },      {        "name": "free",        "source": {        "abilities": [          {            "name": "EntryAbility",            "icon":"$media:layered_image",            "label":"$string:EntryAbility_label",            "launchType": "multiton"          }        ]      }     }   ]  }AI写代码1.9 -> 定义C++工程依赖的.so文件在 C++ 工程中,可以对每个target依赖的.so文件进行定制。例如某模块依赖了function1.so、function2.so和function3.so三个文件,其中target为default的产物依赖了function1.so和function2.so;其中target为vip的产物依赖了function1.so和 function3.so,则示例代码如下所示:{  "apiType": 'stageMode',  "buildOption": {    "externalNativeOptions": {      "path": "./src/main/cpp/CMakeLists.txt",      "arguments": [],      "abiFilters": [        "arm64-v8a",        "x86_64"      ],      "cppFlags": "",    }  },  "targets": [  //定义不同的target     {      "name": "default",      "config": {        "buildOption": {          "nativeLib": {            "filter": {              //按照.so文件的优先级顺序,打包最高优先级的function1.so文件               "pickFirsts": [                "**/function1.so"              ],              //排除不打包的function3.so文件               "excludes": [                "**/function3.so"              ],              //允许当.so中资源重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件               "enableOverride": true            }          }        }      }    },    {      "name": "vip",      "config": {        "buildOption": {          "nativeLib": {            "filter": {              //按照.so文件的优先级顺序,打包最高优先级的function1.so文件               "pickFirsts": [                "**/function1.so"              ],              //排除不打包的function2.so文件               "excludes": [                "**/function2.so"              ],              //允许当.so中资源重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件               "enableOverride": true            }          }        }      }    }  ]}AI写代码2 -> 构建定义的目标产物每个target对应一个HAP,每个product对应一个APP包,在编译构建时,如果存在多product或多target时,您可以指定编译具体的包。单击右上角的 图标,指定需要打包的Product及Target,然后单击Apply保存。例如选择"ProductA"中,entry模块对应的"free" Target。Product:选择需要构建的 APP 包。Build Mode:选择编译模式。Product Info:该APP包的BundleName和SigningConfig信息。Target Select:选择各个模块的Target,该Target需要包含在定义的Product中才能选择,如果未包含则显示"No Target to apply"。然后执行编译构建APP/HAP的任务:单击菜单栏的Build > Build Hap(s)/APP(s) > Build APP(s) ,构建指定的Product对应的APP。例如,按照上述设置,此时DevEco Studio将构建生成 ProductA 的 APP 包。default和ProductB的APP均不会生成。单击菜单栏的Build > Build Hap(s)/APP(s) > Build Hap(s),构建指定Product下的所有Target对应发的HAP。例如,按照上述配置,此时DevEco Studio将构建生成entry模块下default和free的HAP。如果您想将某个模块下的指定target打包生成HAP,可以在工程目录中,单击模块名,然后再单击Build > Make Module ‘模块名 ’,此时DevEco Studio将构建生成模块下指定target对应的包。例如,按照上述配置,此时DevEco Studio将构建生成entry模块下free的HAP,不会生成default的HAP。————————————————                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                        原文链接:https://blog.csdn.net/weixin_74809706/article/details/148765945
  • “秒开”时代,HarmonyOS预加载让页面加载快如闪电
    在用户体验为王的时代,应用“秒开”已成为用户对移动应用的核心期待。HarmonyOS预加载服务将应用页面的数据提前加载到本地缓存,页面打开直接从本地获取数据渲染,有效提升页面打开速度,解决应用页面加载慢、白屏的困境。一、安装预加载:助力“凯叔讲故事”页面加载提速37.9%​安装预加载服务适用于安装后首次打开,应用首页加载提速场景。在应用安装时,将一些必要的资源,例如图片、音频、视频或数据文件,提前加载到本地进行缓存。当用户安装后首次打开应用时,直接调用本地缓存数据渲染页面,跳过网络请求环节。优质儿童内容品牌“凯叔讲故事”非常重视用户体验,接入安装预加载后,页面加载提速37.9%。  实际案例应用:凯叔讲故事 二、周期性预加载:动态场景即发即现​​周期性预加载服务适用于任意页面加载提速的场景,可与安装预加载结合使用。系统每隔12小时拉取一次指定页面(不局限首开页面)的云侧数据并将其缓存到本地,并可将静态资源放置到云端,减少包体大小。开发者可在节日活动开始前通过周期性预加载服务提前将主题资源获取到本地,用户访问时直接从本地获取即可,减少了网络请求的时间和带宽消耗,实现即发即现的效果,提升用户体验。三、FastWeb:移动端H5页面的“隐形加速器”FastWeb组件是一个高性能Web容器,针对App中H5页面可以提供预启动、预渲染、预编译、离线资源免拦截注入等能力。其可提前加载高频页面资源并优化渲染流程,有效解决传统H5页面的白屏、卡顿问题。某省政务服务App接入FastWeb后,页面打开速度提升超32.9%。  (上述数据来源于合作伙伴实践反馈,具体效果以实际场景为准)AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。         如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • 节约测试成本50%,崩溃率直降72%,云测云调助力质效双提升
    产品质量不仅是企业的生命线,更是用户体验的第一道门。 HUAWEI AppGallery Connect “云测+云调”双引擎,助力开发者轻松跨越从代码到产品的最后一公里! 一、云测试:真机云端护航,高效测试省成本移动应用生命周期中的测试环节,常面临成本高企、效率低下、技术门槛高等挑战。HUAWEI AppGallery Connect 云测试提供一站式解决方案:海量热门主流真机,可全面检测应用兼容性、性能、稳定性、功耗及UX等关键指标。测试完成后快速输出详尽专业的测试报告,精准定位问题并提供修复建议,显著提升应用质量与发布效率,大幅降低测试成本与资源投入。二、云调试:彻底告别"设备荒",调试效率提升50%HUAWEI AppGallery Connect云调试为开发者提供海量移动终端设备支持,解决设备机型不足、设备管理困难及bug无法复现等问题,支持7x24小时远程调测,彻底告别"设备荒"。真实运行环境精准复现用户场景,断点、日志即时获取,调试效率提升50%。用云端弹性资源替代固定资产投入,实现开发效能与成本支出双优化,让调试瓶颈迎刃而解。三、双剑合璧,节约测试成本50%,崩溃率直降72%15日天气预报应用,应用版本更新快,新版本上线时间紧迫。通过云测试全面的测试报告,开发者快速发现了不同机型上出现的无响应、UI异常、崩溃等问题,节约测试成本50%。并通过云调试快速定位,崩溃率下降了72%。(上述数据来源于合作伙伴实践反馈,具体效果以实际场景为准)AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。  如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
总条数:209 到第
上滑加载中