鸿蒙OS开发实例:【窥探网络请求】

HarmonyOS 平台中使用网络请求,需要引入 "@ohos.net.http", 并且需要在 module.json5 文件中申请网络权限, 即 "ohos.permission.INTERNET"

本篇文章将尝试使用 @ohos.net.http 来实现网络请求

场景设定

  1. WeiBo UniDemo HuaWei : 请求顺序
  2. WeiBo1 UniDemo2 HuaWei3 : 异步/同步请求时,序号表示请求回来的顺序
  3. "开始网络请求-异步" : 开始异步请求
  4. "开始网络请求-同步" : 开始同步请求
  5. "开始网络请求-自定义方法装饰器" : 采用自定义方法装饰器进行传参,进而完成网络请求

官方网络请求案例

注意:

每次请求都必须新创建一个HTTP请求实例,即只要发起请求,必须调用createHttp方法

更多鸿蒙开发应用知识已更新qr23.cn/AKFP8k参考前往。

关于 @ohos.net.http 有三个request方法

  1. request(url: string, callback: AsyncCallback): void;

    1.1 如下"官方指南代码缩减版"使用到了这个方法

  2. request(url: string, options: HttpRequestOptions, callback: AsyncCallback): void;

    2.1 如下"官方指南代码" 使用了这个方法

  3. request(url: string, options?: HttpRequestOptions): Promise;

    3.1 将在后续实践代码中使用到

cpp 复制代码
// 引入包名
import http from '@ohos.net.http';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {
    console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
    // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
    "EXAMPLE_URL",
    {
        method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
        // 开发者根据自身业务需要添加header字段
        header: {
            'Content-Type': 'application/json'
        },
        // 当使用POST请求时此字段用于传递内容
        extraData: {
            "data": "data to send",
        },
        expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型
        usingCache: true, // 可选,默认为true
        priority: 1, // 可选,默认为1
        connectTimeout: 60000, // 可选,默认为60000ms
        readTimeout: 60000, // 可选,默认为60000ms
        usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
    }, (err, data) => {
        if (!err) {
            // data.result为HTTP响应内容,可根据业务需要进行解析
            console.info('Result:' + JSON.stringify(data.result));
            console.info('code:' + JSON.stringify(data.responseCode));
            // data.header为HTTP响应头,可根据业务需要进行解析
            console.info('header:' + JSON.stringify(data.header));
            console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
        } else {
            console.info('error:' + JSON.stringify(err));
            // 取消订阅HTTP响应头事件
            httpRequest.off('headersReceive');
            // 当该请求使用完毕时,调用destroy方法主动销毁
            httpRequest.destroy();
        }
    }
);
cpp 复制代码
// 引入包名
import http from '@ohos.net.http';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();

httpRequest.request(
    // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
    "EXAMPLE_URL",
    (err, data) => {
        if (!err) {
            // data.result为HTTP响应内容,可根据业务需要进行解析
            console.info('Result:' + JSON.stringify(data.result));
            console.info('code:' + JSON.stringify(data.responseCode));
            // data.header为HTTP响应头,可根据业务需要进行解析
            console.info('header:' + JSON.stringify(data.header));
            console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
        } else {
            console.info('error:' + JSON.stringify(err));
            // 取消订阅HTTP响应头事件
            httpRequest.off('headersReceive');
            // 当该请求使用完毕时,调用destroy方法主动销毁
            httpRequest.destroy();
        }
    }
);

场景布局

基础页面组件代码

考虑到实际的场景会用到网络请求加载,因此这里将发挥 [@BuilderParam] 装饰器作用,先定义基础页面

组件中定义了 @Prop netLoad:boolean 变量来控制是否展示加载动画

cpp 复制代码
@Component
export struct BasePage {
  @Prop netLoad: boolean

  //指向一个组件  
  @BuilderParam aB0: () => {}

  build(){
     Stack(){
       
       //为组件占位
       this.aB0()

       if (this.netLoad) {
         LoadingProgress()
           .width(px2vp(150))
           .height(px2vp(150))
           .color(Color.Blue)
       }

     }.hitTestBehavior(HitTestMode.None)
  }

}

主页面布局代码

cpp 复制代码
import { BasePage } from './BasePage'

@Entry
@Component
struct NetIndex {
  @State netLoad: number = 0
  @State msg: string = ''

