鸿蒙原生APP性能优化之应用冷启动优化

往期推文全新看点

概述

应用启动时延是影响用户体验的关键要素,是指从用户点击桌面应用图标、通知或其他入口启动应用,到应用界面内容成功加载并显示在屏幕上的时间间隔。如果这段时间耗时比较长,肯定会影响用户的体验。

应用启动可以分为冷启动和热启动,当应用启动时,后台没有该应用的进程,这时系统会重新创建应用的进程, 这种启动方式就叫做冷启动;而热启动是当应用程序已经在后台运行,用户再次打开应用程序时,应用程序仍然在内存中,可以直接从内存中加载并继续之前的状态,而不需要重新初始化和加载资源。

当应用冷启动时延大于1100ms时,可以认为是应用启动缓慢。

本文将介绍以下内容,来帮助开发者提升应用的冷启动速度,避免卡顿感:

  • 应用冷启动流程
  • 识别启动缓慢问题
  • 提升应用冷启动速度

应用冷启动流程

在优化应用冷启动体验前,需要先了解应用冷启动的流程和几个重要的生命周期。应用冷启动的过程大致可分成以下5个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页,如下图所示。

  1. 应用进程创建&初始化阶段:该阶段主要是系统完成应用进程的创建以及初始化的过程,包含了启动页图标(startWindowIcon)的解码。
  2. Application&Ability初始化:该阶段主要是资源加载、虚拟机创建、Application&Ability相关对象的创建与初始化、依赖模块的加载等。
  3. Ability/AbilityStage生命周期:该阶段主要是AbilityStage/Ability的启动生命周期,执行相应的生命周期回调。
  4. 加载绘制首页:该阶段主要是加载首页内容、测量布局、刷新组件并绘制。
  5. 网络数据二次刷新:该阶段主要是应用根据业务需要对网络数据进行请求、处理、二次刷新。

可见如果想要提升应用冷启动速度,需要缩短以上几个阶段的耗时。

识别启动缓慢问题

如果开发者需要分析启动过程的耗时瓶颈,优化应用或服务的冷启动速度,可使用Profiler提供的Launch场景分析能力,录制启动过程中的关键数据进行分析,从而识别出导致启动缓慢的原因所在。Profiler Launch可以拆解应用冷启动过程,抓取不同阶段的耗时数据,帮助开发者快速分析冷启动过程的耗时瓶颈。

从上图可以看到Launch将应用的冷启动过程拆解为以下几个阶段:

  1. Create Process:应用进程创建阶段,对应的trace打点为AbilityManagerService::StartAbilityMissionListManager::StartAbilityLocked##{bundleName}
  2. Application Launching:应用启动阶段,对应的trace打点为AppMgrServiceInner::AttachApplication##{bundleName}
  3. UI Ability Launching:UIAbility启动阶段,对应的trace打点为MainThread::HandleLaunchAbility##{bundleName}
  4. UI Ability OnForeground:应用进入前台阶段,对应的trace打点为AbilityThread::HandleAbilityTransaction
  5. First Frame - App Phase:App首帧渲染提交阶段,对应的trace打点为H:ReceiveVsync,H:MarshRSTransactionData
  6. First Frame - Render Phase:RS首帧渲染提交阶段,对应的trace打点为H:ReceiveVsync,H:RSMainThread::ProcessCommandUn
  7. EntryAbility:应用启动之后的阶段,渲染完成,首页显示

从Create Process阶段开始到First Frame - Render Phase阶段,这段时间可以看作是应用的冷启动时间,在Launch泳道到上,使用鼠标左键拖动这两个阶段的区间,可以看到应用冷启动时间为215.2ms,这个启动速度是比较快的。

冷启动缓慢示例分析

运行如下示例代码,我们可以明显的感知应用启动比较缓慢。接下来我们通过这个示例,结合Launch来分析应用冷启动缓慢问题。

