Harmoney北向开发入门篇(三)

Stage应用模型

应用模型是HarmonyOS为开发者提供的应用程序所需能力的抽象提炼,它提供了应用程序必备的组件和运行机制。有了应用模型,开发者可以基于一套统一的模型进行应用开发,使应用开发更简单、高效。

HarmonyOS应用模型概况

随着系统的演进发展,HarmonyOS先后提供了两种应用模型:

  • FA(Feature Ability)模型:HarmonyOS早期版本开始支持的模型,已经不再主推。
  • Stage模型:HarmonyOS 3.1 Developer Preview版本开始新增的模型,是目前主推且会长期演进的模型
    在该模型中,由于提供了AbilityStage、WindowStage等类作为应用组件和Window窗口的"舞台",因此称这种应用模型为Stage模型。

developer.huawei.com/consumer/cn...

Stage模型基本概念

Ability Module 与 Library Module

我们新建的项目内部,默认包含一个entry子模块,entry模块内部包含有源代码、资源、配置文件等等。

entry模块这种包含应用内特殊能力的,我们称之为为Ability Module,即有特殊能力的模块。

在DevEco Studio中新建Module时,也内置了一些Module:比如网格、列表、登录、开屏页等

除了有特殊能力的Module之外;在多个Module之间,它们存在使用公共类、函数等资源的情况,那么就需要另外一种类型的Module来存放公共使用的资源、函数等,所以具有这种公共能力的模块,称之为library Module。

编译期

  • 每个ability Module都支持单独编译,并且在编译时,会被编译成HAP(Harmony Ability Package)文件。
  • 而library Module会被编译成HSP(Harmony Shared Package)文件,即共享包。
  • 每个HAP包在运行过程中都可以引用和依赖多个HSP包。
  • 一个应用中往往会由多个Module构成,所以会有多个HAP文件;而一个应用只能指定一个HAP文件作为程序的入口,所以作为入口的HAP就是应用主模块,我们称为Entry类型的HAP;其他则是Feature类型的HAP。
  • HAP有很多文件,最终还是要合并到一起组成APP的,所以多个HAP合并在一起后我们称之为bundle,bundle有自己的名字属性 name,这个name会作为bundle的唯一标识,最终生成一个APP安装包。
  • 在我们的应用开发调试时,我们可以只编译一个Enrty类型HAP作为主入口,如果要调试其他Feature类型的HAP,那么则单独添加该HAP进行编译调试,这样调试效率也会更高。

运行期

  • 每个HAP都可以独立运行,为了展示页面,所以它们会各自创建一个名为 AbilityStage 的类实例,即"应用组件的舞台"。
    • 每个Entry类型或者Feature类型的HAP在运行期都有一个AbilityStage类实例,当HAP中的代码首次被加载到进程中的时候,系统会先创建AbilityStage实例。
  • Stage模型提供UIAbility和ExtensionAbility两种类型的组件。
  • UIAbility:包含UI界面的应用组件,是系统调度的基本单元。
  • ExtensionAbility:比如应用卡片、输入法实现,都是基于ExtensionAbility实现。
  • 我们常规应用页面最终都是通过UIAbility组件来展示的,但并不是直接通过UIAbility来展示的。
    • UIAbility持有一个WindowStage实例,即组件内窗口的"舞台"。
    • 每个UIAbility类实例都会与一个WindowStage类实例绑定。
  • 而WindowStage持有Window对象"窗口"。
  • 而Windows则是用来绘制UI界面的窗口,搭载ArkUI-Page。

总结

  • 项目中大致分为两种类型Module,分别是 Ability Module 和 Library Module。
  • 在编译期,每个Ability Module都会各自生成一个HAP,每个 Library Module 都会各自生成一个HSP。
    • HAP在运行时可以引用和依赖多个HSP。
    • 一个应用程序中,只存在一个主入口HAP,称为Entry类型的HAP,其他称为Feature类型的HAP。
  • 在运行期,每个HAP都会各自创建一个 AbilityStage 实例;
    • Stage模型提供了UIAbility和ExtensionAbility两种类型;
    • Stage模型在对跨端的UI兼容更加优秀。
  • 正是因为提供了AbilityStage、WindowStage等类作为应用组件和Window窗口的"舞台",所以这个应用模型称为Stage模型。
  • 通过 Stage舞台 的机制,使得Ability 和 Window窗口 分隔开了,实现了两者的解耦;所以在将来开发跨设备的软件时,就可以针对不同设备来对窗口做单独的裁剪等设置,更好的实现跨端适配。