  build() {
      Stack(){
        BasePage({netLoad: this.netLoad != 0}) {
          Column( {space: 20} ){

            Row({space: 20}){
              Text('WeiBo').fontColor(Color.Black)
              Text('UniDemo').fontColor(Color.Black)
              Text('HuaWei').fontColor(Color.Black)
            }

            Row({space: 20}){
              Text('WeiBo' + this.weiboIndex)
              Text('UniDemo' + this.uniIndex)
              Text('HuaWei' + this.huaweiIndex)
            }

            Button('开始网络请求 - 异步').fontSize(20).onClick( () => {
                ...
            })

            Button('开始网络请求 - 同步').fontSize(20).onClick( () => {
                ...
            })

            Button('开始网络请求-自定义方法装饰器').fontSize(20).onClick( () => {
              ...
            })

            Scroll() {
              Text(this.msg).width('100%')
            }
            .scrollable(ScrollDirection.Vertical)
          }
          .width('100%')
          .height('100%')
          .padding({top: px2vp(120)})
        }

      }
  }

}

简单装封装网络请求

函数传参,直接调用封装方法

WeiBo为数据结构体,暂时不用关心,后续会贴出完整代码,这里仅仅是演示网络请求用法

cpp 复制代码
//引用封装好的HNet网络工具类
import HNet from './util/HNet'

@State msg: string = ''
    
getWeiBoData(){
   HNet.get<WeiBo>({
  url: 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4188_-_ctg1_4188',
}).then( (r) => {

  this.msg = ''

  if(r.code == 0 && r.result){
    r.result.data.statuses.forEach((value: WeiBoItem) => {
      this.msg = this.msg.concat(value.created_at + ' ' + value.id + '\n')
    })
  } else {
    this.msg = r.code + ' ' + r.msg
  }
  console.log('顺序-weibo-' + (new Date().getTime() - starTime))

  this.netLoad--

})    
   
}

自定义方法装饰器,完成传参调用

网络请求样例

cpp 复制代码
NetController.getWeiBo<WeiBo>().then( r => {
   ......
})   

按照业务定义传参

cpp 复制代码
import { Get, NetResponse } from './util/HNet'

export default class BizNetController {

  @Get('https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4188_-_ctg1_4188')
  static getWeiBo<WeiBo>(): Promise<NetResponse<WeiBo>>{ return }

}

封装的网络请求代码

cpp 复制代码
import http from '@ohos.net.http';

//自定义网络请求参数对象    
class NetParams{
  url: string
  extraData?: JSON
}

//自定义数据公共结构体    
export class NetResponse<T> {
  result: T
  code: number
  msg: string
}

//网络封装工具类    
class HNet {

  //POST 请求方法  
  static post<T>(options: NetParams): Promise<NetResponse<T>>{
    return this.request(options, http.RequestMethod.POST)
  }

  //GET 请求方法  
  static get<T>(options: NetParams): Promise<NetResponse<T>>{
    return this.request(options, http.RequestMethod.GET)
  }

    
  private static request<T>(options: NetParams, method: http.RequestMethod): Promise<NetResponse<T>>{

    let r = http.createHttp()

    return r.request(options.url, {
      method: method,
      extraData: options.extraData != null ? JSON.stringify(options.extraData) : null
    }).then( (response: http.HttpResponse) => {

      let netResponse = new NetResponse<T>()

      let dataType = typeof response.result

      if(dataType === 'string'){
         console.log('结果为字符串类型')
      }

      if(response.responseCode == 200){
        netResponse.code = 0
        netResponse.msg = 'success'
        netResponse.result = JSON.parse(response.result as string)

      } else {
        //出错
        netResponse.code = -1
        netResponse.msg = 'error'

      }

      return netResponse

    }).catch( reject => {
      console.log('结果发生错误')

      let netResponse = new NetResponse<T>()
      netResponse.code = reject.code
      netResponse.msg  = reject.message
      return netResponse

    }).finally( () => {
       //网络请求完成后,需要进行销毁
       r.destroy()
    })

  }

}

export default HNet 
    
//用于装饰器传参
export function Get(targetUrl: string) : MethodDecorator {

  return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
        //替换方法
        descriptor.value = () => {
           let options = new NetParams()
           options.url = targetUrl
            return HNet.get(options)
        }
  }

}

完整代码

代码结构

net/BasePage.ets

