使用HarmonyOS实现图片编辑,裁剪、旋转、亮度、透明度 ...

打印 上一主题 下一主题

主题 1017|帖子 1017|积分 3051

先容

本篇Codelab是基于ArkTS的声明式开发范式的样例,主要先容了图片编辑实现过程。样例主要包含以下功能:

  • 图片的解码。
  • 使用PixelMap进行图片编辑,如裁剪、旋转、亮度、透明度、饱和度等。
  • 图片的编码。

相干概念



  • 图片解码:读取差别格式的图片文件,无压缩的解码为位图格式。
  • PixelMap:图片解码后的状态,用于对图片像素进行处理惩罚。
  • 图片编码:图片颠末像素处理惩罚完成之后,须要重新进行编码打包,生成须要的图片格式。
环境搭建

软件要求



  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。
硬件要求



  • 开发板范例:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。
环境搭建

完本钱篇Codelab我们起首要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步调进行:

  • 获取OpenHarmony系统版本:标准系统办理方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  • 完成DevEco Device Tool的安装
  • 完成RK3568开发板的烧录
3.搭建开发环境。

  • 开始前请参考工具准备,完成DevEco Studio的安装和开发环境设置。
  • 开发环境设置完成后,请参考使用工程领导创建工程(模板选择“Empty Ability”)。
  • 工程创建完成后,选择使用真机进行调测。
代码结构解读

本篇Codelab只对核心代码进行讲解。
  1. ├──entry/src/main/ets                            // 代码区
  2. │  ├──common                        
  3. │  │  └──constant
  4. │  │     └──CommonConstant.ets                   // 常量类
  5. │  ├──entryability
  6. │  │  └──EntryAbility.ts                         // 本地启动ability           
  7. │  ├──pages
  8. │  │  └──HomePage.ets                            // 本地主页面   
  9. │  ├──utils
  10. │  │  ├──AdjustUtil.ets                          // 调节工具类
  11. │  │  ├──CropUtil.ets                            // 裁剪工具类
  12. │  │  ├──DecodeUtil.ets                          // 解码工具类
  13. │  │  ├──DrawingUtils.ets                        // Canvas画图工具类
  14. │  │  ├──EncodeUtil.ets                          // 编码工具类
  15. │  │  ├──LoggerUtil.ets                          // 日志工具类
  16. │  │  ├──MathUtils.ets                           // 坐标转换工具类
  17. │  │  └──OpacityUtil.ets                         // 透明度调节工具类
  18. │  ├──view
  19. │  │  ├──AdjustContentView.ets                   // 色域调整视图     
  20. │  │  └──ImageSelect.ets                         // Canvas选择框实现类   
  21. │  ├──viewmodel
  22. │  │  ├──CropShow.ets                            // 选择框显示控制类
  23. │  │  ├──CropType.ets                            // 按比例选取图片
  24. │  │  ├──IconListViewModel.ets                   // icon数据
  25. │  │  ├──ImageEditCrop.ets                       // 图片编辑操作类
  26. │  │  ├──ImageFilterCrop.ets                     // 图片操作收集类
  27. │  │  ├──ImageSizeItem.ets                       // 图片尺寸
  28. │  │  ├──Line.ets                                // 线封装类
  29. │  │  ├──MessageItem.ets                         // 多线程封装消息
  30. │  │  ├──OptionViewModel.ets                     // 图片处理封装类
  31. │  │  ├──PixelMapWrapper.ets                     // PixelMap封装类
  32. │  │  ├──Point.ets                               // 点封装类
  33. │  │  ├──Ratio.ets                               // 比例封装类
  34. │  │  ├──Rect.ets                                // 矩形封装类
  35. │  │  ├──RegionItem.ets                          // 区域封装类
  36. │  │  └──ScreenManager.ts                        // 屏幕尺寸计算工具类
  37. │  └──workers
  38. │     ├──AdjustBrightnessWork.ts                 // 亮度异步调节
  39. │     └──AdjustSaturationWork.ts                 // 饱和度异步调节
  40. └──entry/src/main/resources                      // 资源文件目录