UIAbility概述

UIAbility组件是一种包含UI界面的应用组件,主要用于和用户交互。

UIAbility组件是系统调度的基本单元,为应用提供绘制界面的窗口;一个UIAbility组件中可以通过多个页面来实现一个功能模块。每一个UIAbility组件实例,都对应于一个最近任务列表中的任务。

UIAbility的声明配置

为使应用能够正常使用UIAbility,需要在module.json5配置文件abilities标签中声明UIAbility的名称、入口、标签等相关信息。

kotlin 复制代码
{
  "module": {
    // ...
    "abilities": [
      {
        "name": "EntryAbility", // UIAbility组件的名称
        "srcEntry": "./ets/entryability/EntryAbility.ts", // UIAbility组件的代码路径
        "description": "$string:EntryAbility_desc", // UIAbility组件的描述信息
        "icon": "$media:icon", // UIAbility组件的图标
        "label": "$string:EntryAbility_label", // UIAbility组件的标签
        "startWindowIcon": "$media:icon", // UIAbility组件启动页面图标资源文件的索引
        "startWindowBackground": "$color:start_window_background", // UIAbility组件启动页面背景颜色资源文件的索引
        // ...
      }
    ]
  }
}

UIAbility组件生命周期

当用户打开、切换和返回到对应应用时,应用中的UIAbility实例会在其生命周期的不同状态之间转换。UIAbility类提供了一系列回调,通过这些回调可以知道当前UIAbility实例的某个状态发生改变,会经过UIAbility实例的创建和销毁,或者UIAbility实例发生了前后台的状态切换。

UIAbility的生命周期包括Create、Foreground、Background、Destroy四个状态,如下图所示。

OnCreate

Create状态为在应用加载过程中,UIAbility实例创建完成时触发,系统会调用onCreate()回调。以在该回调中进行页面初始化操作,例如变量定义资源加载等,用于后续的UI界面展示。

scala 复制代码
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  onCreate(want, launchParam) {
    // 页面初始化
  }
  // ...
}

WindowStageCreate 和 WindowStageDestroy

UIAbility实例创建完成之后,在进入Foreground之前,系统会创建一个WindowStage。

WindowStage创建完成后会进入onWindowStageCreate()回调,我们可以在该回调中设置UI界面加载、设置WindowStage的事件订阅。

UI界面加载 与 WindowStage事件订阅

我们可以在onWindowStageCreate()回调中通过loadContent()方法设置应用要加载的页面并根据需要订阅WindowStage的事件(获焦/失焦、可见/不可见)。

javascript 复制代码
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';

export default class EntryAbility extends UIAbility {
    onWindowStageCreate(windowStage: Window.WindowStage) {
        // 设置WindowStage的事件订阅(获焦/失焦、可见/不可见)
        windowStage.on(
          'windowStageEvent',//监听事件,固定为'windowStageEvent',即WindowStage生命周期变化事件。
          (windowStageEvent)//回调函数。返回当前的WindowStage生命周期状态。
            =>{
          switch (windowStageEvent) {
            case window.WindowStageEventType.SHOWN:
              //切换到前台
            break
            case window.WindowStageEventType.ACTIVE:
              //获取到焦点
            break
            case window.WindowStageEventType.INACTIVE:
              //失去焦点
              break
            case window.WindowStageEventType.HIDDEN:
              //切到后台
              break
          }
        })
      
        // 设置UI界面加载,这里加载的是'pages/Index'文件、
        windowStage.loadContent('pages/Index', (err, data) => {
            // ...
        });
    }
}

对应于onWindowStageCreate()回调。在UIAbility实例销毁之前,则会先进入onWindowStageDestroy()回调,可以在该回调中释放UI界面资源。例如在onWindowStageDestroy()中注销获焦/失焦等WindowStage事件。

scala 复制代码
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';

export default class EntryAbility extends UIAbility {
  // ...

  onWindowStageDestroy() {
    // 释放UI界面资源
  }
}

