-
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为分组加密算法,分组长度为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));});
-
一丶使用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); }});
-
当别人已在鸿蒙生态接单月入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等。 别再犹豫,抓住这个难得的机会,让自己在公益性培训中实现华丽转身!立即报名,开启你的成长之旅!
-
使用DevEcoStudio 开发、编译鸿蒙 NEXT_APP 以及使用中文插件 #鸿蒙开发工具 #DevEco Studio1. 概述DevEco Studio 是华为提供的一站式集成开发环境(IDE),专为鸿蒙操作系统(HarmonyOS Next)应用和服务开发设计 DevEco Studio,掌握基本操作和开发流程。2. 安装与配置访问华为开发者联盟官网 下载 DevEco Studio 安装包运行安装程序,按照向导完成安装启动 DevEco Studio,首次启动会自动下载并安装 SDK 组件3. 创建新项目3.1 启动向导启动 DevEco Studio,选择 Start a new HarmonyOS project选择应用模板(如 Empty Ability、Native C++ 等)3.2 项目结构创建完成后,DevEco Studio 会生成标准的鸿蒙应用项目结构:myapplication/ ├── AppScope/ │ ├── resources/ │ └── app.json5 # 版本号等内容 ├── entry/ # 主模块 │ ├── src/ │ │ ├── main/ │ │ │ ├── ets/ # ArkTS 代码 │ │ │ ├── resources/ # 资源文件 │ │ │ └── module.json5 │ │ ├── test/ # 测试代码 │ │ ├── mock/ │ │ ├── ohosTest/ │ │ ├── build-profile.json5 │ │ ├── hvigorfile.ts │ │ ├── obfuscation-rules.txt │ │ └── oh-package.json5 │ └── build/ # 编译后测试包 ├── hvgor/ │ └── hvigor-config.json5 ├── build/ # 编译后正式包 └── build-profile.json5 # 项目构建配置文件4 代码方式布局使用 ArkTS 声明式语法:@Entry @Component export struct Index { @State message: string = 'Hello World' build() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) Button('Click Me') .onClick(() => { this.message = 'Hello HarmonyOS!' }) } .width('100%') } } 5. 应用调试5.1 模拟器调试点击工具栏中的 Tools > Device Manager 图标在弹出窗口中点击 New Emulator选择设备类型和系统版本,点击 Next 完成创建点击工具栏中的运行按钮,选择模拟器启动应用5.2 真机调试用 USB 线将鸿蒙设备连接到电脑在设备上多次点击版本号开启 开发者选项 和 USB 调试 功能在 DevEco Studio 中选择设备并点击运行按钮,选择已连接的设备如设备未识别,检查 USB 驱动是否正确安装6. 代码编辑与辅助功能6.1 代码补全DevEco Studio 支持智能代码补全,输入代码时会自动提示可能的选项:输入组件名称时提示可用组件输入属性名时提示可用属性支持方法参数提示和类型检查6.2 代码导航Ctrl + 左键点击:跳转到变量、方法或类的定义处Shift + Shift:快速打开文件Alt + 左/右箭头:在编辑历史中导航7. 构建与打包7.1 构建应用点击 Build > Build Hap(s)/App(s) 构建 APP 包构建完成后,APK 文件位于 build/outputs/default 目录下7.2 签名配置点击 File > Project Structure > Project > Signing Configs选择已有的签名密钥配置签名信息并生成签名8. 中文插件切换中文版不是选择语言,而是需要下载插件点击File > Settings > Plugins搜索Chinese(Simplified)下载并应用重启 DevEcoStudio9. 常见问题与解决方法9.1 模拟器无法启动尝试删除并重新创建模拟器降低模拟器系统版本检查内存9.2 代码报错 “arkts-no-props-by-index”错误原因:ArkTS 不支持通过索引访问对象属性解决方法:使用点号表示法或 Map 结构替代
-
鸿蒙Next实现瀑布流布局 #鸿蒙影音娱乐类应用 #拍摄美化 #HarmonyOS一、环境准备与项目创建在开始实现瀑布流布局前,需确保已安装好 DevEco Studio,且已配置好鸿蒙开发环境。打开 DevEco Studio,新建一个鸿蒙应用项目,选择合适的模板(如 Empty Feature Ability),设置项目名称、包名等信息,完成项目创建。二、布局设计思路鸿蒙 Next 的瀑布流布局可以通过自定义组件结合 Column、Row 等容器组件实现。其核心思路是将数据分成若干列,每列独立滚动展示,且根据数据项高度动态调整布局,以达到类似瀑布自然流动的效果。三、基础实现创建一个自定义组件 MasonryLayout,接收图片数据数组作为参数,并根据列数将数据分配到不同列中展示:@Component export struct MasonryLayout { @Prop data: string[]; @State cols: number[] = Array.from<number>({ length: 2 }).fill(0); build() { Row({}) { ForEach(this.cols, (_col: number, cIndex) => { Column({ }) { ForEach(this.data, (item: string, i) => { if(i % this.cols.length === cIndex) { Image(item).width(`${100 / this.cols.length}%`); } }) } }) }.alignItems(VerticalAlign.Top) } } 四、引用 MasonryLayout 瀑布流组件build() { MasonryLayout({ data: ["img1.png", "img2.png", "img3.png", "img4.png", "img5.png"], }); } 五、优化与扩展1. 响应式布局通过 MediaQuery 组件根据屏幕宽度动态调整瀑布流的列数,以适配不同设备:在 UIAbility 的 onWindowStageCreate 生命周期回调中,通过窗口对象获取启动时的应用窗口宽度并注册回调函数监听窗口尺寸变化。将窗口尺寸的长度单位由 px 换算为 vp 后,即可基于前文中介绍的规则得到当前断点值,此时可以使用状态变量记录当前的断点值方便后续使用MainAbility.tsimport { window, display } from "@kit.ArkUI"; import { UIAbility } from "@kit.AbilityKit"; export default class MainAbility extends UIAbility { private windowObj?: window.Window; private col: number = 2; //... // 根据当前窗口尺寸更新断点 private updateBreakpoint(windowWidth: number): void { // 将长度的单位由px换算为vp let windowWidthVp = windowWidth / display.getDefaultDisplaySync().densityPixels; let col: number = this.col; if (windowWidthVp < 320) { // "xs"; col = 1; } else if (windowWidthVp < 600) { // "sm"; col = 2; } else if (windowWidthVp < 840) { // "md"; col = 3; } else { // "lg"; col = 4; } if (this.col !== col) { this.col = col; } } onWindowStageCreate(windowStage: window.WindowStage): void { windowStage.getMainWindow().then((windowObj) => { this.windowObj = windowObj; // 获取应用启动时的窗口尺寸 this.updateBreakpoint(windowObj.getWindowProperties().windowRect.width); // 注册回调函数,监听窗口尺寸变化 windowObj.on("windowSizeChange", (windowSize) => { this.updateBreakpoint(windowSize.width); }); }); // ... } //... } MasonryLayout.etsinterface IBpMapCol { xs: number; sm: number; md: number; lg: number; } const bpMapCol = new Map<string, number>(); bpMapCol.set('xs', 1) bpMapCol.set('sm', 2) bpMapCol.set('md', 3) bpMapCol.set('lg', 4) @Component export struct MasonryLayout { @StorageProp('currentBreakpoint') curBp: keyof IBpMapCol = 'sm'; @Prop data: string[]; @State cols: number[] = Array.from<number>({ length: bpMapCol.get(this.curBp) || 2 }).fill(0); build() { Row({}) { ForEach(this.cols, (_col: number, cIndex) => { Column({ }) { ForEach(this.data, (item: string, i) => { if(i % this.cols.length === cIndex) { Image(item).width(`${100 / this.cols.length}%`); Text(this.curBp) } }) } }) }.alignItems(VerticalAlign.Top) } } 注:鸿蒙 next 中无法使用索引访问对象属性,如 const obj = { a: 1 } 无法使用 obj[a],这种情况可以用 Map2. 动态加载数据为了实现类似真实瀑布流不断加载新数据的效果,可以结合鸿蒙的 LazyForEach 组件,在滚动到列表底部时触发数据加载逻辑六、网络权限// config.json { "module": { "reqPermissions": [ { "name": "ohos.permission.INTERNET", "reason": "需要网络权限来加载图片" } ] } } 七、常见问题与解决方案1. 图片加载后布局跳动解决方案:使用预估高度占位,图片加载完成后更新高度2. 大数据量性能问题解决方案:实现虚拟列表,只渲染可视区域内的元素3. 滚动卡顿解决方案:使用防抖/节流处理滚动事件避免在滚动回调中执行复杂计算使用鸿蒙的 Canvas 组件替代部分布局组件4. 不同设备适配问题解决方案:使用响应式布局动态调整列数基于设备类型设置不同的默认列数八、最佳实践总结优先使用固定高度:如果业务场景允许,尽量使用固定高度或宽高比,减少动态测量开销合理实现懒加载:对于非首屏内容或图片资源,一定要实现懒加载渐进式增强体验:先确保基础功能可用,再添加动画和交互效果测试与优化:在不同设备上测试性能表现,针对卡顿问题进行专项优化遵循鸿蒙设计规范:保持与鸿蒙系统一致的视觉风格和交互体验
-
鸿蒙NEXT上传图片功能PhotoViewPicker核心功能解析 #ArkTS#鸿蒙Next#HarmonyOS_SDK应用服务#HarmonyOS 语言PhotoViewPicker 是鸿蒙系统中用于媒体资源选择的核心组件,通过它可以便捷地实现图片、视频等媒体文件的选择功能。下面从基本用法、参数配置到高级应用进行全面解析:一、PhotoViewPicker 基础用法PhotoViewPicker 的使用流程主要分为三步:创建实例配置参数启动选择器获取结果以下是最基本的使用示例:import photoAccessHelper from "@ohos.photoAccess.photoAccessHelper"; async function pickImage() { try { // 1. 创建选择器实例 const picker = photoAccessHelper.createPhotoViewPicker(); // 2. 配置选择参数(此处使用默认配置) const options = { MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE, // 只选择图片 maxSelectNumber: 1, // 最多选择张数 isSearchSupported: true, // 显示搜索 isPhotoTakingSupported: true, // 支持拍照 recommendationOptions: true, // 智能推荐 preselectedUris: true, // 预览文件 isPreviewForSingleSelectionSupported: true, // 单选是否支持预览 }; // 3. 启动选择器并获取结果 const selectedAssets = await picker.select(options); if (selectedAssets.photoUris.length) { // 处理选择的资源 console.info("选择的资源:", selectedAssets.photoUris); } } catch (error) { console.error("选择图片失败:", error); } } 二、关键参数详解PhotoViewPicker 的参数配置非常灵活,可以根据需求定制选择器的行为:const options = { MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE, // 只选择图片 maxSelectNumber: 1, // 最多选择张数 isSearchSupported: true, // 显示搜索 isPhotoTakingSupported: true, // 支持拍照 recommendationOptions: true, // 智能推荐 preselectedUris: true, // 预览文件 isPreviewForSingleSelectionSupported: true, // 单选是否支持预览 }; 三、MIMEType 参数深度解析MIMEType 参数是 PhotoViewPicker 中非常强大的一个配置项,它允许你精确控制选择器中显示的文件类型:// 示例1:只允许选择JPEG和PNG图片 IMAGE_TYPE = 'image/*', // 示例2:只允许选择视频文件 VIDEO_TYPE = 'video/*', // 示例3: MOVING_PHOTO_IMAGE_TYPE = 'image/movingPhoto' // 示例4:允许所有 IMAGE_VIDEO_TYPE = '*/*', 四、处理选择结果选择器返回的结果是一个 PhotoSelectResult 对象,包含以下关键属性:class PhotoSelectResult { /** * The uris for the selected files. * * @type { Array<string> } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @since 10 */ /** * The uris for the selected files. * * @type { Array<string> } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @atomicservice * @since 11 */ /** * The uris for the selected files. * * @type { Array<string> } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @crossplatform * @atomicservice * @since 12 */ photoUris: Array<string>; /** * Original option. * * @type { boolean } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @since 10 */ /** * Original option. * * @type { boolean } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @atomicservice * @since 11 */ /** * Original option. * * @type { boolean } * @syscap SystemCapability.FileManagement.PhotoAccessHelper.Core * @crossplatform * @atomicservice * @since 12 */ isOriginalPhoto: boolean; } 获取到资源后,通常需要进行以下处理:使用文件 URI 读取文件内容进行必要的格式转换(如压缩图片)上传到服务器或保存到本地// 这里以oss上传为例 // uri为选择图片路径 import { http } from '@kit.NetworkKit'; import fs from '@ohos.file.fs' import { request } from '@kit.BasicServicesKit'; export async function upload (uri: string): Promise<string> { // 此处从服务器获取 const data = { policy: 'qweqwe', signature: 'qweqwe', ossAccessKeyId: 'qweqwe', host: 'https://???/api', }; const name = Date.now() + '.' + uri.split('.').pop(); const key = `${new Date().getFullYear()}/${name}` const context = getContext(); // 通过getContext获取沙箱地址 const destPath = `${context.cacheDir}/${name}`; const file = fs.openSync(uri); // 将文件复制一份到沙箱缓存地址,这一步尤为重要,只有沙箱地址的文件可以进行上传操作 fs.copyFileSync(file.fd, destPath); const result = await request.uploadFile(context,{ // files字段是上传的文件组成的列表,类型为formData files: [{ filename: 'file', name: 'file', uri: `internal://cache/${name}`, type: 'image/jpeg' }], // data字段是携带的参数,建议把类型设置为formData data: [ { name: 'name', value: `${name}`, }, { name: 'policy', value: `${data.policy}` }, { name: 'OSSAccessKeyId', value: Object.values(data)[2] }, { name: 'signature', value: `${data.signature}` }, { name: 'key', value: key }, ], method: http.RequestMethod.POST, header: { Accept: '*/*', // 设置header确保参数类型为FormData "Content-Type": "multipart/form-data" }, // 请求地址 url: data.host }); return new Promise((res, rej) => { result.on('progress', (u, t) => { console.log('进度', u / t); }); result.on('complete', e => { console.log('ok', JSON.stringify(e)); res(`${data.host + key}`); }); result.on('fail', e => { console.log('错误', JSON.stringify(e)); rej(e); }) }); } 五、注意事项与常见问题权限要求 需要在 config.json 中声明文件访问权限:{ "requestPermissions": [ { "name": "ohos.permission.READ_MEDIA", "reason": "需要访问媒体文件" } ] } 文件处理注意系统媒体库中的文件 URI 通常是临时的,建议复制到应用私有目录再使用const name = Date.now() + ""; const key = `${new Date().toLocaleDateString()}/${name}`; const context = getContext(); const destPath = `${context.cacheDir}/${name}`; const file = fileIo.openSync(uri); fileIo.copyFileSync(file.fd, destPath); console.log(destPath); 大文件处理时建议进行异步操作,避免 UI 卡顿request.uploadFile文件上传时候一直报错 401兼容性注意:不同鸿蒙版本的 API 可能存在差异,建议在开发前查阅对应版本的官方文档部分参数(如 title、initialDirectory)可能只在特定版本中支持通过合理配置 PhotoViewPicker 的各项参数,开发者可以轻松实现符合需求的媒体选择功能,为应用增色不少。
-
贡献 OpenHarmony 库关键配置 #自研框架#ArkUI-X#三方框架#OpenHarmony#HarmonyOS创建第三方库打开 DevEco Studio 创建一个项目,然后创建一个库模块,选择 static library。详细步骤可参考:开发静态共享包。在项目内会生成 library 文件夹对所创建的库模块进行开发,需要完善库模块中生成的 oh-package.json5 文件,有关三方库名称的规则,请参阅三方库名称指南章节,其他配置项的设置请参考 oh-package.json5 配置说明。目录分析 library // HAR根目录 ├─libs // 存放用户自定义引用的Native库,一般为.so文件f └─src │ └─main │ ├─cpp │ │ ├─types // 定义Native API对外暴露的接口 │ │ │ └─liblibrary │ │ │ ├─index.d.ts │ │ │ └─oh-package.json5 │ │ ├─CMakeLists.txt // CMake配置文件 │ │ └─napi_init.cpp // C++源码文件 │ └─ets // ArkTS源码目录 │ │ └─components │ │ └─MainPage.ets │ ├─resources // 资源目录,用于存放资源文件,如图片、多媒体、字符串等 │ └─module.json5 // 模块配置文件,包含当前HAR的配置信息 ├─build-profile.json5 // Hvigor编译构建所需的配置文件,包含编译选项 ├─hvigorfile.ts // Hvigor构建脚本文件,包含构建当前模块的插件、自定义任务等 ├─Index.ets // HAR的入口文件,一般作为出口定义HAR对外提供的函数、组件等 └─oh-package.json5 // HAR的描述文件,定义HAR的基本信息、依赖项等 library/build-profile.json5 建议开启代码混淆{ "apiType": "stageMode", "buildOption": {}, "buildOptionSet": [ { "name": "release", "arkOptions": { // 混淆相关参数 "obfuscation": { "ruleOptions": { // true表示进行混淆,false表示不进行混淆。5.0.3.600及以上版本默认为false "enable": true, // 混淆规则文件 "files": ["./obfuscation-rules.txt"] }, // consumerFiles中指定的混淆配置文件会在构建依赖这个library的工程或library时被应用 "consumerFiles": ["./consumer-rules.txt"] } } } ], "targets": [ { "name": "default" } ] } build-profile.json5 设置 useNormalizedOHMUrl{ "app": { "products": [ { "buildOption": { "strictMode": { "useNormalizedOHMUrl": false } } } ] } } 在库模块的根目录中,创建一个 README.md(不区分大小写) 文件,描述您三方库的代码以及如何使用它,文件不能为空。README.md 模板# feilongui FeilongUI 是一款功能丰富、高效易用的 UI 库,旨在帮助开发者快速构建美观、交互流畅的用户界面。以下是该库的详细使用指南。 ## 安装命令 README.md 中未包含安装命令会导致审核失败 `ohpm install feilongui` ## 模块介绍 README.md 中缺少简要的三方库使用说明会导致审核失败没有文件会报错ohpm ERROR: HttpCode 400 The OHPM package must contain a non-empty readme.md file. ohpm ERROR: Publish failed, detail: The "Publish" request to url "https://ohpm.openharmony.cn/ohpm/feilongui" has failed在库模块的根目录中,创建一个 CHANGELOG.md 文件,描述您三方库的代码不同版本的变更内容,文件不能为空。没有文件会报错ohpm ERROR: HttpCode 400 The OHPM package must contain a non-empty changelog.md file. ohpm ERROR: Publish failed, detail: The "Publish" request to url "https://ohpm.openharmony.cn/ohpm/feilongui" has failedChangelog.md模板(CHANGELOG.md中未包含当前版本,也就是oh-package.json5中version值的版本。 CHANGELOG.md由清晰的版本号和该版本的修改内容组成,修改内容不可为空,不然过不了审核)# Changelog ## 1.0.0 \*\* Unreleased Added - 新增 [按钮],用于 [点击]。 Changed - 优化 [模块 / 功能名称] 的性能,提升 [具体指标,如响应速度、加载时间等]。 Deprecated - 标记 [某接口 / 方法 / 功能] 为废弃,计划在 [具体版本] 中移除。 Removed - 移除不再维护的 [某功能 / 模块]。 Fixed - 修复 [问题描述] 导致的 [具体错误,如程序崩溃、数据错误等]。 Security - 修复 [名称] 提升系统安全性。在库模块的根目录中,创建一个 LICENSE(不区分大小写) 文件,指定该软件包可以在什么样的许可下被使用、修改和共享,文件不能为空。许可证模板(LICENSE文件中许可证条款内容和oh-package.json5文件中许可证名称不一致会审核失败) 许可证获取地址Copyright [此处填写年份,如2025] [此处填写在library/oh-package.json5中的name,否则审核失败] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.没有 LICENSE 文件会报错ohpm ERROR: HttpCode 400 The OHPM package must contain a non-empty license file. ohpm ERROR: Publish failed, detail: The "Publish" request to url "https://ohpm.openharmony.cn/ohpm/feilongui" has failed在进行 publish 发布前,请先确保在 OpenHarmony 三方库中心仓上已经创建了帐号,且利用工具 ssh-keygen 生成公、私钥文件ssh-keygen -m PEM -t RSA -b 4096 -f ~/.ssh_ohpm/mykey ohpm config set key_path ~/.ssh_ohpm/mykey不签名发布时会报错ohpm ERROR: Publish failed, detail: The "key_path" is empty - configure "key_path" in the .ohpmrc file.不设置密码发布时会报错ohpm ERROR: Private key without passphrase is not supported. ohpm ERROR: You must config a encrypted private key using a non-empty passphrase. ohpm ERROR: Publish failed, detail: Not supported private key. 不上传公钥(~/.ssh_ohpm/mykey.pub)会报错ohpm ERROR: HttpCode 400 The publicKey verify failed! ohpm ERROR: Publish failed, detail: The "Login" request to url "https://ohpm.openharmony.cn/ohpm/login" has failed设置 publish_id不设置 publish_id 会报错ohpm ERROR: Publish failed, detail: The "publish_id" is empty - configure "publish_id" in .ohpmrc file.publish_id 设置错误会报错ohpm ERROR: HttpCode 400 The publishId is invalid! ohpm ERROR: Publish failed, detail: The "Login" request to url "https://ohpm.openharmony.cn/ohpm/login" has failed发布后再发布不更新版本号会报错ohpm ERROR: HttpCode 400 The OHPM package version already exists. ohpm ERROR: Publish failed, detail: The "Publish" request to url "https://ohpm.openharmony.cn/ohpm/feilongui" has failed利用 DevEco Studio 对开发后的库模块打成 HAR 包。( 详情请见:构建 HAR)在工具中构建 library 库时需要选中 library 文件夹内的文件构建后所在目录为library/build/default/outputs/default/library-signed.har后续发布需要使用这个路径
-
DevEcoStudio 中使用模拟器时如何过滤日志 #鸿蒙核心技术#鸿蒙开发者工具##DevEcoStudio在 Hilog > Settings > Filter 设置Log message: A03d00/JSAPP当你看到不断更新的日志时,你会不会崩溃因为 No-filters 模式下模拟器会输出系统所有日志信息,这个模式在开发中并不使用,可用自定义模式找到模拟器日志,选择自定义在 Filter name 中输入custom (可以忽略这一步)Log level 中选择Info在 Log message 输入框中输入A03d00/JSAPP(打印内容)操作后在控制台查看就行了其他日志内容类型启动相关日志:记录模拟器启动过程中的各种信息,如加载系统镜像、初始化硬件设备、配置网络等操作的结果和状态。如果模拟器启动失败,这里会包含导致失败的具体原因,例如端口冲突、虚拟机管理程序未启用或配置错误、权限不足等。系统运行日志:包含模拟器系统运行时的各种事件和状态信息,如进程的启动和停止、系统服务的运行情况、内存和 CPU 的使用统计等。这些信息有助于开发者了解模拟器的整体运行状况,判断是否存在资源瓶颈或系统异常。应用相关日志:当在模拟器中运行应用程序时,会记录应用的启动、暂停、恢复、销毁等生命周期事件,以及应用中发生的各种错误、警告和调试信息。这对于开发者调试应用在模拟器上的运行问题非常重要,可以帮助定位应用中的代码错误、资源泄漏等问题。硬件模拟日志:模拟器需要模拟设备的硬件功能,如屏幕、摄像头、传感器等。相关日志会记录硬件模拟的操作和状态,例如屏幕分辨率的设置、摄像头的调用情况、传感器数据的模拟等。如果应用依赖于特定的硬件功能,这些日志可以帮助确定硬件模拟是否正常工作,以及应用与模拟硬件的交互是否正确。日志级别DEBUG:调试级别日志,通常包含详细的调试信息,用于开发者在开发过程中深入了解程序的执行流程和变量状态等。在正式发布版本中默认不被打印,只有在调试版本或打开调试开关的情况下才会打印。INFO:信息级别日志,用于记录程序运行中的重要信息,如系统启动、模块加载、关键操作的执行等,有助于开发者了解程序的整体运行情况。WARN:警告级别日志,提示可能存在的问题或潜在的风险,如资源使用接近上限、不推荐的操作被执行等,但并不一定表示程序出现了错误。ERROR:错误级别日志,用于记录程序中发生的错误情况,如代码异常、文件读取失败、网络连接中断等,这些错误可能会导致程序的部分功能无法正常运行。FATAL:严重错误级别日志,通常表示程序出现了严重的错误,导致整个系统或关键功能无法继续运行,如系统崩溃、内存耗尽等。
-
CodeArts IDE 鸿蒙版本功能是否完整?鸿蒙系统终端是否有命令教程?
上滑加载中
推荐直播
-
华为云码道-玩转OpenClaw,在线养虾2026/03/11 周三 19:00-21:00
刘昱,华为云高级工程师/谈心,华为云技术专家/李海仑,上海圭卓智能科技有限公司CEO
OpenClaw 火爆开发者圈,华为云码道最新推出 Skill ——开发者只需输入一句口令,即可部署一个功能完整的「小龙虾」智能体。直播带你玩转华为云码道,玩转OpenClaw
回顾中 -
华为云码道-AI时代应用开发利器2026/03/18 周三 19:00-20:00
童得力,华为云开发者生态运营总监/姚圣伟,华为云HCDE开发者专家
本次直播由华为专家带你实战应用开发,看华为云码道(CodeArts)代码智能体如何在AI时代让你的创意应用快速落地。更有华为云HCDE开发者专家带你用码道玩转JiuwenClaw,让小艺成为你的AI助理。
回顾中 -
Skill 构建 × 智能创作:基于华为云码道的 AI 内容生产提效方案2026/03/25 周三 19:00-20:00
余伟,华为云软件研发工程师/万邵业(万少),华为云HCDE开发者专家
本次直播带来两大实战:华为云码道 Skill-Creator 手把手搭建专属知识库 Skill;如何用码道提效 OpenClaw 小说文本,打造从大纲到成稿的 AI 原创小说全链路。技术干货 + OPC创作思路,一次讲透!
回顾中
热门标签