复制代码
图片解码

在这个章节中,须要完成图片解码的利用,并将解码后的图片展示。效果如图所示:

在进行图片编辑前须要先加载图片,当前文档是在生命周期aboutToAppear开始加载。具体实现步调。

  • 读取资源文件。
  • 将获取的fd创建成图片实例,通过实例获取其pixelMap。
  • 将解析好的pixelMap通过Image组件加载表现。
  1. // HomePage.ets
  2. aboutToAppear() {
  3.   this.pixelInit();
  4.   ...
  5. }
  6. build() {
  7.   Column() {
  8.     ...
  9.     Column() {
  10.       if (this.isCrop && this.showCanvas && this.statusBar > 0) {
  11.         if (this.isSaveFresh) {
  12.           ImageSelect({
  13.             statusBar: this.statusBar
  14.           })
  15.         }
  16.         ...
  17.       } else {
  18.         if (this.isPixelMapChange) {
  19.           Image(this.pixelMap)
  20.             .scale({ x: this.imageScale, y: this.imageScale, z: 1 })
  21.             .objectFit(ImageFit.None)
  22.         }
  23.         ...
  24.       }
  25.     }
  26.     ...
  27.   }
  28.   ...
  29. }
  30. async getResourceFd(filename: string) {
  31.   const resourceMgr = getContext(this).resourceManager;
  32.   const context = getContext(this);
  33.   if (filename === CommonConstants.RAW_FILE_NAME) {
  34.     let imageBuffer = await resourceMgr.getMediaContent($r("app.media.ic_low"))
  35.     let filePath = context.cacheDir + '/' + filename;
  36.     let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  37.     let writeLen = fs.writeSync(file.fd, imageBuffer.buffer);
  38.     fs.copyFileSync(filePath, context.cacheDir + '/' + CommonConstants.RAW_FILE_NAME_TEST);
  39.     return file.fd;
  40.   } else {
  41.     let filePath = context.cacheDir + '/' + filename;
  42.     let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  43.     return file.fd;
  44.   }
  45. }
  46. async getPixelMap(fileName: string) {
  47.   const fd = await this.getResourceFd(fileName);
  48.   const imageSourceApi = image.createImageSource(fd);
  49.   if (!imageSourceApi) {
  50.     Logger.error(TAG, 'imageSourceAPI created failed!');
  51.     return;
  52.   }
  53.   const pixelMap = await imageSourceApi.createPixelMap({
  54.     editable: true
  55.   });
  56.   return pixelMap;
  57. }
复制代码
图片处理惩罚