const LARGE_NUMBER = 200000000;
const DELAYED_TIME = 1000;

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  aboutToAppear(): void {
    console.log('aboutToAppear');
    this.computeTask();
  }

  computeTask(): void {
    let count = 0;
    while (count < LARGE_NUMBER) {
      count++;
    }
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

首先是创建Launch分析录制,可以看到整个的启动时间比较长,其中UI Ability OnForeground这个阶段占据应用冷启动过程的大部分时间,耗时达到了4.1s,所以我们需要重点分析这个阶段的耗时。

针对应用冷启动问题的性能分析,有以下两种方式可以选择,一种是分析主线程的Trace数据,另一种则是分析采样得到的函数热点。

分析主线程的Trace数据

  1. 单击“Launch”泳道上的UI Ability OnForeground阶段,在下方的“Details”详情面板中,可查看到所选阶段的耗时统计情况;
  2. 展开UI Ability OnForeground统计信息折叠表,可以看到各函数的具体耗时信息;
  3. 根据Duration找到耗时最长的函数aboutToAppear;
  4. 单击图标按钮,可直接跳转至主线程的打点任务中,查看相关Trace数据,如下图所示。

可以看到在UI Ability OnForeground阶段的耗时基本是由aboutToAppear造成的,我们再看aboutToAppear中的代码逻辑,可以推断是由于计算任务computeTask耗时造成的。

分析采样得到的函数热点

我们也可以分析采样得到的函数热点直观的显示应用冷启动过程中具体函数的耗时,如下图:

  1. 单击“Launch”泳道上的UI Ability OnForeground阶段;
  2. 选择“ArkTS Callstack”泳道,其会基于时间轴展示CPU使用率和状态的变化,以及当前调用栈名称和调用类型;
  3. 下方“Details”详情面板中查看到这段时间内的函数热点,其会以Top-Down形式的树状列表进行展示。很明显aboutToAppear函数中的;computeTask函数耗时最多,占整个阶段的96.7%,双击该函数可以跳转到源码。
  4. 此外,点击底部Flame Chart按钮打开火焰图可以更直观的看出热点函数的耗时情况,如下图所示。

冷启动速度优化

通过前面的分析,冷启动缓慢是由于在aboutToAppear执行了耗时计算任务,我们可以将该computeTask以异步延时的方式处理,优化后的代码如下:

const LARGE_NUMBER = 100000000;
const DELAYED_TIME = 1000;

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  aboutToAppear(): void {
    console.log('aboutToAppear');
    this.computeTaskAsync();
  }

  ...

  computeTask(): void {
    let count = 0;
    while (count < LARGE_NUMBER) {
      count++;
    }
  }

  // 运算任务异步处理
  private computeTaskAsync(): void {
    setTimeout(() => { // 这里使用setTimeout来实现异步延迟运行
      this.computeTask();
    }, DELAYED_TIME);
  }
}

然后重新编译运行程序以及录制Launch,可以看到优化后UI Ability OnForeground阶段耗时大幅度缩短,如下图所示:

查看首帧卡顿

为了识别首帧是否卡顿,可以先在Launch的Frame泳道进行查看。应用的首帧渲染提交在First Frame - App Phase阶段,APP侧下面的这一帧表示应用渲染的首帧,如下图所示,此处首帧为36号帧:

如上所示36号帧被标记为了红色,表示首帧出现了卡顿。鼠标左键36号帧,可以看到它的期望提交渲染时间为左边白色竖线区域所示,这里出现了比较严重的延时。发现问题后,开发者可以参考前面讲到的示例进行问题定位和优化。

提升应用冷启动速度

本文将通过公共类优化的方法,包括 非冷启动必须的服务或模块延迟加载 、 减少主线程非UI耗时操作 和 网络请求提前发送 ,以及结合应用启动的几个阶段分别介绍提升应用冷启动速度的相关方法。

非冷启动必须的服务或模块延迟加载

应用在启动前加载过多不必要启动项,同时这些启动项在主线程串行执行,该阶段耗时接近450ms。

应用冷启动过程中,加载自身不必要的串行启动项,会导致冷启动耗时增加。建议延后加载或者并行处理。

减少主线程非UI耗时操作

在应用启动流程中,主要聚焦在执行UI相关操作中,为了更快的显示首页内容,不建议在主线程中执行非UI相关的耗时操作,建议通过异步任务进行延迟处理或放到其他子线程中执行。

在冷启动过程中如果存在图片下载、网络请求前置数据、数据反序列化等非UI操作开发者可以根据实际情况移至子线程中进行。