net/NetRequest.ets

net/util/HNet.ts

net/viewmodel/WeiBoModel.ts

net/BizNetController.ets

详细代码

cpp 复制代码
@Component
export struct BasePage {
  @Prop netLoad: boolean

  @BuilderParam aB0: () => {}

  build(){
     Stack(){

       this.aB0()

       if (this.netLoad) {
         LoadingProgress()
           .width(px2vp(150))
           .height(px2vp(150))
           .color(Color.Blue)
       }

     }.hitTestBehavior(HitTestMode.None)
  }

}   
cpp 复制代码
import HNet from './util/HNet'
import NetController from './BizNetController'
import { WeiBo, WeiBoItem } from './viewmodel/WeiBoModel'
import { BasePage } from './BasePage'

@Entry
@Component
struct NetIndex {
  @State netLoad: number = 0
  @State msg: string = ''

  @State weiboColor: Color = Color.Black
  @State uniColor: Color = Color.Black
  @State huaweiColor: Color = Color.Black

  @State weiboIndex: number = 1
  @State uniIndex: number = 2
  @State huaweiIndex: number = 3

  private  TEST_Target_URL: string[] = [
    'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4188_-_ctg1_4188',
    'https://unidemo.dcloud.net.cn/api/news',
    'https://developer.huawei.com/config/cn/head.json',
  ]

  build() {
      Stack(){
        BasePage({netLoad: this.netLoad != 0}) {
          Column( {space: 20} ){

            Row({space: 20}){
              Text('WeiBo').fontColor(Color.Black)
              Text('UniDemo').fontColor(Color.Black)
              Text('HuaWei').fontColor(Color.Black)
            }

            Row({space: 20}){
              Text('WeiBo' + this.weiboIndex).fontColor(this.weiboColor)
              Text('UniDemo' + this.uniIndex).fontColor(this.uniColor)
              Text('HuaWei' + this.huaweiIndex).fontColor(this.huaweiColor)
            }

            Button('开始网络请求 - 异步').fontSize(20).onClick( () => {
                this.weiboColor = Color.Black
                this.uniColor = Color.Black
                this.huaweiColor = Color.Black
                this.weiboIndex = 1
                this.uniIndex = 2
                this.huaweiIndex = 3
                this.asyncGetData()
            })

            Button('开始网络请求 - 同步').fontSize(20).onClick( () => {
                this.weiboColor = Color.Black
                this.uniColor = Color.Black
                this.huaweiColor = Color.Black

                this.weiboIndex = 1
                this.uniIndex = 2
                this.huaweiIndex = 3
                this.syncGetData()
            })

            Button('开始网络请求-自定义方法装饰器').fontSize(20).onClick( () => {
              this.getWeiBoListByController()
            })

            Scroll() {
              Text(this.msg).width('100%')
            }
            .scrollable(ScrollDirection.Vertical)
          }
          .width('100%')
          .height('100%')
          .padding({top: px2vp(120)})
        }

      }
  }

  asyncGetData(){

    this.netLoad = 3;

    this.TEST_Target_URL.forEach( (value) => {

      HNet.get({
        url: value,
      }).then( (r) => {

        this.msg = JSON.stringify(r)

        if(value.indexOf('weibo') != -1){
          this.weiboColor = Color.Green
          this.weiboIndex = 3 - this.netLoad + 1
        } else if(value.indexOf('unidemo') != -1){
          this.uniColor = Color.Green
          this.uniIndex = 3 - this.netLoad + 1
        } else if(value.indexOf('huawei') != -1){
          this.huaweiColor = Color.Green
          this.huaweiIndex = 3 - this.netLoad + 1
        }

        this.netLoad--

      })
    })

  }