Foreground与Background状态

  • Foreground和Background状态分别在UIAbility实例切换至前台和切换至后台时触发,对应于onForeground()回调和onBackground()回调。
  • onForeground()回调,在UIAbility的UI界面可见之前,如UIAbility切换至前台时触发。可以在onForeground()回调中申请系统需要的资源,或者重新申请在onBackground()中释放的资源。
  • onBackground()回调,在UIAbility的UI界面完全不可见之后,如UIAbility切换至后台时候触发。可以在onBackground()回调中释放UI界面不可见时无用的资源,或者在此回调中执行较为耗时的操作,例如状态保存等。
  • 例如应用在使用过程中需要使用用户定位时,假设应用已获得用户的定位权限授权。在UI界面显示之前,可以在onForeground()回调中开启定位功能,从而获取到当前的位置信息。
  • 当应用切换到后台状态,可以在onBackground()回调中停止定位功能,以节省系统的资源消耗。
scala 复制代码
import UIAbility from '@ohos.app.ability.UIAbility';

export default class EntryAbility extends UIAbility {
    onForeground() {
        // 申请系统需要的资源,或者重新申请在onBackground中释放的资源
    }

    onBackground() {
        // 释放UI界面不可见时无用的资源,或者在此回调中执行较为耗时的操作
        // 例如状态保存等
    }
}

Destroy

Destroy状态在UIAbility实例销毁时触发。可以在onDestroy()回调中进行系统资源的释放、数据的保存等操作。

例如调用terminateSelf()方法停止当前UIAbility实例,从而完成UIAbility实例的销毁;或者用户使用最近任务列表关闭该UIAbility实例,完成UIAbility的销毁。

scala 复制代码
import UIAbility from '@ohos.app.ability.UIAbility';
import Window from '@ohos.window';

export default class EntryAbility extends UIAbility {
    onDestroy() {
        // 系统资源的释放、数据的保存等
    }
}

应用周期流程

  1. UIAbility实例创建完成后,会调用onCreate。
  2. onCreate之后,UIAbility需要先去创建WindowStage才能得到WIndow来展示UI;
  3. 当WindowStage完成实例创建后会调用onWindowStageCreate。
  4. WindowsStage创建完成后,接下来UIAbility会被移到前台,即 onForeground。
  5. 之后由WindowStage控制Window实例的可见性,使页面可见,即Visible。
  6. 接着是走Active,表示页面得到焦点。
  7. 之后如果将应用关闭,WindowStage会先将页面失去焦点,走InActive。
  8. 接着使页面不可见,即 InVisible;
  9. UIAbility将自身至于后台,调用onBackground;
  10. UIAbility先销毁WindowStage实例,触发onWindowStageDestroy。
  11. 最后Ability销毁自己,走onDestroy。

hilog

我们在刚刚看的Ability中,发现鸿蒙的log日志使用不是常见的console.log,而是使用的hilog。

hilog是鸿蒙提供的日志打印工具,他支持不同类型的log:error、info、debug等等。

它的第一个参数是数字,表示一个域,我们可以通过这个域的值来筛选日志。

第二个参数是字符串,它是TAG,也是标记,和第一个参数有些类似。

第三个参数是日志输出内容:%s 是一个占位符,表示输出一个占位符,在后面的参数值进行补充,这个和c很像。

而%s中间的 {public} 用来修饰当前占位符对应的参数是否要公开;private则是不公开,当正式环境下,输出的日志中对应参数会不公开。

在我们debug环境中,{private}无效,日志参数始终会显示。54

页面与组件生命周期

页面与其子组件的销毁关系

下图中,我们定义了一个@Enrty入口页面组件PageA 和 普通组件ComponentA。

我们在PageA的build函数中创建了ComponentA;那么ComponentA组件会先被创建实例,之后是执行Build函数,最终被渲染到页面中。

  • 当我们页面执行跳转其他页面时,有两种方式,一种是pushUrl(),此时当前页面不会出栈,所以 ComponentA 不一定会被销毁。
  • 如果使用replaceUrl(),那么当前页面会被目标页面替换,当前页面会出栈,所以自然页面内部的组件就被销毁了。
  • 同时,我们还创建了 @State show变量,用来控制ComponentA的创建和移除。当show为true时,ComponentA被创建;反之,ComponentA实例会被销毁回收;所以,即使页面没有被销毁,但其内部的组件仍有可能被销毁。