<think>好的,我现在需要解决用户在鸿蒙开发中实现从小程序返回到原生App的功能,特别是涉及微信分享场景的问题。首先,我得理解用户的具体需求。用户希望当用户在微信小程序中完成某些操作后,能够返回到原生的鸿蒙应用。这可能涉及到微信分享功能后的回调处理,或者从小程序跳转回原生App的机制。 首先,我需要回顾鸿蒙开发的相关知识,尤其是与微信集成和导航相关的部分。根据提供的引用,引用[1]提到了HarmonyOS支持多设备协同和第三方应用接入,特别是微信分享功能。引用[2]和[3]讨论了鸿蒙的UI组件,比如Column、Row和Flex布局,这可能与界面跳转有关。引用[4]提到了底部导航栏的实现,但可能和当前问题关联不大。 接下来,我需要确定鸿蒙中如何处理应用间的跳转和回调。通常,在移动开发中,应用间的跳转可以通过URL Scheme或者Deep Link实现。在微信分享场景中,分享到小程序后,可能需要在小程序中设置返回原生App的链接,这需要配置正确的Scheme。 然后,考虑鸿蒙的具体实现。根据引用[1],接入微信分享需要注册微信开发者账号,配置应用信息,并集成微信SDK。这可能涉及到在分享时添加回调参数,以便微信在操作完成后能够触发返回原生App的逻辑。 另外,鸿蒙的Ability框架中,Page Ability用于UI页面,Service Ability用于后台服务。用户可能需要在小程序完成操作后,通过Intent启动指定的Ability。需要检查微信SDK是否支持回调URL,并在鸿蒙应用中注册相应的Scheme来处理这种跳转。 可能的步骤包括: 1. 在鸿蒙应用中注册自定义URL Scheme,以便微信小程序可以触发该Scheme。 2. 在微信分享配置中添加回调URL,指向该自定义Scheme。 3. 在鸿蒙应用中处理接收到的Intent,当用户从微信返回时,正确导航到指定页面。 同时,需要确保微信SDK在鸿蒙中的兼容性,以及正确处理应用前后台的状态。可能还需要处理参数传递,例如分享后的状态或数据需要带回原生应用。 最后,验证整个流程是否正确,包括分享到微信小程序、用户操作后是否能正确跳转回鸿蒙应用,并携带必要的数据。如果有错误,可能需要检查Scheme配置、权限设置或Intent过滤器的正确性。</think>在鸿蒙开发中实现从小程序返回原生App的功能,需要结合微信分享SDK与鸿蒙的页面路由机制。以下是分步骤实现方案: --- ### 一、实现原理 通过微信SDK的分享回调参数携带**鸿蒙应用的自定义Scheme**,在小程序端完成操作后触发Scheme跳转回原生应用鸿蒙通过`Want`和`Ability`机制捕获Scheme请求并处理路由[^1][^2]。 --- ### 二、具体实现步骤 #### 1. 注册微信开发者平台 - 在微信开放平台创建应用,获取`AppID` - 配置鸿蒙应用的**签名信息**和**包名**(需与`config.json`中的`bundleName`一致) #### 2. 配置鸿蒙应用Scheme 在`config.json`中添加Scheme声明: ```json "abilities": [{ "name": "EntryAbility", "srcEntrance": "./ets/entryability/EntryAbility.ts", "schemes": [{ "name": "harmonywechat", "roles": ["跳转动作类型"] }] }] ``` #### 3. 集成微信分享SDK 在分享参数中携带回调Scheme: ```typescript // 构建分享参数 let request = { scene: 0, // 0-会话 1-朋友圈 miniProgram: { webpageUrl: "原始网页URL", miniprogramType: 0, // 正式版 path: "/pages/index" }, extra: { // 携带回调Scheme参数 callbackScheme: "harmonywechat://com.example.app/return?action=share" } }; wx.shareAppMessage(request); ``` #### 4. 处理Scheme回调 在`EntryAbility`中重写`onCreate`方法: ```typescript onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { if (want?.uri) { const uri = decodeURIComponent(want.uri); if (uri.startsWith('harmonywechat://')) { // 解析参数示例 const params = new URLSearchParams(uri.split('?')[1]); if (params.get('action') === 'share') { // 执行返回原生页面的路由逻辑 postActionToUI({ action: 'RETURN_FROM_WECHAT', data: params.get('share_id') }); } } } } ``` #### 5. 跨页面通信 使用`EventHub`传递回调事件: ```typescript // 在目标页面注册监听 AppStorage.SetOrCreate('eventHub', new EventHub()); const eventHub = AppStorage.Get('eventHub'); eventHub.on('RETURN_FROM_WECHAT', (data) => { // 更新页面状态或执行导航 }); ``` --- ### 三、注意事项 1. **Scheme白名单**:需在微信开放平台配置允许的Scheme 2. **参数编码**:URL参数必须进行`encodeURIComponent`处理 3. **生命周期管理**:正确处理应用冷启动/热启动场景 4. **安全验证**:建议对回调参数增加签名验证 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值