  async syncGetData() {

    let starTime
    let url
    this.netLoad = 3;

    starTime = new Date().getTime()
    url = this.TEST_Target_URL[0]

    starTime = new Date().getTime()
    if(url.indexOf('weibo') != -1){
      console.log('顺序-请求-weibo')
    } else if(url.indexOf('unidemo') != -1){
      console.log('顺序-请求-unidemo')
    } else if(url.indexOf('huawei') != -1){
      console.log('顺序-请求-huawei')
    }

    await HNet.get<WeiBo>({
      url: url,
    }).then( (r) => {

      this.msg = ''

      if(r.code == 0 && r.result){
        r.result.data.statuses.forEach((value: WeiBoItem) => {
          this.msg = this.msg.concat(value.created_at + ' ' + value.id + '\n')
        })
      } else {
        this.msg = r.code + ' ' + r.msg
      }

      if(url.indexOf('weibo') != -1){
        this.weiboColor = Color.Green
        this.weiboIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-weibo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('unidemo') != -1){
        this.uniColor = Color.Green
        this.uniIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-unidemo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('huawei') != -1){
        this.huaweiColor = Color.Green
        this.huaweiIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-huawei-' + (new Date().getTime() - starTime))
      }

      this.netLoad--

    })

    starTime = new Date().getTime()
    url = this.TEST_Target_URL[1]

    starTime = new Date().getTime()
    if(url.indexOf('weibo') != -1){
      console.log('顺序-请求-weibo')
    } else if(url.indexOf('unidemo') != -1){
      console.log('顺序-请求-unidemo')
    } else if(url.indexOf('huawei') != -1){
      console.log('顺序-请求-huawei')
    }

    await HNet.get({
      url: url,
    }).then( (r) => {

      this.msg = JSON.stringify(r)

      if(url.indexOf('weibo') != -1){
        this.weiboColor = Color.Green
        this.weiboIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-weibo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('unidemo') != -1){
        this.uniColor = Color.Green
        this.uniIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-unidemo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('huawei') != -1){
        this.huaweiColor = Color.Green
        this.huaweiIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-huawei-' + (new Date().getTime() - starTime))
      }

      this.netLoad--

    })

    starTime = new Date().getTime()
    url = this.TEST_Target_URL[2]

    starTime = new Date().getTime()
    if(url.indexOf('weibo') != -1){
      console.log('顺序-请求-weibo')
    } else if(url.indexOf('unidemo') != -1){
      console.log('顺序-请求-unidemo')
    } else if(url.indexOf('huawei') != -1){
      console.log('顺序-请求-huawei')
    }

    await HNet.get({
      url: url,
    }).then( (r) => {

      this.msg = JSON.stringify(r)

      if(url.indexOf('weibo') != -1){
        this.weiboColor = Color.Green
        this.weiboIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-weibo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('unidemo') != -1){
        this.uniColor = Color.Green
        this.uniIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-unidemo-' + (new Date().getTime() - starTime))
      } else if(url.indexOf('huawei') != -1){
        this.huaweiColor = Color.Green
        this.huaweiIndex = 3 - this.netLoad + 1
        console.log('顺序-返回-huawei-' + (new Date().getTime() - starTime))
      }

      this.netLoad--

    })

  }

  getHuaWeiSomeDataByNet(){

    this.netLoad = 1

    let starTime = new Date().getTime()

    console.log('顺序-huawei-请求' + starTime)

    HNet.get({
      url: 'https://developer.huawei.com/config/cn/head.json',
    }).then( (r) => {

      this.msg = JSON.stringify(r, null, '\t')

      this.netLoad--

      console.log('顺序-huawei-' + (new Date().getTime() - starTime))

    })

  }

  getWeiBoListByHNet(){

    this.netLoad = 1

    let starTime = new Date().getTime()

    console.log('顺序-weibo-请求' + starTime)

    HNet.get<WeiBo>({
      url: 'https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4188_-_ctg1_4188',
    }).then( (r) => {

      this.msg = ''

      if(r.code == 0 && r.result){
        r.result.data.statuses.forEach((value: WeiBoItem) => {
          this.msg = this.msg.concat(value.created_at + ' ' + value.id + '\n')
        })
      } else {
        this.msg = r.code + ' ' + r.msg
      }
      console.log('顺序-weibo-' + (new Date().getTime() - starTime))

      this.netLoad--

    })
  }

  getWeiBoListByController(){

    this.netLoad = 1

    NetController.getWeiBo<WeiBo>().then( r => {

      this.msg = ''

      if(r.code == 0 && r.result){
        r.result.data.statuses.forEach((value: WeiBoItem) => {
          this.msg = this.msg.concat(value.created_at + ' ' + value.id + '\n' + value.source + '\n')
        })
      } else {
        this.msg = r.code + ' ' + r.msg
      }

      this.netLoad--

    })
  }

}    

import { Get, NetResponse } from './util/HNet'

export default class BizNetController {