综上所述:页面中子组件是否销毁 并不完全取决于 页面是否销毁。当页面销毁时,其内部子组件必然被销毁;当页面未被销毁时,也有可能因为代码对视图控制而导致子组件被销毁。

组件提供的钩子函数

同时,组件还提供了几个钩子函数。

  • aboutToAppear:在组件实例被创建后,调用Build函数之前,会先执行当前aboutToAppear函数,我们可以在此进行一些数据的初始化。
  • onPageShow:页面组件函数,表示页面被展示。
  • onBackPress:页面组件函数,表示当前页按下了返回键。
  • onPageHide:页面组件函数,表示当前页面被隐藏。
  • aboutToDisappear:在组件销毁之前(onPageHide之后),会执行此aboutToDisappear函数,我们可以在此时对数据进行保存,做持久化操作。

注意: 页面生命周期函数只能在作为 @Entry 入口组件的组件内才会有效; 所以普通组件的数据预处理尽可能放在aboutToAppear中执行。

页面组件跳转时的生命周期流程

  • 页面组件A跳转页面组件B时:
    1. 首先组件B先被创建,触发组件B的aboutToAppear函数。
    2. 第二步隐藏组件A,执行了组件A的onPageHide函数。
    3. 第三步组件B显示出来,执行了组件B的onPageShow函数。
    4. 第四步,组件B内部的组件被创建,触发aboutToAppear函数后,执行Build函数。

FOREACH函数对组件生命周期的影响 (API 9 以上没有这个问题)

在FOREACH函数中,如果通过FOREACH函数来生成多个组件;那么当@State 数组元素被修改删除后,会重新触发FOREACH函数执行;而之前通过FOREACH生成的所有组件都会被回收销毁,从而执行aboutToAppear;接着重新执行FOREACH生成新的组件,并执行aboutToAppear函数。

所以,对FOREACH所遍历数组 (做了数据绑定的情况下) 的其中任一条数据做删除/替换/新增操作时,会导致FOREACH函数内的其他所有组件被重新创建。

解决方法

那么如何控制FOREACH函数对其他组件影响呢?

这时就提到了FOREACH函数的第三个参数,该参会要返回组件ID作为唯一标识。通过这个唯一标识,FOREACH就能够在数据变化时,判断出哪些组件唯一标识不变,从而不触发重走生命周期。

scss 复制代码
FOREACH(
  arr:Array,//要遍历的数据数组
  (item:any,index?:number)=>{
    //页面组件生成的函数回调
    Row(){
      Image(item.image)
      Column(){
        Text(item.name)
        Text(item.price)
      }
    }
  },
  keyGenerator?:(item:any,index?:number):string => {
    //定义每个item项的ID,必须唯一,用于列表内部的渲染判断
  }
)

ArkTS声明式UI更新机制优化

ArkTS声明式UI在API 9上优化了相关UI更新机制,当自定义组件的某个状态变量发生变化导致自定义组件重新渲染时,仅执行该自定义组件build函数中的部分UI描述(使用了该状态变量的内置UI组件的UI描述)来实现更高性能的UI更新。而API8及以前在状态变量发生变化时会执行build函数中的全量UI描述来实现UI更新。

developer.huawei.com/consumer/cn...

UIAbility的启动模式

UIAbility的启动模式是指UIAbility实例在启动时的不同呈现状态。针对不同的业务场景,系统提供了三种启动模式:

1. singleton(单实例模式)

  • 系统中只存在唯一一个该UIAbility实例,即在最近任务列表中只存在一个该类型的UIAbility实例。
    是默认启动模式。
    每次调用startAbility()方法时,如果应用进程中该类型的UIAbility实例已经存在,则复用系统中的UIAbility实例。

应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用startAbility()方法启动该UIAbility实例,此时只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。

使用:如果需要使用singleton启动模式,在module.json5配置文件中的"launchType"字段配置为"singleton"即可。

json 复制代码
{
  "module": {
    // ...
    "abilities": [
      {
        "launchType": "singleton",
        // ...
      }
    ]
  }
}

2. multiton(多实例模式)

  • multiton启动模式为多实例模式,每次调用startAbility()方法时,都会在应用进程中创建一个新的该类型UIAbility实例。即在最近任务列表中可以看到有多个该类型的UIAbility实例。
    使用:multion也是将在module.json5配置文件中的"launchType"字段配置为"multion"即可。