当前章节须要完成图片的裁剪、旋转、色域调节(本章只先容亮度、透明度、饱和度)等功能。


  • 裁剪:选取图片中的部分进行裁剪生成新的图片。
  • 旋转:将图片按照差别的角度进行旋转,生成新的图片。
  • 色域调节:当前Codelab色域调节的亮度、透明度和饱和度,使用色域模型RGB-HSV来实现的。RGB:是我们接触最多的颜色空间,分别为红色(R),绿色(G)和蓝色(B)。HSV:是用色相H,饱和度S,明亮度V来形貌颜色的变化。H:色相H取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。S:饱和度S越高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。V:明度V表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。
  1. // AdjustUtil.ets
  2. // rgb转hsv
  3. function rgb2hsv(red: number, green: number, blue: number) {
  4.   let hsvH: number = 0, hsvS: number = 0, hsvV: number = 0;
  5.   const rgbR: number = colorTransform(red);
  6.   const rgbG: number = colorTransform(green);
  7.   const rgbB: number = colorTransform(blue);
  8.   const maxValue = Math.max(rgbR, Math.max(rgbG, rgbB));
  9.   const minValue = Math.min(rgbR, Math.min(rgbG, rgbB));
  10.   hsvV = maxValue * CommonConstants.CONVERT_INT;
  11.   if (maxValue === 0) {
  12.     hsvS = 0;
  13.   } else {
  14.     hsvS = Number((1 - minValue / maxValue).toFixed(CommonConstants.DECIMAL_TWO)) * CommonConstants.CONVERT_INT;
  15.   }
  16.   if (maxValue === minValue) {
  17.     hsvH = 0;
  18.   }
  19.   if (maxValue === rgbR && rgbG >= rgbB) {
  20.     hsvH = Math.floor(CommonConstants.ANGLE_60 * ((rgbG - rgbB) / (maxValue - minValue)));
  21.   }
  22.   if (maxValue === rgbR && rgbG < rgbB) {
  23.     hsvH = Math.floor(CommonConstants.ANGLE_60 * ((rgbG - rgbB) / (maxValue - minValue)) + CommonConstants.ANGLE_360);
  24.   }
  25.   if (maxValue === rgbG) {
  26.     hsvH = Math.floor(CommonConstants.ANGLE_60 * ((rgbB - rgbR) / (maxValue - minValue)) + CommonConstants.ANGLE_120);
  27.   }
  28.   if (maxValue === rgbB) {
  29.     hsvH = Math.floor(CommonConstants.ANGLE_60 * ((rgbR - rgbG) / (maxValue - minValue)) + CommonConstants.ANGLE_240);
  30.   }
  31.   return [hsvH, hsvS, hsvV];
  32. }
  33. // hsv转rgb
  34. function hsv2rgb(hue: number, saturation: number, value: number) {
  35.   let rgbR: number = 0, rgbG: number = 0, rgbB: number = 0;
  36.   if (saturation === 0) {
  37.     rgbR = rgbG = rgbB = Math.round((value * CommonConstants.COLOR_LEVEL_MAX) / CommonConstants.CONVERT_INT);
  38.     return { rgbR, rgbG, rgbB };
  39.   }
  40.   const cxmC = (value * saturation) / (CommonConstants.CONVERT_INT * CommonConstants.CONVERT_INT);
  41.   const cxmX = cxmC * (1 - Math.abs((hue / CommonConstants.ANGLE_60) % CommonConstants.MOD_2 - 1));
  42.   const cxmM = (value - cxmC * CommonConstants.CONVERT_INT) / CommonConstants.CONVERT_INT;
  43.   const hsvHRange = Math.floor(hue / CommonConstants.ANGLE_60);
  44.   switch (hsvHRange) {
  45.     case AngelRange.ANGEL_0_60:
  46.       rgbR = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  47.       rgbG = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  48.       rgbB = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  49.       break;
  50.     case AngelRange.ANGEL_60_120:
  51.       rgbR = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  52.       rgbG = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  53.       rgbB = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  54.       break;
  55.     case AngelRange.ANGEL_120_180:
  56.       rgbR = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  57.       rgbG = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  58.       rgbB = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  59.       break;
  60.     case AngelRange.ANGEL_180_240:
  61.       rgbR = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  62.       rgbG = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  63.       rgbB = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  64.       break;
  65.     case AngelRange.ANGEL_240_300:
  66.       rgbR = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  67.       rgbG = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  68.       rgbB = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  69.       break;
  70.     case AngelRange.ANGEL_300_360:
  71.       rgbR = (cxmC + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  72.       rgbG = (0 + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  73.       rgbB = (cxmX + cxmM) * CommonConstants.COLOR_LEVEL_MAX;
  74.       break;
  75.     default:
  76.       break;
  77.   }
  78.   return [
  79.     Math.round(rgbR),
  80.     Math.round(rgbG),
  81.     Math.round(rgbB)
  82.   ];
  83. }
复制代码
图片裁剪


  • 通过pixelMap获取图片尺寸,为后续裁剪做准备。
  • 确定裁剪的方式,当前裁剪默认有自由选取、1:1选取、4:3选取、16:9选取。
  • 通过pixelMap调用接口crop()进行裁剪利用。
说明: 当前裁剪功能采用pixelMap裁剪能力直接做切割,会有叠加效果,后续会通过增加选取框对当前功能进行优化。

  1. // HomePage.ets
  2. cropImage(index: CropType) {
  3.   this.currentCropIndex = index;
  4.   switch (this.currentCropIndex) {
  5.     case CropType.ORIGINAL_IMAGE:
  6.       this.cropRatio = CropRatioType.RATIO_TYPE_FREE;
  7.       break;
  8.     case CropType.SQUARE:
  9.       this.cropRatio = CropRatioType.RATIO_TYPE_1_1;
  10.       break;
  11.     case CropType.BANNER:
  12.       this.cropRatio = CropRatioType.RATIO_TYPE_4_3;
  13.       break;
  14.     case CropType.RECTANGLE:
  15.       this.cropRatio = CropRatioType.RATIO_TYPE_16_9;
  16.       break;
  17.     default:
  18.       this.cropRatio = CropRatioType.RATIO_TYPE_FREE;
  19.       break;
  20.   }
  21. }
  22. // ImageFilterCrop.ets
  23. cropImage(pixelMap: PixelMapWrapper, realCropRect: RectF, callback: () => void) {
  24.   let offWidth = realCropRect.getWidth();
  25.   let offHeight = realCropRect.getHeight();
  26.   if (pixelMap.pixelMap!== undefined) {
  27.     pixelMap.pixelMap.crop({
  28.       size:{ height: vp2px(offHeight), width: vp2px(offWidth) },
  29.       x: vp2px(realCropRect.left),
  30.       y: vp2px(realCropRect.top)
  31.     }, callback);
  32.   }
  33. }
复制代码
图片旋转


  • 确定旋转方向,当前支持顺时针和逆时针旋转。
  • 通过pixelMap调用接口rotate()进行旋转利用。

  1. // HomePage.ets
  2. rotateImage(rotateType: RotateType) {
  3.   if (rotateType === RotateType.CLOCKWISE) {
  4.     try {
  5.       if (this.pixelMap !== undefined) {
  6.         this.pixelMap.rotate(CommonConstants.CLOCK_WISE)
  7.           .then(() => {
  8.             this.flushPixelMapNew();
  9.           })
  10.       }
  11.     } catch (error) {
  12.       Logger.error(TAG, `there is a error in rotate process with ${error?.code}`);
  13.     }
  14.   }
  15.   if (rotateType === RotateType.ANTI_CLOCK) {
  16.     try {
  17.       if (this.pixelMap !== undefined) {
  18.         this.pixelMap.rotate(CommonConstants.ANTI_CLOCK)
  19.           .then(() => {
  20.             this.flushPixelMapNew();
  21.           })
  22.       }
  23.     } catch (error) {
  24.       Logger.error(TAG, `there is a error in rotate process with ${error?.code}`);
  25.     }
  26.   }
  27. }
复制代码
亮度调节


  • 将pixelMap转换成ArrayBuffer。
  • 将生成好的ArrayBuffer发送到worker线程。
  • 对每一个像素点的亮度值按倍率计算。
  • 将计算好的ArrayBuffer发送回主线程。
  • 将ArrayBuffer写入pixelMap,刷新UI。
说明: 当前亮度调节是在UI层面实现的,未实现细节优化算法,只做简单示例。调节后的图片会有色彩上的失真。

  1. // AdjustContentView.ets
  2. // 转化成pixelMap及发送buffer到worker,返回数据刷新ui
  3. postToWorker(type: AdjustId, value: number, workerName: string) {
  4.   let sliderValue = type === AdjustId.BRIGHTNESS ? this.brightnessLastSlider : this.saturationLastSlider;
  5.   try {
  6.     let workerInstance = new worker.ThreadWorker(workerName);
  7.     const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber());
  8.     this.pixelMap.readPixelsToBuffer(bufferArray).then(() => {
  9.       let message = new MessageItem(bufferArray, sliderValue, value);
  10.       workerInstance.postMessage(message);
  11.       if (this.postState) {
  12.         this.deviceListDialogController.open();
  13.       }
  14.       this.postState = false;
  15.       workerInstance.onmessage = (event: MessageEvents) => {
  16.         this.updatePixelMap(event)
  17.       };
  18.       if (type === AdjustId.BRIGHTNESS) {
  19.         this.brightnessLastSlider = Math.round(value);
  20.       } else {
  21.         this.saturationLastSlider = Math.round(value);
  22.       }
  23.       workerInstance.onexit = () => {
  24.         if (workerInstance !== undefined) {
  25.           workerInstance.terminate();
  26.         }
  27.       }
  28.     });
  29.   } catch (error) {
  30.     Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`)
  31.   }
  32. }
  33. // AdjustBrightnessWork.ts
  34. // worker线程处理部分
  35. workerPort.onmessage = function(event : MessageEvents) {
  36.   let bufferArray = event.data.buf;
  37.   let last = event.data.last;
  38.   let cur = event.data.cur;
  39.   let buffer = adjustImageValue(bufferArray, last, cur);
  40.   workerPort.postMessage(buffer);
  41.   workerPort.close();
  42. }
  43. // AdjustUtil.ets
  44. // 倍率计算部分
  45. export function adjustImageValue(bufferArray: ArrayBuffer, last: number, cur: number) {
  46.   return execColorInfo(bufferArray, last, cur, HSVIndex.VALUE);
  47. }
复制代码
透明度调节


  • 获取pixelMap。
  • 调用接口opacity()进行透明度调节。

  1. // OpacityUtil.ets
  2. export async function adjustOpacity(pixelMap: PixelMap, value: number) {
  3.   if (!pixelMap) {
  4.     return;
  5.   }
  6.   const newPixelMap = pixelMap;
  7.   await newPixelMap.opacity(value / CommonConstants.SLIDER_MAX);
  8.   return newPixelMap;
  9. }
复制代码
饱和度调节


  • 将pixelMap转换成ArrayBuffer。
  • 将生成好的ArrayBuffer发送到worker线程。
  • 对每一个像素点的饱和度按倍率计算。
  • 将计算好的ArrayBuffer发送回主线程。
  • 将ArrayBuffer写入pixelMap,刷新UI。
说明: 当前饱和度调节是在UI层面实现的,未实现细节优化算法,只做简单示例。调节后的图片会有色彩上的失真。

  1. // AdjustContentView.ets
  2. // 转化成pixelMap及发送buffer到worker,返回数据刷新ui
  3. postToWorker(type: AdjustId, value: number, workerName: string) {
  4.   let sliderValue = type === AdjustId.BRIGHTNESS ? this.brightnessLastSlider : this.saturationLastSlider;
  5.   try {
  6.     let workerInstance = new worker.ThreadWorker(workerName);
  7.     const bufferArray = new ArrayBuffer(this.pixelMap.getPixelBytesNumber());
  8.     this.pixelMap.readPixelsToBuffer(bufferArray).then(() => {
  9.       let message = new MessageItem(bufferArray, sliderValue, value);
  10.       workerInstance.postMessage(message);
  11.       if (this.postState) {
  12.         this.deviceListDialogController.open();
  13.       }
  14.       this.postState = false;
  15.       workerInstance.onmessage = (event: MessageEvents) => {
  16.         this.updatePixelMap(event)
  17.       };
  18.       if (type === AdjustId.BRIGHTNESS) {
  19.         this.brightnessLastSlider = Math.round(value);
  20.       } else {
  21.         this.saturationLastSlider = Math.round(value);
  22.       }
  23.       workerInstance.onexit = () => {
  24.         if (workerInstance !== undefined) {
  25.           workerInstance.terminate();
  26.         }
  27.       }
  28.     });
  29.   } catch (error) {
  30.     Logger.error(`Create work instance fail, error message: ${JSON.stringify(error)}`);
  31.   }
  32. }
  33. // AdjustSaturationWork.ts
  34. // worker线程处理部分
  35. workerPort.onmessage = function(event : MessageEvents) {
  36.   let bufferArray = event.data.buf;
  37.   let last = event.data.last;
  38.   let cur = event.data.cur;
  39.   let buffer = adjustSaturation(bufferArray, last, cur)
  40.   workerPort.postMessage(buffer);
  41.   workerPort.close();
  42. }
  43. // AdjustUtil.ets
  44. // 倍率计算部分
  45. export function adjustSaturation(bufferArray: ArrayBuffer, last: number, cur: number) {
  46.   return execColorInfo(bufferArray, last, cur, HSVIndex.SATURATION);
  47. }
复制代码
图片编码

图片位图颠末处理惩罚之后,还是属于解码的状态,还须要进行打包编码成对应的格式,本章讲解编码的具体过程。

  • 通过image组件创建打包工具packer。
  • 使用PackingOption进行打包参数设定,比如格式、压缩质量等。
  • 打包成图片信息数据imageData。
  • 创建媒体库media,获取公共路径。
  • 创建媒体文件asset,获取其fd。
  • 使用fs将打包好的图片数据写入到媒体文件asset中。
  1. // ImageSelect.ets
  2. async encode(pixelMap: PixelMap | undefined) {
  3.   if (pixelMap === undefined) {
  4.     return;
  5.   }
  6.   const newPixelMap = pixelMap;
  7.   // 打包图片
  8.   const imagePackerApi = image.createImagePacker();
  9.   const packOptions: image.PackingOption = {
  10.     format: CommonConstants.ENCODE_FORMAT,
  11.     quality: CommonConstants.ENCODE_QUALITY
  12.   }
  13.   const imageData = await imagePackerApi.packing(newPixelMap, packOptions);
  14.   Logger.info(TAG, `imageData's length is ${imageData.byteLength}`);
  15.   // 获取相册路径
  16.   const context = getContext(this);
  17.   const media = mediaLibrary.getMediaLibrary(context);
  18.   const publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE);
  19.   const currentTime = new Date().getTime();
  20.   // 创建图片资源
  21.   const imageAssetInfo = await media.createAsset(
  22.     mediaLibrary.MediaType.IMAGE,
  23.     `${CommonConstants.IMAGE_PREFIX}_${currentTime}${CommonConstants.IMAGE_FORMAT}`,
  24.     publicPath
  25.   );
  26.   const imageFd = await imageAssetInfo.open(CommonConstants.ENCODE_FILE_PERMISSION);
  27.   await fs.write(imageFd, imageData);
  28.   // 释放资源
  29.   await imageAssetInfo.close(imageFd);
  30.   imagePackerApi.release();
  31.   await media.release();
  32. }
复制代码
总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  • 使用image库进行图片的解码。
  • 使用pixelMap进行图片处理惩罚(旋转、裁剪、亮度、透明度、饱和度等)。
  • 使用image库进行图片的编码。
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完备版方式请点击→《HarmonyOS讲授视频
HarmonyOS讲授视频:语法ArkTS、TypeScript、ArkUI等…视频教程




鸿蒙生态应用开发白皮书V2.0PDF:

获取完备版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  • 应用开发导读(ArkTS)
  • .……


二、HarmonyOS 概念

  • 系统定义
  • 技术架构
  • 技术特性
  • 系统安全


三、如何快速入门?《鸿蒙底子入门学习指南》

  • 基本概念
  • 构建第一个ArkTS应用
  • .……


四、开发底子知识

  • 应用底子知识
  • 设置文件
  • 应用数据管理
  • 应用安全管理
  • 应用隐私保护
  • 三方应用调用管控机制
  • 资源分类与访问
  • 学习ArkTS语言
  • .……


五、基于ArkTS 开发

  • Ability开发
  • UI开发
  • 公共变乱与通知
  • 窗口管理
  • 媒体
  • 安全
  • 7.网络与链接
  • 电话服务
  • 数据管理
  • 后台使命(Background Task)管理
  • 装备管理
  • 装备使用信息统计
  • DFX
  • 国际化开发
  • 折叠屏系列
  • .……


更多了解更多鸿蒙开发的相干知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表