### Install Third-Party Library Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md Use 'make install' to install the compiled library files to the specified prefix directory. This includes headers, libraries, and executables. ```bash owner@ubuntu:/mnt/e/configure/jpeg-9e$ make install make[1]: Entering directory '/mnt/e/configure/jpeg-9e' /usr/bin/mkdir -p '/mnt/e/configure/jpeg-9e/jpeg/lib' /bin/bash ./libtool --mode=install /usr/bin/install -c libjpeg.la '/mnt/e/configure/jpeg-9e/jpeg/lib' libtool: install: /usr/bin/install -c .libs/libjpeg.so.9.5.0 /mnt/e/configure/jpeg-9e/jpeg/lib/libjpeg.so.9.5.0 ... # 省略部分make install信息 ... libtool: install: /usr/bin/install -c wrjpgcom /mnt/e/configure/jpeg-9e/jpeg/bin/wrjpgcom /bin/bash /mnt/e/configure/jpeg-9e/install-sh -d /mnt/e/configure/jpeg-9e/jpeg/include /usr/bin/install -c -m 644 jconfig.h /mnt/e/configure/jpeg-9e/jpeg/include/jconfig.h /usr/bin/mkdir -p '/mnt/e/configure/jpeg-9e/jpeg/include' /usr/bin/install -c -m 644 jerror.h jmorecfg.h jpeglib.h '/mnt/e/configure/jpeg-9e/jpeg/include' /usr/bin/mkdir -p '/mnt/e/configure/jpeg-9e/jpeg/share/man/man1' /usr/bin/install -c -m 644 cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1 '/mnt/e/configure/jpeg-9e/jpeg/share/man/man1' /usr/bin/mkdir -p '/mnt/e/configure/jpeg-9e/jpeg/lib/pkgconfig' /usr/bin/install -c -m 644 libjpeg.pc '/mnt/e/configure/jpeg-9e/jpeg/lib/pkgconfig' ``` -------------------------------- ### Verify Installed Library Files Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md Navigate to the installation directory and use 'ls' and 'file' commands to verify the presence and type of installed library files. ```bash owner@ubuntu:/mnt/e/configure/jpeg-9e$ cd xxx/jpeg owner@ubuntu:/mnt/e/configure/jpeg-9e/jpeg$ ls bin include lib share owner@ubuntu:/mnt/e/configure/jpeg-9e/jpeg$ ls lib libjpeg.a libjpeg.la libjpeg.so libjpeg.so.9 libjpeg.so.9.5.0 pkgconfig owner@ubuntu:/mnt/e/configure/jpeg-9e/jpeg$ ls include/ jconfig.h jerror.h jmorecfg.h jpeglib.h owner@ubuntu:/mnt/e/configure/jpeg-9e/jpeg$ file lib/libjpeg.so.9.5.0 lib/libjpeg.so.9.5.0: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, with debug_info, not stripped ``` -------------------------------- ### Installing Compiled Third-Party Library Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-make-adapts-to-harmonyos.md Execute the 'make install' command with the PREFIX variable set to the desired installation directory. This copies the compiled artifacts to their designated locations. ```bash owner@ubuntu:/mnt/e/make-makefile/bzip2-1.0.6$ make install PREFIX=xxx/bzip/ # 执行make install安装 if ( test ! -d /mnt/e/make-makefile/bzip2-1.0.6/bzip/bin ) ; then mkdir -p /mnt/e/make-makefile/bzip2-1.0.6/bzip/bin ; fi if ( test ! -d /mnt/e/make-makefile/bzip2-1.0.6/bzip/lib ) ; then mkdir -p /mnt/e/make-makefile/bzip2-1.0.6/bzip/lib ; fi if ( test ! -d /mnt/e/make-makefile/bzip2-1.0.6/bzip/man ) ; then mkdir -p /mnt/e/make-makefile/bzip2-1.0.6/bzip/man ; fi if ( test ! -d /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1 ) ; then mkdir -p /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1 ; fi if ( test ! -d /mnt/e/make-makefile/bzip2-1.0.6/bzip/include ) ; then mkdir -p /mnt/e/make-makefile/bzip2-1.0.6/bzip/include ; fi ... # 省略部分make install信息 ... cp -f bzgrep.1 bzmore.1 bzdiff.1 /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1 chmod a+r /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzgrep.1 chmod a+r /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzmore.1 chmod a+r /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzdiff.1 echo ".so man1/bzgrep.1" > /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzegrep.1 echo ".so man1/bzgrep.1" > /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzfgrep.1 echo ".so man1/bzmore.1" > /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzless.1 echo ".so man1/bzdiff.1" > /mnt/e/make-makefile/bzip2-1.0.6/bzip/man/man1/bzcmp.1 owner@ubuntu:/mnt/e/make-makefile/bzip2-1.0.6$ ls xxx/bzip/ # 查看安装文件 bin include lib man ``` -------------------------------- ### Example of Slow Cold Start Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-application-cold-start-optimization.md This code demonstrates a scenario that causes a slow cold start due to a computationally intensive task in the aboutToAppear method. Use this to practice identifying performance bottlenecks. ```typescript const LARGE_NUMBER: number = 200000000; @Entry @Component struct Index { @State message: string = 'Hello World'; aboutToAppear(): void { console.log('aboutToAppear'); this.computeTask(); } computeTask(): void { let count: number = 0; while (count < LARGE_NUMBER) { count++; } } build() { Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) } .width('100%') } .height('100%') } } ``` -------------------------------- ### Execute Configure Command for Cross-Compilation Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md Run the configure script with specific options for cross-compilation. Use --prefix to set the installation directory and --host to specify the target architecture. This example configures for aarch64. ```bash owner@ubuntu:/mnt/e/configure/jpeg-9e$ ./configure --prefix=xxx/jpeg --host=aarch64-linux # 执行configure命令配置交叉编译信息 ``` -------------------------------- ### Inspect Installed Files Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-cmake-adapts-to-harmonyos.md Verify that the installation was successful by checking the contents of the installation directory. This includes the 'include' and 'lib' subdirectories containing the library's headers and binaries. ```bash owner@ubuntu:/mnt/e/cmake/cJSON-1.7.18/build$ ls /mnt/e/cmake/cJSON-1.7.18/cJSON/lib ``` -------------------------------- ### Prepare and Start Casting Media Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-audio-cast.md Prepare and start casting local audio by creating an AVQueueItem with media metadata and file descriptors, then calling prepare() and start() on the AVCAstController. Error handling for file operations is included. ```typescript let playItem: avSession.AVQueueItem; if (this.context && songItem.lyric) { lyricContent = await getRawStringData(this.context, songItem.lyric); } try { let file = await fileIo.open(this.context?.filesDir + '/' + curSrc); let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd }; playItem = { itemId: this.musicIndex, description: { assetId: 'AUDIO-' + JSON.stringify(this.musicIndex), title: songItem.title, artist: songItem.singer, subtitle: 'audio', mediaType: 'AUDIO', albumCoverUri: songItem.albumCoverUri, fdSrc: avFileDescriptor, startPosition: startPosition, duration: AppStorage.get('durationTime'), lyricContent: lyricContent, } }; await this.avCastController?.prepare(playItem); await this.avCastController?.start(playItem); } catch (err) { hilog.error(0x0000, TAG, `open file ${err}`); } ``` -------------------------------- ### Configure and Start Camera Session Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-third-party-camera.md Begin configuring the camera session by adding input and output streams, setting color space, and then committing and starting the session. ```typescript photoSession.beginConfig(); photoSession.addInput(cameraInput); photoSession.addOutput(previewOutput); photoSession.addOutput(photoOutPut); photoSession.setColorSpace(colorSpaceManager.ColorSpace.DISPLAY_P3); await photoSession.commitConfig(); await photoSession.start(); ``` -------------------------------- ### Listen for Window Size Changes Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-landscape-and-portrait-development.md Implement this in `aboutToAppear` to start listening for window size changes. Ensure to handle potential errors during setup. ```typescript aboutToAppear(): void { try { // ... this.windowClass.on('windowSizeChange', (size) => { // ... }) // ... } catch (err) { let error = err as BusinessError; Logger.error(TAG, `aboutToAppear err, error code: ${error.code}, error message: ${error.message}`); } } ``` -------------------------------- ### Install Compiled Library Files Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-cmake-adapts-to-harmonyos.md Execute 'make install' to copy the compiled binary files, header files, and CMake configuration files to the directory specified by CMAKE_INSTALL_PREFIX. ```bash owner@ubuntu:/mnt/e/cmake/cJSON-1.7.18/cJSON/build$ make install ``` -------------------------------- ### Install Lottie Library Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-news_homepage.md Install the Lottie library for OpenHarmony using the ohpm package manager. This is the first step to enable Lottie animations. ```bash ohpm install @ohos/lottie ``` -------------------------------- ### Start Recorder and Encoder Threads Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-audio-video-synchronization.md Initiates the recording process by starting the muxer, video encoder, and creating necessary threads for encoding and capturing audio. Ensure all components are initialized before calling. ```cpp int32_t Recorder::Start() { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(encContext_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); int32_t ret = muxer_->Start(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Muxer start failed"); ret = videoEncoder_->Start(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Encoder start failed"); isStarted_ = true; encOutputThread_ = std::make_unique(&Recorder::EncOutputThread, this); if (encOutputThread_ == nullptr) { AVCODEC_SAMPLE_LOGE("Create thread failed"); StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } if (audioEncContext_) { // Start AudioCapturer audioCapturer_->AudioCapturerStart(); ret = audioEncoder_->Start(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Audio Encoder start failed"); isStarted_ = true; audioEncInputThread_ = std::make_unique(&Recorder::AudioEncInputThread, this); audioEncOutputThread_ = std::make_unique(&Recorder::AudioEncOutputThread, this); if (audioEncInputThread_ == nullptr || audioEncOutputThread_ == nullptr) { AVCODEC_SAMPLE_LOGE("Create thread failed"); StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } if (audioEncContext_ != nullptr) { audioEncContext_->ClearCache(); } } AVCODEC_SAMPLE_LOGI("Succeed"); return AVCODEC_SAMPLE_ERR_OK; } ``` -------------------------------- ### View Configure Help Options Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md Run this command to view all available configuration options for the configure script. This helps in understanding customization possibilities for building libraries. ```bash owner@ubuntu:/mnt/e/configure/jpeg-9e$ ./configure --help # 查看configure配置项 ``` -------------------------------- ### Initialize Player with Sample Information Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-video-render.md Initializes the player with file descriptors, offsets, sizes, and media type. Sets the NativeWindow for native image decoding. ```cpp napi_value PluginRender::StartPlayer(napi_env env, napi_callback_info info) { SampleInfo sampleInfo; size_t argc = 4; napi_value args[4] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); napi_get_value_int32(env, args[0], &sampleInfo.inputFd); napi_get_value_int64(env, args[1], &sampleInfo.inputFileOffset); napi_get_value_int64(env, args[2], &sampleInfo.inputFileSize); size_t length = 0; napi_status status = napi_get_value_string_utf8(env, args[3], nullptr, 0, &length); char* buf = new char[length + 1]; std::memset(buf, 0, length + 1); status = napi_get_value_string_utf8(env, args[3], buf, length + 1, &length); std::string type = buf; PluginRender *render = PluginRender::GetInstance(type); if (render != nullptr) { if (type == "OpenGL") { sampleInfo.window = render->openGLRenderThread_->GetNativeImageWindow(); } else if (type == "Vulkan") { sampleInfo.window = render->vulkanRenderThread_->GetNativeImageWindow(); } else { sampleInfo.window = render->nativeWindow; } } int32_t ret = Player::GetInstance().Init(sampleInfo); if (ret != AVCODEC_SAMPLE_ERR_OK) { return nullptr; } Player::GetInstance().Start(); return nullptr; } ``` -------------------------------- ### HPKBUILD Configuration for OpenSSL (configure build) Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-lycium-adapts-to-harmonyos.md Example HPKBUILD configuration for OpenSSL using the 'configure' build tool. It includes architecture-specific environment setup and defines the 'host' variable required for cross-compilation. ```shell pkgname=openssl # 库名 pkgver=OpenSSL_1_1_1u # 库的版本号 source="https://github.com/openssl/$pkgname/archive/refs/tags/$pkgver.zip" # 库的源码包路径 archs=("armeabi-v7a" "arm64-v8a") # 架构信息 buildtools="configure" # 编译方式为configure builddir=$pkgname-${pkgver} # openssl 源码包解压后的文件夹名 packagename=$builddir.zip # 包名 source envset.sh # 导入envset.sh,envset.sh为环境设置脚本文件,通常包含构建所需的变量和函数,存放于tpc_c_cplusplus/lycium/script目录下 host= # 定义host变量 ``` -------------------------------- ### Configure and Start Camera Session Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-custom-camera-preview.md Use Session.commitConfig() and Session.start() to finalize camera configurations and initiate the preview session. Ensure all necessary outputs are added before committing. ```typescript const session = this.cameraManager?.createSession(sceneMode); session?.beginConfig(); session?.addInput(this.cameraInput); // ... for (const outputManager of this.outputManagers) { if (outputManager.isActive) { const output = await outputManager.createOutput(config); session?.addOutput(output); } } await session?.commitConfig(); await session?.start(); ``` -------------------------------- ### Handle Drag Start Event Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-unified-drag-and-drop.md In the onDragStart callback of the RichEditor component, construct drag data based on the selected content. This involves getting the current selection and building the unified data structure for drag and drop. ```typescript RichEditor({ controller: this.sourceController }) // ... .onSelectionChange((value: RichEditorRange) => { this.selectedStartIndex = value.start as number; this.selectedEndIndex = value.end as number; }) // ... .onDragStart((event) => { try { const selection = this.sourceController.getSelection(); // construct drag data this.buildUnifiedRecords(selection); event.setData(this.unifiedData); } catch (error) { const err = error as BusinessError; hilog.error(0x0000, TAG, `%{public}s`, err.code, err.message); } }) // ... ``` -------------------------------- ### Get File Info and Start Screen Capture Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-avscreencapture-for-screen-recording.md Obtain file information and initiate screen recording by passing the file descriptor, width, and height to the native method. Ensure the file path is correctly constructed. ```typescript // 获取保存文件信息并调用Native方法 async createVideoFd(): Promise { // 拼接文件路径 this.tmpFileNameTwo = systemDateTime.getTime(true) + '.mp4'; // ... this.filepath = this.getUIContext().getHostContext()?.filesDir + '/' + this.tmpFileNameTwo; hilog.info(0xFF00, CommonConstants.LOG_TAG, 'filepath uri: %{public}s', this.filepath); // 获取文件信息 this.file = fs.openSync(this.filepath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // ... // 调用native方法开启录制并传递fd、宽高 avScreenCapture.startScreenCaptureToFile(this.file.fd, this.displayInfo.width, this.displayInfo.height); // ... } ``` -------------------------------- ### Full LTPO Cyclic Animation Implementation Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-ltpo-description.md This comprehensive example demonstrates the full implementation of a cyclic animation using DisplaySync and LTPO. It includes creating DisplaySync instances, setting frame rates, handling frame events for animation updates, and managing the animation's start and stop states. ```javascript import { displaySync } from '@kit.ArkGraphics2D'; @Entry @Component struct Index { @State drawFirstSize: number = 25; @State rotateAngle: number = 1; @State drawSecondSize: number = 25; private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined; private backDisplaySyncFast: displaySync.DisplaySync | undefined = undefined; private isBigger30: boolean = true; aboutToDisappear() { if (this.backDisplaySyncSlow) { this.backDisplaySyncSlow.stop(); // DisplaySync enable off this.backDisplaySyncSlow = undefined; // Empty the instance } if (this.backDisplaySyncFast) { this.backDisplaySyncFast.stop(); // DisplaySync enable off this.backDisplaySyncFast = undefined; // Empty the instance } } CreateDisplaySyncSlow() { // Defining the Desired Drawing Frame Rate this.backDisplaySyncSlow = displaySync.create(); // Creating a DisplaySync Instance let range: ExpectedFrameRateRange = { expected: 30, min: 0, max: 120 }; this.backDisplaySyncSlow.setExpectedFrameRateRange(range); // Setting the frame rate let draw30 = (intervalInfo: displaySync.IntervalInfo) => { if (this.isBigger30) { this.rotateAngle += 1; } else { this.rotateAngle -= 1; if (this.rotateAngle < 25) { this.isBigger30 = true; } } }; this.backDisplaySyncSlow.on("frame", draw30); // Subscribing to frame events and registering subscription functions } build() { Column() { Row() { Image($r('app.media.avatar')) .height(40) .width(40) } .rotate({ x: 0, y: 0, z: 1, centerX: '50%', centerY: '50%', angle: this.rotateAngle }) Row() { Button('Start') .onClick(() => { if (this.backDisplaySyncSlow === undefined) { this.CreateDisplaySyncSlow(); } if (this.backDisplaySyncSlow) { this.backDisplaySyncSlow.start(); // DisplaySync enable off } }) } } } } ``` -------------------------------- ### Setup Vulkan Render Context Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-video-render.md Initializes the Vulkan rendering context by setting up the native window, Vulkan instance, physical device, logical device, swap chain, render pass, framebuffers, and buffers. ```cpp void VulkanRender::SetupWindow(NativeWindow *nativeWindow) { nativeWindow_ = nativeWindow; CreateInstance(); vkExample::utils::LoadVulkanFunctions(instance); CreateSurface(); PickPhysicalDevice(); CreateLogicalDevice(); vkExample::utils::LoadVulkanFunctions(device); createSwapChain(); createRenderPass(); createFrameBuffersAndImages(); createVertexBuffer(); createUniformBuffer(); deviceInfoInitialized = true; } ``` -------------------------------- ### Install Remote SO Dependency via ohpm Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-stability-coding-standard-ndk-arkts.md To use SOs from remote modules, install them using the ohpm install command. The dependency will be automatically added to your project's oh-package.json5. ```bash ohpm install library --registry http://localhost:8088/repos/ohpm ``` -------------------------------- ### Starting a Download Task Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-file-upload-and-download-performance.md Initiates the download process for a created task. This is a fundamental step after task creation and configuration. ```typescript await downTask.start(); ``` -------------------------------- ### Load and Call SO Library Function in Native C/C++ Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-dynamic-link-library.md Demonstrates how to load an SO library using dlopen and retrieve a specific function (e.g., 'sub') for execution. Ensure to close the library handle with dlclose after use. ```cpp typedef double (*Sub)(double, double); static napi_value NAPI_Global_nativeSub(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args[3] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); double value0; napi_get_value_double(env, args[0], &value0); double value1; napi_get_value_double(env, args[1], &value1); size_t length = 0; napi_status status = napi_get_value_string_utf8(env, args[2], nullptr, 0, &length); if (status != napi_ok) { return nullptr; } char *path = new char[length + 1]; std::memset(path, 0, length + 1); napi_get_value_string_utf8(env, args[2], path, length + 1, &length); // Get the SO library path information void *handle = dlopen(path, RTLD_LAZY); // Open a SO library and get the path napi_value result = nullptr; Sub sub_func = (Sub)dlsym(handle, "sub"); // Get the function named sub status = napi_create_double(env, sub_func(value0, value1), &result); delete[] path; dlclose(handle); // Remember to close the SO library if (status != napi_ok) { return nullptr; } return result; } ``` -------------------------------- ### Start Video Encoder Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-hdrvivid.md Starts the video encoder. Ensure the encoder instance is valid before calling this function. ```c++ int32_t VideoEncoder::Start() { CHECK_AND_RETURN_RET_LOG(encoder_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Encoder is null"); int ret = OH_VideoEncoder_Start(encoder_); CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Start failed, ret: %{public}d", ret); return AVCODEC_SAMPLE_ERR_OK; } ``` -------------------------------- ### Initialize Window Utility Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-multi-device-responsive-layout.md In the EntryAbility's `onWindowStageCreate` lifecycle method, obtain the application's main window instance and initialize a `WindowUtil` class with it. This setup is crucial for managing window-related functionalities. ```typescript try { this.windowUtil = new WindowUtil(windowStage.getMainWindowSync()); } catch (error) { let err = error as BusinessError; hilog.error(0x0000, 'TestLog', `Failed to get main window. Code: ${err.code}, message: ${err.message}`); } ``` -------------------------------- ### Initialize and Configure Video Encoder Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-surface-encoder.md Create and configure a video encoder, obtaining a NativeWindow object. This includes setting encoder parameters, registering callbacks, and preparing the encoder. ```cpp int32_t VideoEncoder::Create(const std::string &videoCodecMime) { encoder_ = OH_VideoEncoder_CreateByMime(videoCodecMime.c_str()); if (encoder_ == nullptr) { return -1; } return 0; } int32_t VideoEncoder::Config(SampleInfo &sampleInfo, CodecUserData *codecUserData) { // Configure video encoder OH_AVFormat *format = OH_AVFormat_Create(); OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth); OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight); OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate); OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat); OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, sampleInfo.bitrateMode); OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, sampleInfo.bitrate); OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, sampleInfo.hevcProfile); int ret = OH_VideoEncoder_Configure(encoder_, format); if (ret != AV_ERR_OK) { OH_LOG_ERROR(LOG_APP, "Config failed, ret: %{public}d", ret); } OH_AVFormat_Destroy(format); format = nullptr; // GetSurface from video encoder OH_VideoEncoder_GetSurface(encoder_, &sampleInfo.window); // SetCallback for video encoder OH_VideoEncoder_RegisterCallback(encoder_, {VideoEncoder::OnCodecError, VideoEncoder::OnCodecFormatChange, VideoEncoder::OnNeedInputBuffer, VideoEncoder::OnNewOutputBuffer}, codecUserData); // Prepare video encoder OH_VideoEncoder_Prepare(encoder_); return 0; } ``` -------------------------------- ### OutOfMemoryError Stacktrace Example Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-scenario-stability-jscrash.md This is an example of a stacktrace indicating an OutOfMemoryError. It shows the error name, message, and the function where the allocation failed. ```text Device info:xxx Build info:xxx Fingerprint:873b2d78dbf1c413e983bae646887824217f21ad45746f8cd70beafc8212c482 Timestamp:xxx Module name:com.example.oom Version:1.0.0 VersionCode:1000000 PreInstalled:No Foreground:Yes Pid:20168 Uid:20020198 Process Memory(kB): 663416(Rss) Device Memory(kB): Total 11679260, Free 898896, Available 5358592 Reason:OutOfMemoryError Error name:OutOfMemoryError Error message:OutOfMemory when trying to allocate 40 bytes function name: SharedHeap::AllocateOldOrHugeObject Stacktrace: Cannot get SourceMap info, dump raw stack: at testGenStringOOM entry (entry/src/main/ets/pages/Index.ts:39:15) at anonymous entry (entry/src/main/ets/pages/Index.ts:21:13) ``` -------------------------------- ### Configure Third-Party Library Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md Run the configure script to check system compatibility and generate Makefiles. Ensure no errors are reported for successful configuration. ```bash checking host system type... x86_64-pc-linux-gnu checking target system type... x86_64-pc-linux-gnu ... # 省略部分configure信息 ... configure: creating ./config.status config.status: creating Makefile config.status: creating libjpeg.pc config.status: creating jconfig.h config.status: executing depfiles commands config.status: executing libtool commands ``` -------------------------------- ### Handle Swiper Animation Start Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-smooth-switching.md Update the current index when a Swiper animation starts. This is crucial for initiating the next video's playback. ```typescript .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => { hilog.info(0x0000, TAG, `onAnimationStart index: ${index}, targetIndex: ${targetIndex}, extraInfo: ${extraInfo}.`); // Key point: The curIndex is updated at AnimationStart and the next video starts to be played. this.curIndex = targetIndex; }) ``` -------------------------------- ### Install pkg-config for Python Dependency Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-gn-adapts-to-harmonyos.md Resolve 'python pkg-config file not found' errors by installing the pkg-config plugin using the apt-get package manager. ```bash sudo apt-get install pkg-config ``` -------------------------------- ### Start VideoProcessing Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-hdrvivid.md Starts the video processing task. Ensure that the processor is initialized and callbacks are registered before calling this function. Check the return code for success. ```cpp void PluginManager::StartProcessing() { PluginManager::GetInstance()->sampleInfo_->vpErrorCode = 0; VideoProcessing_ErrorCode ret = OH_VideoProcessing_Start(processor); if (ret != VIDEO_PROCESSING_SUCCESS) { // ... } CHECK_AND_RETURN_LOG(ret == VIDEO_PROCESSING_SUCCESS, "OH_VideoProcessing_Start failed, ret: %{public}d", ret); // ... OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, LOG_TAG, "StartProcessing succeed"); } ``` -------------------------------- ### Grid with GridLayoutOptions for Item Sizing (Recommended) Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-improve_grid_performance.md This example shows the recommended way to set Grid item sizes using GridLayoutOptions, which is more efficient and maintainable for irregular layouts. ```typescript // Import performance dot modules import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'; @Component struct TextItem { @State item: string = ''; build() { Text(this.item) .fontSize(16) .backgroundColor(0xF9CF93) .width('100%') .height(80) .textAlign(TextAlign.Center) } aboutToAppear() { // Finish the task hiTraceMeter.finishTrace('useGridLayoutOptions', 1); } } class MyDataSource implements IDataSource { private dataArray: string[] = []; public pushData(data: string): void { this.dataArray.push(data); } public totalCount(): number { return this.dataArray.length; } public getData(index: number): string { return this.dataArray[index]; } registerDataChangeListener(listener: DataChangeListener): void { } unregisterDataChangeListener(listener: DataChangeListener): void { } } @Component export struct GridExample2 { private datasource: MyDataSource = new MyDataSource(); scroller: Scroller = new Scroller(); private irregularData: number[] = []; layoutOptions: GridLayoutOptions = { regularSize: [1, 1], irregularIndexes: this.irregularData, }; aboutToAppear() { for (let i = 1; i <= 2000; i++) { this.datasource.pushData(i + ''); if ((i - 1) % 4 === 0) { this.irregularData.push(i - 1); } } } build() { Column({ space: 5 }) { Text('使用GridLayoutOptions设置GridItem大小').fontColor(0xCCCCCC).fontSize(9).width('90%') Grid(this.scroller, this.layoutOptions) { LazyForEach(this.datasource, (item: string, index: number) => { GridItem() { TextItem({ item: item }) } }, (item: string) => item) } .columnsTemplate('1fr 1fr 1fr') .columnsGap(10) .rowsGap(10) .width('90%') .height('40%') Button('scrollToIndex:1900').onClick(() => { // Start some tasks. hiTraceMeter.startTrace('useGridLayoutOptions', 1); this.scroller.scrollToIndex(1900); }) } } } ``` -------------------------------- ### Set Window Position and Size via StartOptions Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-multi-device-window-mode.md Use StartOptions to specify the window's position (windowLeft, windowTop) and dimensions (windowWidth, windowHeight), along with minimum size constraints (minWindowWidth, minWindowHeight). ```typescript let want: Want = { bundleName: 'com.example.pcproject', abilityName: 'SubEntryAbility' }; try { (this.getUIContext().getHostContext() as common.UIAbilityContext).startAbility(want, { windowLeft: 700, windowTop: 300, windowWidth: 1600, windowHeight: 1000, minWindowWidth: 800, minWindowHeight: 600 }) .then(() => { // Carry out normal business operations hilog.info(DOMAIN, TAG, '%{public}s', 'startAbility succeed'); }) .catch((err: BusinessError) => { // Handle business logic errors hilog.error(DOMAIN, TAG, '%{public}s', `startAbility failed. Cause code: ${err.code}, message: ${err.message}`); }); } catch (err) { // Handle the err of incorrect input parameters hilog.error(DOMAIN, TAG, '%{public}s', `startAbility failed. Cause code: ${err.code}, message: ${err.message}`); } ``` -------------------------------- ### Grid with columnStart/columnEnd for Item Sizing (Anti-pattern) Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-improve_grid_performance.md This example demonstrates an anti-pattern for setting Grid item sizes using columnStart and columnEnd. It is less performant and harder to manage for complex layouts. ```typescript // Import performance dot modules import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'; @Component struct TextItem { @State item: string = ''; build() { Text(this.item) .fontSize(16) .backgroundColor(0xF9CF93) .width('100%') .height(80) .textAlign(TextAlign.Center) } aboutToAppear() { // Finish the task hiTraceMeter.finishTrace('useColumnStartColumnEnd', 1); } } class MyDataSource implements IDataSource { private dataArray: string[] = []; public pushData(data: string): void { this.dataArray.push(data); } public totalCount(): number { return this.dataArray.length; } public getData(index: number): string { return this.dataArray[index]; } registerDataChangeListener(listener: DataChangeListener): void { } unregisterDataChangeListener(listener: DataChangeListener): void { } } @Entry @Component struct GridExample { private datasource: MyDataSource = new MyDataSource(); scroller: Scroller = new Scroller(); aboutToAppear() { for (let i = 1; i <= 2000; i++) { this.datasource.pushData(i + ''); } } build() { Column({ space: 5 }) { Text('使用columnStart,columnEnd设置GridItem大小').fontColor(0xCCCCCC).fontSize(9).width('90%') Grid(this.scroller) { LazyForEach(this.datasource, (item: string, index: number) => { if ((index % 4) === 0) { GridItem() { TextItem({ item: item }) } .columnStart(0).columnEnd(2) } else { GridItem() { TextItem({ item: item }) } } }, (item: string) => item) } .columnsTemplate('1fr 1fr 1fr') .columnsGap(10) .rowsGap(10) .width('90%') .height('40%') Button('scrollToIndex:1900').onClick(() => { // Start some tasks. hiTraceMeter.startTrace('useColumnStartColumnEnd', 1); this.scroller.scrollToIndex(1900); }) }.width('100%') .margin({ top: 5 }) } } ``` -------------------------------- ### Handle Tab Animation Start Event Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-news_homepage.md Call the Lottie animation controller when the TabBar animation starts. This ensures the correct animation plays when a tab is selected. ```typescript // Home.ets .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => { this.currentBottomIndex = targetIndex; this.lottieController(); }) ``` -------------------------------- ### Configure Audio and Video Parameters (Native) Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-avscreencapture-for-screen-recording.md Set up audio and video capture and encoding parameters. This includes defining audio sample rate, channels, source, and codec format, as well as video frame width, height, and source. ```cpp void CAVScreenCaptureToFile::SetConfigAsFile(OH_AVScreenCaptureConfig &config, int32_t videoWidth, int32_t videoHeight) { // 音频配置 OH_AudioCaptureInfo micCapInfo = {.audioSampleRate = 48000, .audioChannels = 2, .audioSource = OH_SOURCE_DEFAULT}; OH_AudioCaptureInfo innerCapInfo = {.audioSampleRate = 48000, .audioChannels = 2, .audioSource = OH_ALL_PLAYBACK}; OH_AudioEncInfo audioEncInfo = {.audioBitrate = 96000, .audioCodecformat = OH_AudioCodecFormat::OH_AAC_LC}; OH_AudioInfo audioInfo = {.micCapInfo = micCapInfo, .innerCapInfo = innerCapInfo, .audioEncInfo = audioEncInfo}; // 视频配置 OH_VideoCaptureInfo videoCapInfo = { .videoFrameWidth = videoWidth, .videoFrameHeight = videoHeight, .videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA}; OH_VideoEncInfo videoEncInfo = { ``` -------------------------------- ### Start Screen Capture with Surface Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-avscreencapture-for-screen-recording.md Start screen recording using the Surface mode. This method specifies the Surface to be used for recording and initiates the capture process. ```c result = OH_AVScreenCapture_StartScreenCaptureWithSurface(g_avCapture, sampleInfo_.window); OH_LOG_INFO(LOG_APP, "OH_VideoEncoder_Start Started 2 %{public}d", result); if (result != AV_SCREEN_CAPTURE_ERR_OK) { OH_LOG_INFO(LOG_APP, "ScreenCapture Started failed %{public}d", result); OH_AVScreenCapture_Release(g_avCapture); } ``` -------------------------------- ### Move Executables to Library Directory Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-configure-adapts-to-harmonyos.md After installation, move the executable files from the 'bin' directory within the library's installation path to the main library source directory. ```bash owner@ubuntu:/mnt/e/configure$ mv jpeg-9e/jpeg/bin/* jpeg-9e/ ``` -------------------------------- ### Initialize Audio Capturer Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-avscreencapture-for-screen-recording.md Configure and initialize an audio capturer for screen recording. Ensure all necessary parameters like channel count, sample format, and latency mode are set correctly. ```c OH_AudioStreamBuilder_SetChannelCount(builder_, sampleInfo.audioChannelCount); OH_AudioStreamBuilder_SetSampleFormat(builder_, AUDIOSTREAM_SAMPLE_S16LE); OH_AudioStreamBuilder_SetLatencyMode(builder_, AUDIOSTREAM_LATENCY_MODE_NORMAL); OH_AudioStreamBuilder_SetEncodingType(builder_, AUDIOSTREAM_ENCODING_TYPE_RAW); OH_AudioCapturer_Callbacks callbacks; callbacks.OH_AudioCapturer_OnReadData = AudioCapturerOnReadData; OH_AudioStreamBuilder_SetCapturerCallback(builder_, callbacks, audioEncContext); // 创建 OH_AudioCapturer对象 OH_AudioStreamBuilder_GenerateCapturer(builder_, &audioCapturer_); ``` -------------------------------- ### Initialize Native Image and Surface Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-video-render.md Initializes a native image, acquires its native window, and sets up a frame available listener. Ensure proper error handling for each step. ```cpp OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OpenGLRenderThread", "OH_NativeImage_Create failed."); return false; } int ret = 0; { std::lock_guard lock(nativeImageSurfaceIdMutex_); nativeImageWindow_ = OH_NativeImage_AcquireNativeWindow(nativeImage_); ret = OH_NativeImage_GetSurfaceId(nativeImage_, &nativeImageSurfaceId_); } if (ret != 0) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OpenGLRenderThread", "OH_NativeImage_GetSurfaceId failed, ret is %{public}d.", ret); return false; } nativeImageFrameAvailableListener_.context = this; nativeImageFrameAvailableListener_.onFrameAvailable = &OpenGLRenderThread::OnNativeImageFrameAvailable; ret = OH_NativeImage_SetOnFrameAvailableListener(nativeImage_, nativeImageFrameAvailableListener_); if (ret != 0) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "OpenGLRenderThread", "OH_NativeImage_SetOnFrameAvailableListener failed, ret is %{public}d.", ret); return false; } return true; } ``` -------------------------------- ### Start Video Encoder and Muxer in HarmonyOS Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-image-to-video-synthesis.md Initiates the video encoder and muxer, and starts the input/output threads for video encoding. This function should be called after successful creation and configuration. ```cpp // Start the encoder, create input and output thread. int32_t Transcoding::Start() { std::unique_lock lock(mutex_); int32_t ret; CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); if (videoEncContext_) { CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); int32_t ret = muxer_->Start(); CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Muxer start failed"); ret = videoEncoder_->Start(); isStarted_ = true; CHECK_AND_RETURN_RET_LOG(ret == AVCODEC_SAMPLE_ERR_OK, ret, "Encoder start failed"); videoEncInputThread_ = std::make_unique(&Transcoding::VideoEncInputThread, this); videoEncOutputThread_ = std::make_unique(&Transcoding::VideoEncOutputThread, this); if (videoEncInputThread_ == nullptr || videoEncOutputThread_ == nullptr) { AVCODEC_SAMPLE_LOGE("Create thread failed"); StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } } if (isReleased_) { isReleased_ = false; videoEncContext_->outputFrameCount = 0; } AVCODEC_SAMPLE_LOGI("Succeed"); doneCond_.notify_all(); return AVCODEC_SAMPLE_ERR_OK; } ``` -------------------------------- ### Start Background Task During Music Playback Source: https://github.com/jizhi-error/harmonyos-best-practices/blob/master/articles/bpta-audio-interaction-practice.md Initiates background audio playback by calling startContinuousTask from BackgroundUtil. This should be called when music playback starts to ensure uninterrupted listening. ```typescript /** * Play music by index. * * @param musicIndex */ async play(musicIndex: number = this.musicIndex) { if (!this.audioRenderer) { return; } if (musicIndex >= this.songList.length) { Logger.error(TAG, `current musicIndex ${musicIndex}`); return; } BackgroundUtil.startContinuousTask(this.context); this.updateMusicIndex(musicIndex); if (this.isFirst) { this.isFirst = false; await this.loadSongAssent(); await this.stop(); await this.start(); } else { await this.stop(); this.updateIsPlay(false); await this.reset(); } } // ... /** * start music. */ public async start() { if (this.audioRenderer) { try { await this.audioRenderer.start().catch((err: BusinessError) => { Logger.error(TAG, `start failed,code is ${err.code},message is ${err.message}`); }) this.updateIsPlay(true); BackgroundUtil.startContinuousTask(this.context); Logger.info(TAG, 'start success'); } catch (e) { Logger.error(TAG, `start failed,audioRenderer is undefined`); } } } ```