3. specified(指定实例模式)

  • specified启动模式为指定实例模式,在目标UIAbility实例创建之前,即我们调用startAbility跳转目标UIAbility之前,我们在want参数中添加一个自定义参数字符串Key作为唯一标识,之后在被调起方的UIAbility启动之前,会先进入其对应的AbilityStage的onAcceptWant()生命周期回调中,我们解析传入的want参数,获取对应的参数。并根据业务需要在onAcceptWant()中返回自定义的唯一Key。
  • 如果我们返回的Key对应了一个已启动的UIAbility,系统则会将之前的UIAbility拉回前台并获焦,而不创建新的实例,否则创建新的实例并启动。

注意:

应用的UIAbility实例已创建,该UIAbility配置为指定实例模式,再次调用startAbility()方法启动该UIAbility实例,且AbilityStageonAcceptWant()回调匹配到一个已创建的UIAbility实例。此时,再次启动该UIAbility时,只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。

使用方法:

例如有两个UIAbility:EntryAbility和FuncAbility,FuncAbility配置为specified启动模式,需要从EntryAbility的页面中启动FuncAbility。

  1. 在FuncAbility中,将module.json5配置文件的"launchType"字段配置为"specified"。
  2. 在EntryAbility中,调用startAbility()方法时,在want参数中,增加一个自定义参数来区别UIAbility实例,例如增加一个"instanceKey"自定义参数。
    注:如果在page页面中,那么要通过 let context= (getContext(this) as common.UIAbilityContext) 来获取UIAbility的context。
javascript 复制代码
function getInstance() {
  // ...
}

//构建要跳转的目标Ability相关信息
let want = {
  deviceId: '', // deviceId为空表示本设备
  bundleName: 'com.example.myapplication',
  abilityName: 'FuncAbility',//目标Ability的name,在module.json5->abilities->name中。
  moduleName: 'module1', // moduleName非必选
  parameters: { // 自定义信息
    instanceKey: getInstance(),
  },
}
// 如果在page页面中,那么要通过 let context= (getContext(this) as common.UIAbilityContext),来获取context。
// context为调用方UIAbility的AbilityContext
this.context.startAbility(want).then(() => {
  // ...
}).catch((err) => {
  // ...
})
  1. 在被调用端对应的AbilityStoge中,解析传入的want参数,获取"instanceKey"自定义参数;并在其onAcceptWant()生命周期回调返回一个字符串Key标识。之后的跳转逻辑则不需要我们处理。(别忘了在配置文件中声明当前的AbilityStage
scala 复制代码
import AbilityStage from '@ohos.app.ability.AbilityStage';

export default class MyAbilityStage extends AbilityStage {
    onAcceptWant(want): string {
        // 在被调用方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值
        // 当前示例指的是module1 Module的FuncAbility
        if (want.abilityName === 'FuncAbility') {
            // 返回的字符串Key标识为自定义拼接的字符串内容
            return `ControlModule_EntryAbilityInstance_${want.parameters.instanceKey}`;
        }

        return '';
    }
}

注意:

在我们配置启动模式时,ide联想出了四个启动模式,而官方文档只有三个启动模式。

此时,不要纠结,就当它是给FA应用模型使用的。

AbilityStage组件容器

在指定UIAbility的启动模式时,我们学习了 specified(指定实例模式) ,在使用 specified 启动模式时,我们需要在 AbilityStage 的onAcceptWant()函数中返回Key值。

AbilityStage是一个Module级别的组件容器,应用的HAP在首次加载时会创建一个AbilityStage实例,可以对该Module进行初始化等操作。

AbilityStage与Module一一对应,即一个Module拥有一个AbilityStage。

DevEco Studio默认工程中未自动生成AbilityStage,如需要使用AbilityStage的能力,可以手动新建一个AbilityStage文件,步骤如下:

  1. 在工程Module对应的ets目录下,右键选择"New > Directory",新建一个目录并命名为myabilitystage。
  2. 在myabilitystage目录,右键选择"New > TypeScript File",新建一个TypeScript文件并命名为MyAbilityStage.ts。
  3. 创建一个类,并继承自AbilityStage,重写onCreate、onAcceptWant。
scala 复制代码
import AbilityStage from '@ohos.app.ability.AbilityStage';
import Want from '@ohos.app.ability.Want';

export default class MyAbilityStage extends AbilityStage {

  onCreate(){
    // 应用的HAP在首次加载的时,为该Module初始化操作
  }

  onAcceptWant(want:Want):string{
    // 仅specified模式下触发
    return "0"
  }
}

export ****default :表示默认导出当前类。

  1. 配置自定义的AbilityStage;在module.json5配置文件中,通过配置srcEntry参数来指定模块对应的代码路径,以作为HAP加载的入口。
json 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "srcEntry": "./ets/myabilitystage/MyAbilityStage.ts",
    ...
  }
}

