• [其他] DontCrack:专为开源鸿蒙 Linux Kernel 打造的进程管理器
    在开源鸿蒙的实际部署中,init.cfg 是系统启动的关键配置文件,但稍有格式错误就可能导致设备卡在 Logo、系统进程无法启动。DontCrack 正是为此而生 —— 一个专注于鸿蒙 Linux Kernel 侧的高可靠进程管理器。✅ 核心优势低耦合高隔离:不挑管理对象,支持二进制、Shell、Python、Node、Perl、Ruby 等脚本时序稳定性保障:避免因启动顺序或配置错误导致系统异常Restful API 控制:支持 /startup、/shutdown、/heartbeat 等接口,轻松远程管理配置灵活:支持独立设置路径、参数、环境变量、预处理脚本、自动重启策略、日志缓存等跨架构免 CGO:Go 编译即可运行,支持 ARM、x86 等架构,适配嵌入式与模拟器环境🛠️ 快速启动示例bash./DontCrack -path /home/test_program.sh \ -args "-key=test123 -shell=/bin/bash" \ -start-now🌐 项目地址📦 GitCode 开源仓库: 👉https://gitcode.com/tyza66/DontCrack📄 示例配置文件: 👉init.cfg 示例🔜 TodoList(欢迎共建)日志本地持久化与定时清理自动重启次数复位与无限重启开关API 访问加密与远程控制增强结构重构,提升可维护性与扩展性欢迎开源鸿蒙社区的伙伴试用、反馈、共建!DontCrack 致力于让init.cfg 更安全、更稳定、更可控,为设备启动保驾护航。如需适配嵌入式平台、模拟器环境或定制启动策略,欢迎交流!# 开鸿Developer社区
  • [其他] 🚀 DontCrack:专为开源鸿蒙 Linux Kernel 打造的进程管理器
    在开源鸿蒙的实际部署中,init.cfg 是系统启动的关键配置文件,但稍有格式错误就可能导致设备卡在 Logo、系统进程无法启动。DontCrack 正是为此而生 —— 一个专注于鸿蒙 Linux Kernel 侧的高可靠进程管理器。✅ 核心优势低耦合高隔离:不挑管理对象,支持二进制、Shell、Python、Node、Perl、Ruby 等脚本时序稳定性保障:避免因启动顺序或配置错误导致系统异常Restful API 控制:支持 /startup、/shutdown、/heartbeat 等接口,轻松远程管理配置灵活:支持独立设置路径、参数、环境变量、预处理脚本、自动重启策略、日志缓存等跨架构免 CGO:Go 编译即可运行,支持 ARM、x86 等架构,适配嵌入式与模拟器环境🛠️ 快速启动示例bash./DontCrack -path /home/test_program.sh-args “-key=test123 -shell=/bin/bash”-start-now🌐 项目地址📦 GitCode 开源仓库: 👉 https://gitcode.com/tyza66/DontCrack📄 示例配置文件: 👉 init.cfg 示例🔜 TodoList(欢迎共建)日志本地持久化与定时清理自动重启次数复位与无限重启开关API 访问加密与远程控制增强结构重构,提升可维护性与扩展性欢迎开源鸿蒙社区的伙伴试用、反馈、共建!DontCrack 致力于让 init.cfg 更安全、更稳定、更可控,为设备启动保驾护航。如需适配嵌入式平台、模拟器环境或定制启动策略,欢迎交流!
  • [技术交流] 开发者技术支持-对象数组Item数据发生变化时UI不刷新问题
    一、问题说明对象数组使用ForEach进行循环遍历渲染时,将循环的Item的数据进行改变,数据发生变化但是ui没有进行刷新 二、原因分析1.数据源未深度检测;2.数据引用地址未更新;3.ForEach使用不当 三、解决思路1.当数据源为嵌套对象或数组时,若未使用@Observed/ObservedV2装饰器修饰类,属性变更无法触发UI刷新。2.直接修改this.list.property = newValue 但未装饰数据类。 四、解决方法1.装饰器说明:@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步(1).使用new创建被@Observed装饰的类,可以被观察到属性的变化。(2).子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。(3.)@Observed用于嵌套类场景中,观察对象类属性变化,要配合自定义组件使用(示例详见嵌套对象),如果要做数据双/单向同步,需要搭配@ObjectLink或者@Prop使用(示例详见@Prop与@ObjectLink的差异)。(4).@ObjectLink不支持简单类型,如果开发者需要使用简单类型,可以使用@Prop。 2.代码示例(1).在item导出class添加@Observed装饰器(2).定义接收数据并在赋值的同时将每一项new出来(3).使用@ObjectLink监听子组件单项数据进行渲染 五、总结UI刷新依赖数据引用地址变化或深度观测装饰器。对于List组件,优先组合使用@Observed+新对象创建,或LazyDataSource的notifyDataReload()+引用变更。
  • [技术交流] 开发者技术支持-跨组件通信:EmitterUtil工具
    在开发过程中遇到两个毫无联系的组件,页面,可以公共EmitterUtil工具来实现跨组件事件调用。传参  Emitter工具类(进行线程间通信)1.发送事件(示例)  EmitterUtil.post(Keys.SHOP_COUNT, true)第一个参数是命名事件ID,string类型的eventId不支持空字符串第二个参数为要传递的参数注:在A页面一个方法即将执行完成要与B页面发生交互的时候调用该方法2.接收订阅事件(示例)  EmitterUtil.onSubscribe<boolean>(Keys.SHOP_COUNT, (data: boolean) => { this.shopCount()})第一个参数同样是命名事件ID,string类型的eventId不支持空字符串第二个参数为callback 事件的回调处理函数可以在该函数内进行参数赋值,方法调用注:在该页面的生命周期aboutToAppear内调用3.取消订阅事件(示例)  aboutToDisappear(): void { EmitterUtil.unSubscribe(Keys.SHOP_COUNT)}注:参数是之前定义好的事件ID,调用取消订阅释放内存
  • [知识分享] harmony中调用自定义so
      由于在项目开发过程中需要将一些数据隐藏,但是又不想暴露出去,可以将数据放到so库中,在so库中经过一些加密算法的加工在给arkts端使用。以下是自定义的so库的步骤。1.生成.so创建Native工程:DevEco Studio -> File -> New -> Create Project -> Native C++ 创建成功之后,main目录下会有一个cpp目录,在cpp中可以编写自己的c代码了 其中 Index.d.ts: 是一个声明文件,用来声明导出的 C++ 函数,在 JS 中可以直接使用这些函数。oh-package.json5: 这是一个配置文件,用来配置so名称、版本等信息CMakeLists.txt、napi_init.cpp: C++代码以及 CMakeLists.txt 文件,用来编译生成 .so 文件,.cpp 文件内用于编写你的逻辑代码我的c代码,大致如下:其中,.nm_modname = "entry",必须和你的目录名字保持一致。将你的函数注册到index.d.ts中即可2.打包Build -> Build Module,在build -> intermediates -> libs -> default目录下生成.so 3.使用.so将自己的so库copy到你的项目中,放到新建的libs下在oh-package.json5添加依赖在使用的地方引入以上就可以成功调用了 
  • [知识分享] 开发者技术支持-UniApp 小程序 鸿蒙SDK集成实现热更新
    一,问题说明原先已实现 UniAPP 项目转鸿蒙,客户提出需要实现类似于微信加载多个小程序并能热更新二、需求分析实现热更新需要能够动态加载小程序资源包,原先的方案是将小程序项目直接打包进鸿蒙 hap中,只支持单个小程序不支持热更新三、解决思路通过查阅UniApp 官方网站,找到小程序动态加载方案及sdk,根据客户需求进行开发适配实现需求四、解决方案可通过 DCloud 平台配置小程序热更新资源包,或将 wgt 资源包上传自己的服务器,app下载资源包更新(一).开发环境DevEco-Studio 5.0.3.800 以上鸿蒙系统版本 API 12 以上 (DevEco-Studio有内置鸿蒙模拟器)HBuilderX-4.27+ 下载uni小程序 SDK不支持x86模拟器(二).配置uni小程序SDK1.修改鸿蒙项目根目录文件 oh-package.json5 的依赖 "@dcloudio/uni-app-runtime": "版本号"  2.点击右上角 Sync Now,并等待 Sync 结束(三).通过wgt包导入小程序应用资源选中您的 uni-app 项目,右键->发行->App-制作应用wgt包  项目编译完成后会在控制台,输出wgt包的路径,点击路径可以直接打开wgt所在目录  如图,__UNI__6275E02.wgt 就是应用资源包,(__UNI__6275E02 为小程序的 appid)如果提示导出失败,请删除项目根目录 manifest.json 源码里的 app-harmony 属性  将生成的wgt包拷贝到 entry/src/main/resources/resfile 目录下,如下图所示  再通过 releaseWgtToRunPath 函数释放 wgt 包到运行目录,最后通过 openUniMP 函数打开小程序,代码如下import { openUniMP,isExistsUniMP, releaseWgtToRunPath } from '@dcloudio/uni-app-runtime';@Entry@Componentstruct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Text(this.message) .id('HelloWorld') .fontSize(50) .fontWeight(FontWeight.Bold) .alignRules({ center: { anchor: '__container__', align: VerticalAlign.Center }, middle: { anchor: '__container__', align: HorizontalAlign.Center } }) .onClick(async ()=>{ const mpId = "__UNI__6275E02" await new Promise<void>((resolve, reject) => { try { // 判断应用是否已释放到运行目录 let isExists = isExistsUniMP(mpId) console.log("isExists:"+isExists) // 拼接wgt包路径 let path = getContext().resourceDir + "/"+mpId+".wgt" // 释放 wgt 包到运行目录 releaseWgtToRunPath(mpId,path, (code:number, data: object)=>{ console.log(JSON.stringify({code,data})) resolve() }) } catch(err){ reject(err) } }) // 启动小程序 const mp = openUniMP(mpId) mp.on('close',()=>{ console.log('UniMP-close') }) mp.on('show',()=>{ console.log('UniMP-show') }) mp.on('hide',()=>{ console.log('UniMP-hide') }) }) } .height('100%') .width('100%') }}
  • [技术交流] 开发者技术支持-webview加载url缓慢的优化方法
    1. 提前初始化Web引擎   在`页面`的`aboutToAppear`阶段调用`initializeWebEngine()`,预加载Web内核动态库,减少首次白屏时间(约优化140ms)。​  aboutToAppear(): void { webview.WebviewController.initializeWebEngine(); // 启动时预加载内核}2. DNS预解析与Socket预连接   在web组件的`onAppear`阶段对目标URL调用`prepareForPageLoad()`,提前建立网络连接(优化约80ms)。 注:url替换成自己的url就可以​  .onAppear(() => {webview.WebviewController.prepareForPageLoad(this.url, true, 2)})3. 页面资源预加载   在`onPageEnd`事件中预判用户下一步操作,用`prefetchPage()`下载下一页资源(如小说/商品详情页)​​  .onPageEnd(()=>{ this.webController.prefetchPage('https://example.com/next-page');})二、渲染与架构优化(进阶提升)1. 预渲染高频页面   对确定性跳转页(如首页→详情),通过`NodeController`创建隐藏的Web组件进行后台渲染,切换时直接展示。    ```typescript   // 创建NodeController管理离线Web组件   const nodeController = new NodeController();   nodeController.buildHiddenWebView(url); // 后台渲染   // 跳转时挂载到NodeContainer显示   ```2. 动态加载非必要模块   使用“动态import() ”按需加载子页面,减少主包体积(主页加载耗时从22.9ms→7.9ms)。    ```typescript   Button('跳转')     .onClick(async () => {       const module = await import('./DetailPage'); // 点击时才加载       this.pageStack.pushPath(module.buildPage);     })   ```3. 优化H5页面设计  - 合并CSS/JS文件,压缩资源(Webpack/Vite配置`manualChunks`分割代码)  - 图片懒加载:`<Image loadMode="lazy">`    - 长任务拆解:用`Web Worker`执行耗时逻辑 
  • [技术交流] 开发者技术支持-AES算法的CBC模式加密NoPadding加密非16位时程序报错问题
    由于AES为分组加密算法,分组长度为128位。如果最后一组明文不足128位(16字节),可以通过不同的填充模式进行数据填充1.问题代码中填充模式选择NoPadding,不会对明文进行填充,所以当最后一组不足128位时程序崩溃,可以选择PKCS5和PKCS7进行填充注:选择PKCS7进行填充加密后再解密,解密数据后会加上一串二进制字符串 需要将用到的数据进行截取2.如果需要ZeroPadding,需要开发者手动对密文进行填充。stringPadding(str: string){  let len = str.length  switch (len % 16) {    case 0:      break;    case 1:      str.padEnd(16 - 1, '0');      break;    case 2:      str.padEnd(16 - 2, '0');      break;    case 3:      str.padEnd(16 - 3, '0');      break;    case 4:      str.padEnd(16 - 4, '0');      break;    case 5:      str.padEnd(16 - 5, '0');      break;    case 6:      str.padEnd(16 - 6, '0');      break;    case 7:      str.padEnd(16 - 7, '0');      break;    case 8:      str.padEnd(16 - 8, '0');      break;    case 9:      str.padEnd(16 - 9, '0');      break;    case 10:      str.padEnd(16 - 10, '0');      break;    case 11:      str.padEnd(16 - 11, '0');      break;    case 12:      str.padEnd(16 - 12, '0');      break;    case 13:      str.padEnd(16 - 13, '0');      break;    case 14:      str.padEnd(16 - 14, '0');      break;    case 15:      str.padEnd(16 - 15, '0');      break;  }}注:手动加0填充后解密出来的数据后会加对应16位的字符串0需要手动截取
  • [技术交流] 开发者技术支持-手动获取权限,手动拉起弹窗授权
    示例demo是以录音ohos.permission.MICROPHONE权限为例子1.通过requestPermissionsFromUser接口进行权限状态获取关键代码:  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();let context = getContext(this) as common.UIAbilityContext;// 等待权限请求完成const data: PermissionRequestResult = await atManager.requestPermissionsFromUser(context, ['ohos.permission.MICROPHONE']);2.通过checkAccessToken接口进行首次授权弹窗拉起关键代码:  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();let bundleInfo: bundleManager.BundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;let tokenID: number = appInfo.accessTokenId;atManager.checkAccessToken(tokenID, 'ohos.permission.MICROPHONE').then((data: abilityAccessCtrl.GrantStatus) => { const authResult = data === 0 ? 1 : 0; console.log(`checkAccessToken success, data->${JSON.stringify(data)}`,authResult.toString());}).catch((err: BusinessError) => { console.error(`checkAccessToken fail, err->${JSON.stringify(err)}`);});3.首次弹窗取消或拒绝后checkAccessToken接口将无法二次拉起,所以需要通过requestPermissionOnSetting进行系统授权弹窗拉起关键代码:  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();let context= getContext(this) as common.UIAbilityContext;atManager.requestPermissionOnSetting(context, ['ohos.permission.MICROPHONE']).then((data: Array<abilityAccessCtrl.GrantStatus>) => { console.info('data:' + JSON.stringify(data)); const authResult = data[0] === 0 ? 1 : 0;}).catch((err: BusinessError) => { console.error('data:' + JSON.stringify(err));});
  • [技术交流] 开发者技术支持-系统弹出授权保存文件
    如何除saveButton按钮外保存视频/图片等使用弹窗授权保存图片视频/** * 保存base64图片/视频到本地相册 */async saveQRCodeImage(type: string, base64: string) {  if (!base64) {    return  }  let context = getContext(this) as common.UIAbilityContext;  let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);  //判断是视频还是图片  if (type.includes("video")) {    try {      let content = base64.split(',')[1]      let dirPath: string = context.cacheDir;      let fileName = 'test.mp4'      this.writeBufferToFile(dirPath, fileName, buffer.from(content, 'base64').buffer)      let uri = fileUri.getUriFromPath(`${dirPath}/${fileName}`);      let srcFileUris: Array<string> =        [uri ];// 实际场景请使用真实的uri      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [{        title: 'test',        fileNameExtension: 'mp4',        photoType: photoAccessHelper.PhotoType.VIDEO,        subtype: photoAccessHelper.PhotoSubtype.DEFAULT, } ];      let desFileUris: Array<string> =        await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);      if (desFileUris.length > 0) {        for (let index = 0; index < desFileUris.length; index++) {          this.copyFileContentTos(srcFileUris[0], desFileUris[index])          promptAction.showToast({ message:$r('app.string.save_success')})        }      }    } catch (err) {      promptAction.showToast({ message: $r('app.string.save_failed') })      console.error('showAssetsCreationDialog failed, errCode is ' + err.code + ', errMsg is ' +      err.message);    }} else {    try {      const modifiedData = base64.replace(        "data:application/octet-stream;base64",        "data:image/png;base64"      );      let content = modifiedData.split(',')[1]      let dirPath: string = context.cacheDir;      let fileName = 'test11.jpg'      this.writeBufferToFile(dirPath, fileName, buffer.from(content, 'base64').buffer)      let uri = fileUri.getUriFromPath(`${dirPath}/${fileName}`);      let srcFileUris: Array<string> =        [uri ];// 实际场景请使用真实的uri      let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [{        title: 'test',        fileNameExtension: 'png',        photoType: photoAccessHelper.PhotoType.IMAGE,        subtype: photoAccessHelper.PhotoSubtype.DEFAULT, } ];      let desFileUris: Array<string> =        await phAccessHelper.showAssetsCreationDialog(srcFileUris, photoCreationConfigs);      if (desFileUris.length > 0) {        for (let index = 0; index < desFileUris.length; index++) {          this.copyFileContentTo(srcFileUris[0], desFileUris[index])        }        promptAction.showToast({ message:$r('app.string.save_success')})      }    } catch (err) {      promptAction.showToast({ message: $r('app.string.save_failed') })      console.error('showAssetsCreationDialog failed, errCode is ' + err.code + ', errMsg is ' +      err.message);    }  }  }copyFileContentTo(srcFilePath: string, destFilePath: string) {  let srcFile = fs.openSync(srcFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)  let destFile = fs.openSync(destFilePath, fs.OpenMode.READ_WRITE |  fs.OpenMode.CREATE)  // 读取源文件内容并写入至目的文件  let bufSize = 4096;  let readSize = 0;  let buf = new ArrayBuffer(bufSize);  let readOptions: ReadOptions = { offset: readSize, length: bufSize };  let readLen = fs.readSync(srcFile.fd, buf, readOptions);  while (readLen > 0) {    readSize += readLen;    let writeOptions: WriteOptions = { length: readLen };    fs.writeSync(destFile.fd, buf, writeOptions);    readOptions.offset = readSize;    readLen = fs.readSync(srcFile.fd, buf, readOptions);  }  // 关闭文件  fs.closeSync(srcFile);  fs.closeSync(destFile);}copyFileContentTos(srcFilePath: string, destFilePath: string) {  let srcFile = fs.openSync(srcFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)  let destFile = fs.openSync(destFilePath, fs.OpenMode.READ_WRITE |  fs.OpenMode.CREATE)  // 读取源文件内容并写入至目的文件  let bufSize = 20400;  let readSize = 0;  let buf = new ArrayBuffer(bufSize);  let readOptions: ReadOptions = { offset: readSize, length: bufSize };  let readLen = fs.readSync(srcFile.fd, buf, readOptions);  while (readLen > 0) {    readSize += readLen;    let writeOptions: WriteOptions = { length: readLen };    fs.writeSync(destFile.fd, buf, writeOptions);    readOptions.offset = readSize;    readLen = fs.readSync(srcFile.fd, buf, readOptions);  }  // 关闭文件  fs.closeSync(srcFile);  fs.closeSync(destFile);}
  • [技术交流] 开发者技术支持-原生跳系统拨打电话页面
    原生跳转拨打电话页面原创男孩收纳专栏 : 日常记录 2025-08-01 18:32发布于:山西 21开发步骤1.import需要的模块。2.调用hasVoiceCapability()接口获取当前设备呼叫能力,如果支持继续下一步;如果不支持则无法发起呼叫。3.跳转到拨号界面,并显示拨号的号码。  // import需要的模块import call from '@ohos.telephony.call';import observer from '@ohos.telephony.observer';// 调用查询能力接口let isSupport = call.hasVoiceCapability();if (!isSupport) {    console.log("not support voice capability, return.");    return;}// 如果设备支持呼叫能力,则继续跳转到拨号界面,并显示拨号的号码call.makeCall("13xxxx", (err)=> {    if (!err) {        console.log("make call success.");    } else {        console.log("make call fail, err is:" + JSON.stringify(err));    }});// 订阅通话业务状态变化(可选)observer.on("callStateChange", (data) => {    console.log("call state change, data is:" + JSON.stringify(data));});
  • [技术交流] 开发者技术支持-使用全局loading加载弹窗
    一丶使用DialogHelper三方组件进行全局或者当前页面loading加载1.首先在页面@state一个弹窗id(在本页使用或者在全局使用都会用到)@statedialogId:string = ''''2.在需要loading加载的地方进行DialogHelper调用this.dialogId = DialogHelper.showLoadingDialog({ autoCancel: false })3.loading弹窗取消DialogHelper.closeDialog(this.dialogId)注:如果在全局使用当前loading可以通过持久化的方式存储dialogId然后在取消的时候进行调用二丶自定义封装弹窗1.可以自定义封装一个LoadingProgress2.通过自定义方法动态绑定该弹窗的Visibility属性:‌ (1) Visibility.Visible 显示(2) Visibility.None 移除布局不占位3.将该组件暴露出去,在使用的地方使用方法进行显隐控制注:这是一个大概的思路,希望可以帮助到大家
  • [技术交流] 开发者技术支持-搭建网络请求框架
    一丶可以使用官方文档的@ohos.net.http(数据请求)进行搭建1.导入模块import { http } from '@kit.NetworkKit';2.示例代码// 引入包名import { http } from '@kit.NetworkKit';import { BusinessError } from '@kit.BasicServicesKit';// 每一个httpRequest对应一个HTTP请求任务,不可复用。let httpRequest = http.createHttp();// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息。// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+httpRequest.on('headersReceive', (header: Object) => {  console.info('header: ' + JSON.stringify(header));});httpRequest.request(// 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定。  "EXAMPLE_URL",  {    method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET。    // 当使用POST请求时此字段用于传递请求体内容,具体格式与服务端协商确定。    extraData: 'data to send',    expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型。    usingCache: true, // 可选,默认为true。    priority: 1, // 可选,默认为1。    // 开发者根据自身业务需要添加header字段。    header: { 'Accept' : 'application/json' },    readTimeout: 60000, // 可选,默认为60000ms。    connectTimeout: 60000, // 可选,默认为60000ms。    usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定。    usingProxy: false, //可选,默认不使用网络代理,自API 10开始支持该属性。    caPath: '/path/to/cacert.pem', // 可选,默认使用系统预设CA证书,自API 10开始支持该属性。    clientCert: { // 可选,默认不使用客户端证书,自API 11开始支持该属性。      certPath: '/path/to/client.pem', // 默认不使用客户端证书,自API 11开始支持该属性。      keyPath: '/path/to/client.key', // 若证书包含Key信息,传入空字符串,自API 11开始支持该属性。      certType: http.CertType.PEM, // 可选,默认使用PEM,自API 11开始支持该属性。      keyPassword: "passwordToKey" // 可选,输入key文件的密码,自API 11开始支持该属性。    },    certificatePinning: [ // 可选,支持证书锁定配置信息的动态设置,自API 12开始支持该属性。      {        publicKeyHash: 'Pin1', // 由应用传入的证书PIN码,自API 12开始支持该属性。        hashAlgorithm: 'SHA-256' // 加密算法,当前仅支持SHA-256,自API 12开始支持该属性。      }, {        publicKeyHash: 'Pin2', // 由应用传入的证书PIN码,自API 12开始支持该属性。        hashAlgorithm: 'SHA-256' // 加密算法,当前仅支持SHA-256,自API 12开始支持该属性。      }    ],    multiFormDataList: [ // 可选,仅当Header中,'content-Type'为'multipart/form-data'时生效,自API 11开始支持该属性。      {        name: "Part1", // 数据名,自API 11开始支持该属性。        contentType: 'text/plain', // 数据类型,自API 11开始支持该属性。        data: 'Example data', // 可选,数据内容,自API 11开始支持该属性。        remoteFileName: 'example.txt' // 可选,自API 11开始支持该属性。      }, {        name: "Part2", // 数据名,自API 11开始支持该属性。        contentType: 'text/plain', // 数据类型,自API 11开始支持该属性。        // data/app/el2/100/base/com.example.myapplication/haps/entry/files/fileName.txt        filePath: `${getContext(this).filesDir}/fileName.txt`, // 可选,传入文件路径,自API 11开始支持该属性。        remoteFileName: 'fileName.txt' // 可选,自API 11开始支持该属性。      }    ]  },  (err: BusinessError, data: http.HttpResponse) => {    if (!err) {      // data.result为HTTP响应内容,可根据业务需要进行解析。      console.info('Result:' + JSON.stringify(data.result));      console.info('code:' + JSON.stringify(data.responseCode));      console.info('type:' + JSON.stringify(data.resultType));      // data.header为HTTP响应头,可根据业务需要进行解析。      console.info('header:' + JSON.stringify(data.header));      console.info('cookies:' + JSON.stringify(data.cookies)); // 自API version 8开始支持cookie。      // 取消订阅HTTP响应头事件。      httpRequest.off('headersReceive');      // 当该请求使用完毕时,开发者务必调用destroy方法主动销毁该JavaScript Object。      httpRequest.destroy();    } else {      console.info('error:' + JSON.stringify(err));      // 取消订阅HTTP响应头事件。      httpRequest.off('headersReceive');      // 当该请求使用完毕时,开发者务必调用destroy方法主动销毁该JavaScript Object。      httpRequest.destroy();    }  });二丶axios:Axios,是一个基于 promise 的网络请求库,本库基于Axios 原库v1.3.4版本进行适配,使其可以运行在 OpenHarmony。1.下载安装依赖ohpm install @ohos/axios2.进行权限设置ohos.permission.INTERNET3.接口与属性列表接口参数功能axios(config)config:请求配置发送请求axios.create(config)config:请求配置创建实例axios.request(config)config:请求配置发送请求axios.get(url[, config])url:请求地址config:请求配置发送get请求axios.delete(url[, config])url:请求地址config:请求配置发送delete请求axios.post(url[, data[, config]])url:请求地址data:发送请求体数据config:请求配置发送post请求axios.put(url[, data[, config]])url:请求地址data:发送请求体数据config:请求配置发送put请求属性列表属性描述axios.defaults['xxx']默认设置 。值为请求配置 config 中的配置项例如 axios.defaults.headers 获取头部信息axios.interceptors拦截器。参考 拦截器 的使用说明:由于ArkTS不再支持any类型,需指定参数的具体类型。 如:axios.get<T = any, R = AxiosResponse, D = any>(url)T: 是响应数据类型。当发送一个 POST 请求时,客户端可能会收到一个 JSON 对象。T 就是这个 JSON 对象的类型。默认情况下,T 是 any,这意味着可以接收任何类型的数据。R: 是响应体的类型。当服务器返回一个响应时,响应体通常是一个 JSON 对象。R 就是这个 JSON 对象的类型。默认情况下,R 是 AxiosResponse,这意味着响应体是一个 AxiosResponse 对象,它的 data 属性是 T 类型的D: 是请求参数的类型。当发送一个 GET 请求时,可能会在 URL 中添加一些查询参数。D 就是这些查询参数的类型。参数为空情况下,D 是 null类型。4.示例​interface user {   firstName: string,   lastName: string }  axios.post<string, AxiosResponse<string>, user>('/user', {      firstName: 'Fred',      lastName: 'Flintstone'    })    .then((response: AxiosResponse<string>) => {      console.info(JSON.stringify(response));    })    .catch((error) => {   console.info(JSON.stringify(error)); });三丶@yunkss/ef_rcp三方库的组件efRcpClientApi
  • [技术交流] 开发者技术支持-获取系统导航栏,状态栏高度
    1.获取应用窗口  let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口2.注册监听函数,动态获取避让区域数据  windowClass.on('avoidAreaChange', (data) => { // 判断当前变化的避让区域类型是否为系统避让区域 if (data.type === window.AvoidAreaType.TYPE_SYSTEM) { // 获取系统避让区域的高度并存储 let topRectHeight = data.area.topRect.height; LogUtil.info('状态栏高度:',topRectHeight.toString()) AppStorage.setOrCreate(Keys.topRectHeight, topRectHeight); } else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) { // 获取导航条避让区域的高度并存储 let bottomRectHeight = data.area.bottomRect.height; LogUtil.info('导航栏高度:',bottomRectHeight.toString()) AppStorage.setOrCreate(Keys.bottomRectHeight, bottomRectHeight); }});
  • [分享交流] 深圳人才福利!5大“国家队”级信创技术免费培训课程开始报名
    当别人已在鸿蒙生态接单月入3万+,你还在Java内卷?当大模型重构IT岗位,传统运维正批量淘汰…体贴的深圳人社为您再次奉上信创技术/鸿蒙系统/麒麟系统等新一代信息应用技术生存技能大餐•       信创智算与大模型技术课程•       开源高斯数据库技术课程•       鸿蒙原生应用开发课程•       开源鸿蒙设备应用技术课程•       前沿  科技  国产系统应用 还等什么基于麒麟操作系统的信创基础软件适配迁移与运维课程 【理论授课、现场实战、组队攻坚】告别枯燥的理论推砌聘请行业专家担任讲师5门免费课程助你抢占信息技术高地,满级晋升!最重要的是全!免!费!咱不花一分钱就开启成长与蜕变的大门报名有啥要求?咋报名?快随我往下看吧!一、  报名条件报名学员需具有新一代电子信息应用技术相关的行业从业背景或具备相关专业背景,并满足以下条件之一即可:1.本市户籍人员;2.在本市正常缴交社会保险的人员;3.深圳市登记失业人员;4.在深圳市公共就业服务机构进行离校两年未就业实名登记的本市高校毕业生;5.本市高校或本市户籍在市外高校的毕业年度(指毕业时间在2025年1月1日至12月31日之间)毕业生(含技师学院高级工班、预备技师班)。温馨提示:(1)同一劳动者同一年度只能参加1次项目制培训哦。如果您已经参加2024年度项目制培训但未完成规定学时50%以上,很遗憾,那无法参加2025年度的项目制培训了哦。(2)同一劳动者同一年度内企业新型学徒制培训,学生学徒制培训、技培生学徒制培训只能参加一次,且均不能和项目制培训同时享受。等等先别急还没完!还有额外补贴!【额外补贴】如您满足以下条件之一:•       本市就业困难人员•       本市零就业家庭成员•       本市就业残疾人•       本市城市低保家庭成员•       本市毕业2年内的“两后生”中的农村学员•       本市求职就业的脱贫人员不仅可以免费学课程还可以再领500元的生活补贴金💴! 接下来咱们看一下具体学习内容吧!二、  学习内容以及报名方式 新一代电子信息应用技术项目制培训 指导单位:深圳市人力资源和社会保障局主办单位 :深圳市职业技能培训指导中心承办单位:深圳职业技术大学1、信创智算与大模型技术课程课程内容培训天数培训名额主要内容包括:1.基于昇腾平台的 DeepSeek 模型搭建与优化2.华为云昇腾算力支持下的私有场景大模型部署3.基于昇腾与 DeepSeek 的私有大模型自主训练4.电商场景下大模型的创新应用与拓展6天约300人 信创智算与大模型技术课程报名二维码及交流群(QQ群)    2、开源高斯数据库技术课程课程内容培训天数培训名额主要内容包括:1.高斯数据库安装与对象管理实操2.场景化高斯数据库实验探索3.数据库AI策略与技巧4.数据安全管理与防护6天约250人开源高斯数据库技术课程报名二维码及交流群(QQ群)   3、      鸿蒙原生应用开发课程课程内容培训天数培训名额主要内容包括:1.基于ArkTSUI框架搭建实训云平台2.鸿蒙原生办公签到系统开发3.基于Next版本开发实时社交软件联动DeepSeek实现聊天问答4.基于鸿蒙服务卡片开发音乐推荐软件5.鸿蒙原生健康服务检测软件开发6天约250人 鸿蒙原生应用开发课程报名二维码及交流群(QQ群)     4、      开源鸿蒙设备应用技术课程课程内容培训天数培训名额主要内容包括:1.OpenHarmony搭建与配置2.开源鸿蒙设备驱动开发和集成3.基于开源鸿蒙的HAL层开发4.基于开源鸿蒙的智能家居软硬件开发6天约250人 开源鸿蒙设备应用技术课程报名二维码及交流群(QQ群)    5、基于麒麟操作系统的信创基础软件适配迁移与运维课程课程内容培训天数培训名额主要内容包括:1.银河麒麟桌面操作系统 V10 的管理应用2.掌握适配测试基础及软硬件适配测试技能6天约250人 基于麒麟操作系统的信创基础软件适配迁移与运维课程报名二维码及交流群(QQ群)   三、成长与收获1.掌握实用技能,提高自身职业技能,增强就业竞争力,优化职业发展路径;2.培训考勤达标且考核通过将获得《深圳市职业技能提升培训合格证书》;3.可自行选考行业权威认证:HCIA-AI认证、HCIA-openGauss认证、HarmonyOS应用开发者认证、开放原子OpenHarmony人才认证、KYCA、KYCP认证(不含考证费)。四、班级设置l  7月29日-9月30日  开设日常精品班(周一到周六)开设周末精品班(周六或周日单日班)l  7月29日-10月20日开设周末精品班(周六或周日单日班)五、咨询与联络黄老师:13528095312(微信同号)周老师:0755-26019607咨询时间:工作日9:00- 18:00其他时间咨询联系QQ群工作人员六、培训地点深圳职业技术大学西丽湖园区(信息楼)建议绿色出行:深圳地铁5号线西丽地铁站F口步行800米。公交车站-深圳职业技术大学(西丽湖园区),线路包括M197、M182、M176、M492、高峰专线59、325、M535、M217、67、326等。 别再犹豫,抓住这个难得的机会,让自己在公益性培训中实现华丽转身!立即报名,开启你的成长之旅!
总条数:43 到第
上滑加载中