  @Get('https://m.weibo.cn/api/feed/trendtop?containerid=102803_ctg1_4188_-_ctg1_4188')
  static getWeiBo<WeiBo>(): Promise<NetResponse<WeiBo>>{ return }

}    

import http from '@ohos.net.http';

class NetParams{
  url: string
  extraData?: JSON
}

export class NetResponse<T> {
  result: T
  code: number
  msg: string
}

class HNet {

  static post<T>(options: NetParams): Promise<NetResponse<T>>{
    return this.request(options, http.RequestMethod.POST)
  }

  static get<T>(options: NetParams): Promise<NetResponse<T>>{
    return this.request(options, http.RequestMethod.GET)
  }

  private static request<T>(options: NetParams, method: http.RequestMethod): Promise<NetResponse<T>>{

    let r = http.createHttp()

    return r.request(options.url, {
      method: method,
      extraData: options.extraData != null ? JSON.stringify(options.extraData) : null
    }).then( (response: http.HttpResponse) => {

      let netResponse = new NetResponse<T>()

      let dataType = typeof response.result

      if(dataType === 'string'){
         console.log('结果为字符串类型')
      }

      if(response.responseCode == 200){
        netResponse.code = 0
        netResponse.msg = 'success'
        netResponse.result = JSON.parse(response.result as string)

      } else {
        //出错
        netResponse.code = -1
        netResponse.msg = 'error'

      }

      return netResponse

    }).catch( reject => {
      console.log('结果发生错误')

      let netResponse = new NetResponse<T>()
      netResponse.code = reject.code
      netResponse.msg  = reject.message
      return netResponse

    }).finally( () => {
       r.destroy()
    })

  }

}

export default HNet

export function Get(targetUrl: string) : MethodDecorator {

  return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
        //替换方法
        descriptor.value = () => {
           let options = new NetParams()
           options.url = targetUrl
            return HNet.get(options)
        }
  }

}
    

export class WeiBo{
  ok: number
  http_code: number
  data: WeiBoDataObj
}

export class WeiBoDataObj{
  total_number: number
  interval: number
  remind_text: string
  page: number
  statuses: Array<WeiBoItem>
}

export class WeiBoItem{
  created_at: string
  id: string
  source: string
  textLength: number
}

最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造 的**《鸿蒙NEXT星河版OpenHarmony开发文档》** 里面内容包含了(**ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony****多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)**技术知识点

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

高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》

针对鸿蒙成长路线打造的鸿蒙学习文档 。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

《鸿蒙 (OpenHarmony)开发学习视频》

《鸿蒙生态应用开发V2.0白皮书》

《鸿蒙 (OpenHarmony)开发基础到实战手册》

获取这份鸿蒙星河版学习资料,请点击→ 《鸿蒙NEXT星河版开发学习文档》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  1. ArkTS语言

  2. 安装DevEco Studio

  3. 运用你的第一个ArkTS应用

  4. ArkUI声明式UI开发

  5. .......

《鸿蒙开发进阶》

  1. Stage模型入门

  2. 网络管理

  3. 数据管理

  4. 电话服务

  5. 分布式应用开发

  6. 通知与窗口管理

  7. 多媒体技术

  8. 安全技能

  9. 任务管理

  10. WebGL

  11. 国际化开发

  12. 应用测试

  13. DFX面向未来设计

  14. 鸿蒙系统移植和裁剪定制

  15. ......

《鸿蒙开发实战》

  1. ArkTS实践

  2. UIAbility应用

  3. 网络案例

  4. ......

获取这份鸿蒙星河版学习资料,请点击→ 《鸿蒙NEXT星河版开发学习文档》

总结

鸿蒙---作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发

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

相关推荐
踏雪Vernon9 小时前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
一只爱撸猫的程序猿11 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
Andy醒13 小时前
HarmonyOS . 沉浸状态栏使用
harmonyos·鸿蒙
yuwinter13 小时前
鸿蒙HarmonyOS学习笔记(2)
笔记·学习·harmonyos
jikuaidi6yuan15 小时前
鸿蒙系统(HarmonyOS)分布式任务调度
分布式·华为·harmonyos
本当迷ya17 小时前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
️ 邪神21 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
SameX1 天前
HarmonyOS Next 安全生态构建与展望
前端·harmonyos
SameX1 天前
HarmonyOS Next 打造智能家居安全系统实战
harmonyos