AbilityStage生命周期

AbilityStage拥有onCreate()生命周期回调和onAcceptWant()、onConfigurationUpdated()、onMemoryLevel()事件回调。

  • onCreate()生命周期回调:在开始加载对应Module的第一个UIAbility实例之前会先创建AbilityStage,并在AbilityStage创建完成之后执行其onCreate()生命周期回调。
    AbilityStage模块提供在Module加载的时候,通知开发者,可以在此进行该Module的初始化(如资源预加载,线程创建等)能力。
  • onAcceptWant()事件回调:UIAbility指定实例模式(specified)启动时候触发的事件回调。
  • onConfigurationUpdated()事件回调:当系统全局配置发生变更时触发的事件,系统语言、深浅色等,配置项目前均定义在Configuration类中。
  • onMemoryLevel()事件回调:当系统调整内存时触发的事件。
    应用被切换到后台时,系统会将在后台的应用保留在缓存中。即使应用处于缓存中,也会影响系统整体性能。当系统资源不足时,系统会通过多种方式从应用中回收内存,必要时会完全停止应用,从而释放内存用于执行关键任务。为了进一步保持系统内存的平衡,避免系统停止用户的应用进程,可以在AbilityStage中的onMemoryLevel()生命周期回调中订阅系统内存的变化情况,释放不必要的资源。

如何考鸿蒙线上能力认证以及如何在官网学习

  1. 开发文档目录:developer.huawei.com/consumer/cn...
    在这里,你可以查看Harmony OS应用开发相关的相关能力使用。
  2. 搜索文档资料:developer.huawei.com/consumer/cn...
    在这里,我们可以全局的搜索一些功能解决方案和接口文档。
  3. Openharmoney三方库地址:ohpm.openharmony.cn/#/cn/home
    在这里,可以找到我们应用所能使用的三方库框架。
  4. 关于应用上架
    上架教程:developer.huawei.com/consumer/cn...
    上架AGC地址:developer.huawei.com/consumer/cn...
  5. 考证位置:
    建议先过基础认证,再去学习高级认证。
    HarmonyOS应用开发者认证是线上考试;还有一种是线下的,需要费用:200~300USD。
    我们应该是考线上认证就行了,在这基础 认证考试的链接里,是有提供配套的学习课程。
    高级认证则没有提供,需要我们自己去查找,根据考试大纲来学习相对应知识。
    每个等级考试,每个账户,每个月有三次考试机会。
    注意 :线上认证考试,考完之后他只有分数,不会给你看错题,也不会告诉你哪题错了。
    HarmonyOS应用开发者基础 认证:developer.huawei.com/consumer/cn...
    HarmonyOS应用开发者高级 认证:developer.huawei.com/consumer/cn...
相关推荐
dawn5 小时前
鸿蒙ArkTS中的获取网络数据
华为·harmonyos
桃花键神5 小时前
鸿蒙5.0时代:原生鸿蒙应用市场引领开发者服务新篇章
华为·harmonyos
鸿蒙自习室5 小时前
鸿蒙多线程开发——并发模型对比(Actor与内存共享)
华为·harmonyos
JavaPub-rodert6 小时前
鸿蒙生态崛起:开发者的机遇与挑战
华为·harmonyos
帅比九日8 小时前
【HarmonyOS Next】封装一个网络请求模块
前端·harmonyos
yilylong10 小时前
鸿蒙(Harmony)实现滑块验证码
华为·harmonyos·鸿蒙
baby_hua10 小时前
HarmonyOS第一课——DevEco Studio的使用
华为·harmonyos
HarmonyOS_SDK10 小时前
融合虚拟与现实,AR Engine为用户提供沉浸式交互体验
harmonyos
- 羊羊不超越 -11 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
长弓三石13 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