<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: victordeng</title>
    <description>The latest articles on DEV Community by victordeng (@victordeng).</description>
    <link>https://dev.to/victordeng</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2947531%2F7a983427-23bd-40c1-a369-e5498272178e.png</url>
      <title>DEV Community: victordeng</title>
      <link>https://dev.to/victordeng</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/victordeng"/>
    <language>en</language>
    <item>
      <title>HarmonyOS NEXT project practice：Call functions between parent-child components</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:51:20 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practicecall-functions-between-parent-child-components-2n81</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practicecall-functions-between-parent-child-components-2n81</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-create-custom-components#%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E5%8F%98%E9%87%8F" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-create-custom-components#%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E5%8F%98%E9%87%8F&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In ArkUI, the content displayed by the UI is all components. Components directly provided by the framework are called system components, while those defined by the developer are called custom components. When developing UI interfaces, it is not only necessary to combine system components, but also to consider factors such as code reusability, separation of business logic and UI, and evolution of subsequent versions. Therefore, encapsulating UI and some business logic into custom components is an essential capability.&lt;/p&gt;

&lt;p&gt;Custom components have the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combatable: allows developers to combine system components, their properties, and methods.&lt;/li&gt;
&lt;li&gt;Reusable: Custom components can be reused by other components and used as different instances in different parent components or containers.&lt;/li&gt;
&lt;li&gt;Data driven UI update: driving UI refresh through changes in state variables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Custom components are so common that function calling issues are inevitable between parent and child components. For example, how does the parent component call the function of the child component? How do child components call the functions of the parent component? This is a problem that we often inevitably encounter in project development.&lt;/p&gt;

&lt;p&gt;Calling functions between parent and child components is a common interaction requirement, mainly used to achieve communication and functional collaboration between components. Common scenarios for calling functions between parent-child components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The parent component needs to actively trigger the internal logic of the child component (such as: the parent component needs to control the form reset of the child component, the parent component needs to trigger the animation or data refresh of the child component, perform specific operations, etc.)&lt;/li&gt;
&lt;li&gt;The child component needs to pass data to the parent component or trigger the logic of the parent component (such as notifying the parent component to save data after the child component form is submitted, triggering the logic of the parent component after the child component user operates, etc.).&lt;/li&gt;
&lt;li&gt;Parent child components require frequent interaction, for example, the parent component controls the state of the child component and notifies the parent component when the state of the child component changes. (such as bidirectional binding of form input boxes, synchronization of parent-child component states (such as switches, selectors), etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following is an example of practical code:&lt;br&gt;
The parent component calls the child component function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entry
@Component
struct CallSubComponentMethodPage {
  private childController = new ChildController()
  private count: number = 0

  build() {
    Column({ space: 10 }) {
      Text('CallSubComponentMethod Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Button('CallSubComponentMethod').onClick(() =&amp;gt; {
        this.count++
        this.childController.changeText(`this is text from parent, and count = ${this.count}`)
      })

      Child({ childController: this.childController })
    }
    .height('100%')
    .width('100%')
  }
}

//定义controller对象
class ChildController {
  changeText = (value: string) =&amp;gt; {
  }
}

@Component
struct Child {
  @State private text: string = 'this is child text'
  childController: ChildController = new ChildController();

  aboutToAppear() {
    //给childController对应的方法赋值
    this.childController.changeText = this.changeText
  }

  //封装的能力
  private changeText = (value: string) =&amp;gt; {
    this.text = value
  }

  build() {
    Column() {
      Text(this.text)
    }
    .backgroundColor('#EEEEEE')
    .width('90%')
    .height(100)
    .justifyContent(FlexAlign.Center)
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Child component calls parent component function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entry
@Component
struct CallParentComponentMethodPage {
  @State sonClickCount: number = 0

  build() {
    Column({ space: 10 }) {
      Text('CallParentComponentMethod Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text(`sonClickCount = ${this.sonClickCount}`)

      Son({
        onSonClick: (count: number) =&amp;gt; {
          this.sonClickCount = count
        }
      })
    }
    .height('100%')
    .width('100%')
  }
}

@Component
struct Son {
  private count: number = 0
  @Require onSonClick: (count: number) =&amp;gt; void = (count: number) =&amp;gt; {
  }

  build() {
    Column({ space: 10 }) {
      Text('Son Component')
      Button('Son Click').onClick(() =&amp;gt; {
        this.count++
        this.onSonClick(this.count)
      })
    }
    .backgroundColor('#EEEEEE')
    .width('90%')
    .height(200)
    .padding(10)
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Load local webpage resources</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:45:34 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceload-local-webpage-resources-2c4</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceload-local-webpage-resources-2c4</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-page-loading-with-web-components#%E5%8A%A0%E8%BD%BD%E6%9C%AC%E5%9C%B0%E9%A1%B5%E9%9D%A2" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-page-loading-with-web-components#%E5%8A%A0%E8%BD%BD%E6%9C%AC%E5%9C%B0%E9%A1%B5%E9%9D%A2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to reduce user waiting perception in scenarios such as startup, jumping, and weak network, and to buy time for dynamic content loading, local pages can be loaded to optimize user experience.&lt;/p&gt;

&lt;p&gt;Show the method of loading a local page file in the following example:&lt;br&gt;
By placing the local page file in the rawfile directory of the application, developers can specify the default loaded local page when creating the web component, and after loading is complete, they can change the current web component's page by calling the loadURL() interface.&lt;/p&gt;

&lt;p&gt;When loading local HTML files, referencing local CSS style files can be achieved through the following methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link rel="stylesheet" href="resource://rawfile/xxx.css"&amp;gt;
&amp;lt;link rel="stylesheet" href="file:///data/storage/el2/base/haps/entry/cache/xxx.css"&amp;gt;// 加载沙箱路径下的本地css文件。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Load \$r or \$rawfile local page
&lt;/h1&gt;

&lt;p&gt;In the resources/rawfile directory&lt;br&gt;
Add hello.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello!&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add helloAgain.html&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello again!&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add WebLocalPage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebLocalPage {
  src: ResourceStr = $rawfile("hello.html")
  webController: webview.WebviewController = new webview.WebviewController();

  build() {
    Column({ space: 10 }) {
      Text('WebPage')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Row({ space: 10 }){
        Button('hello')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到hello.html
              this.webController.loadUrl( $rawfile("hello.html"));
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
        Button('hello again')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到helloAgain.html
              this.webController.loadUrl( $rawfile("helloAgain.html"));
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
      }

      Web({ src: this.src, controller: this.webController })
        .width('100%')
        .layoutWeight(1)
        .horizontalScrollBarAccess(false)//设置是否显示横向滚动条
        .verticalScrollBarAccess(false) //设置是否显示纵向滚动条
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Load local resources through resource protocol
&lt;/h1&gt;

&lt;p&gt;Replace $rawfile with resource protocol&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebLocalPage {
  // src: ResourceStr = $rawfile("hello.html")
  src: ResourceStr = 'resource://rawfile/hello.html'
  webController: webview.WebviewController = new webview.WebviewController();

  build() {
    Column({ space: 10 }) {
      Text('WebPage')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Row({ space: 10 }) {
        Button('hello')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到hello.html
              // this.webController.loadUrl($rawfile("hello.html"));
              this.webController.loadUrl('resource://rawfile/hello.html');
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
        Button('hello again')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到helloAgain.html
              // this.webController.loadUrl($rawfile("helloAgain.html"));
              this.webController.loadUrl('resource://rawfile/helloAgain.html');
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
      }

      Web({ src: this.src, controller: this.webController })
        .width('100%')
        .layoutWeight(1)
        .horizontalScrollBarAccess(false)//设置是否显示横向滚动条
        .verticalScrollBarAccess(false) //设置是否显示纵向滚动条
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Load HTML formatted text data
&lt;/h1&gt;

&lt;p&gt;The src of a web component can directly load HTML strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// WebComponent.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();
  htmlStr: string = "data:text/html, &amp;lt;html&amp;gt;&amp;lt;body bgcolor=\"green\"&amp;gt;&amp;lt;h1&amp;gt;Source:&amp;lt;pre&amp;gt;source&amp;lt;/pre&amp;gt;&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;";

  build() {
    Column() {
      // 组件创建时，加载htmlStr
      Web({ src: this.htmlStr, controller: this.controller })
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Web components can load HTML formatted text data through the loadData() interface. When developers do not need to load the entire page and only need to display some page fragments, this feature can be used to quickly load the page. When loading a large number of HTML files, the fourth parameter baseURL needs to be set to "data".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// WebComponent.ets
import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Column() {
      Button('loadData')
        .onClick(() =&amp;gt; {
          try {
            // 点击按钮时，通过loadData，加载HTML格式的文本数据
            this.controller.loadData(
              "&amp;lt;html&amp;gt;&amp;lt;body bgcolor=\"white\"&amp;gt;Source:&amp;lt;pre&amp;gt;source&amp;lt;/pre&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;",
              "text/html",
              "UTF-8"
            );
          } catch (error) {
            console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
          }
        })
      // 组件创建时，加载www.example.com
      Web({ src: 'www.example.com', controller: this.controller })
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Load web page resources</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:34:33 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceload-web-page-resources-19a6</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceload-web-page-resources-19a6</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-page-loading-with-web-components#%E5%8A%A0%E8%BD%BD%E7%BD%91%E7%BB%9C%E9%A1%B5%E9%9D%A2" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/web-page-loading-with-web-components#%E5%8A%A0%E8%BD%BD%E7%BD%91%E7%BB%9C%E9%A1%B5%E9%9D%A2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Page loading is a fundamental function of web components. According to the source of page loading data, it can be divided into three common scenarios, including loading web pages, loading local pages, and loading rich text data in HTML format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web(value: WebOptions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WebOptions: Define web options through interfaces, with the following properties and meanings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Src: URL of the webpage resource. Src cannot dynamically change the address through a state variable (e.g. @ State). If you need to change it, please reload it through loadurl().&lt;/li&gt;
&lt;li&gt;Controller: A controller that can control various behaviors of web components, including page navigation, declaring cycle state, JavaScript interaction, and more.&lt;/li&gt;
&lt;li&gt;RenderMode: represents the rendering mode of the current web component, renderMode.ASYNC RENDER represents self rendering of the web component, renderMode.SYNC_RENDER represents support for unified rendering capability of the web component, default value is renderMode.ASYNC RENDER, this mode does not support dynamic adjustment.&lt;/li&gt;
&lt;li&gt;IncognitoMode: Indicates whether the currently created webview is in privacy mode. True represents creating a private mode webview, while false represents creating a normal mode webview. Default value: false.&lt;/li&gt;
&lt;li&gt;SharedRenderProcessToken: Refers to the token specified by the current web component for the shared rendering process. In multi rendering process mode, web components with the same token will first attempt to reuse the rendering process bound to the token. The binding between the token and the rendering process occurs during the initialization phase of the rendering process. When there is no associated web component in the rendering process, its binding relationship with the token will be removed. Default value: ''.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The prerequisite for loading web page resources is:&lt;br&gt;
During the page loading process, if network resource retrieval is involved, please configure network access permissions in module. json 5. The method of adding permissions can refer to declaring permissions in the configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"requestPermissions":[
    {
      "name" : "ohos.permission.INTERNET"
    }
  ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developers can specify the default web page to load when creating web components. After the default page is loaded, if you need to change the web page displayed by this web component, you can load the specified web page by calling the loadURL() interface. The first parameter variable src of a web component cannot dynamically change its address through a state variable (e.g. @ State). If you need to change it, please reload it through loadURL().&lt;/p&gt;

&lt;p&gt;Load the specified URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loadUrl(url: string | Resource, headers?: Array&amp;lt;WebHeader&amp;gt;): void
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;URL: The URL that needs to be loaded.&lt;br&gt;
Headers: Additional HTTP request headers for URLs.&lt;/p&gt;

&lt;p&gt;In the following example, after the web component loads the "example. com" page, the developer can change the display page of this web component to "example. com" through the loadURL interface.&lt;/p&gt;

&lt;p&gt;Practical code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { webview } from '@kit.ArkWeb';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct WebOnlinePage {
  src: ResourceStr = 'https://m.baidu.com'
  webController: webview.WebviewController = new webview.WebviewController();

  build() {
    Column({ space: 10 }) {
      Text('WebPage')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Row({ space: 10 }){
        Button('加载百度官网')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到https://m.baidu.com
              this.webController.loadUrl('https://m.baidu.com');
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
        Button('加载华为开发者官网')
          .onClick(() =&amp;gt; {
            try {
              // 点击按钮时，通过loadUrl，跳转到https://developer.huawei.com/
              this.webController.loadUrl('https://developer.huawei.com/');
            } catch (error) {
              console.error(`ErrorCode: ${(error as BusinessError).code},  Message: ${(error as BusinessError).message}`);
            }
          })
      }

      Web({ src: this.src, controller: this.webController })
        .width('100%')
        .layoutWeight(1)
        .horizontalScrollBarAccess(false)//设置是否显示横向滚动条
        .verticalScrollBarAccess(false) //设置是否显示纵向滚动条
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Manage avoidance zones</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:29:16 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practicemanage-avoidance-zones-3f7f</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practicemanage-avoidance-zones-3f7f</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive#section813019373176" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive#section813019373176&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Core concepts
&lt;/h1&gt;

&lt;p&gt;The visibility and concealment of avoidance zones:&lt;br&gt;
When the page is displayed or hidden, use the Window. setWindowLayoutFullScreen() method to set whether the window is in full screen mode, and use the Window. setWindowSystemBarEnabling () method to set the status bar and navigation bar to be visible or hidden.&lt;/p&gt;

&lt;p&gt;Property settings for the system bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setWindowSystemBarProperties(systemBarProperties: SystemBarProperties): Promise&amp;lt;void&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the properties of the main window status bar and use Promise asynchronous callback. This interface does not take effect when called on 2-in-1 devices, and it does not take effect immediately when called on other devices in split screen mode (i.e. window mode is window.Windows Status Type. SPLIT_SCREEN), free floating window mode (i.e. window mode is window.Windows Status Type. FLOODING), and free multi window mode (can be turned on by clicking the free multi window button in the device control center). It only takes effect when entering the full screen main window.&lt;/p&gt;

&lt;p&gt;Concept of Safe Zone:&lt;br&gt;
The safe zone refers to the display area of a page. By default, interfaces developed by developers are laid out within the safe zone and do not overlap with the avoidance zones set by the system, such as the status bar and navigation bar areas. Provide attribute methods that allow developers to set the drawing content of components to exceed the limits of the safe zone. The expandSafeArea attribute supports the extension of the drawing area of components outside the safe zone without changing the layout. Set the setKeyboardAvoidMode to configure the avoidance mode of the page when the virtual keyboard pops up. When there is a title bar or other text on the page that does not want to overlap with the avoidance area, it is recommended to set the expandSafeArea property on the component to achieve immersive effects, or you can directly set full screen immersion through the window interface setWindowLayoutFullScreen.&lt;/p&gt;

&lt;p&gt;Control the avoidance mode of the page when lifting the virtual keyboard&lt;br&gt;
Interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setKeyboardAvoidMode(value: KeyboardAvoidMode): void
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Value: Configure the avoidance mode of the page when lifting the virtual keyboard.&lt;br&gt;
Default value: KeyboardAvoidMode.oFFSET, the default avoidance mode when the keyboard is lifted is upward.&lt;/p&gt;

&lt;p&gt;describe&lt;br&gt;
KeyboardAvoidMode.RISIZE mode compresses the page size, and components with percentage width and height settings on the page will be compressed along with the page, while components with directly set width and height will be laid out according to the fixed size settings. When setting the RESIZE mode of KeyboardAvoidMode, expandSafeArea ([SafeAreaType.KEYBOARD], [SafeAreEdge.BOTTOM]) does not take effect.&lt;br&gt;
KeyboardAvoidMode-NONE mode configuration page does not avoid the keyboard, and the page will be covered by a raised keyboard.&lt;/p&gt;

&lt;p&gt;KeyboardAvoidMode: Configure the avoidance mode of the page when the keyboard avoids. The meaning of attributes is as follows:&lt;br&gt;
OFFSET: Upward mode.&lt;br&gt;
RESIZE: Compression mode.&lt;br&gt;
OFFSET_WITH_CARET: Upward mode, when the cursor position in the input box changes, it will also trigger avoidance.&lt;br&gt;
RESIZE_WITH_CARET: Compression mode, which also triggers avoidance when the cursor position in the input box changes.&lt;br&gt;
NONE: Do not avoid the keyboard.&lt;/p&gt;

&lt;p&gt;Code Practical Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { common } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { KeyboardAvoidMode } from '@kit.ArkUI';

@Entry
@Component
struct ManageAvoidZonePage {
  context = this.getUIContext();
  uiAbilityContext = this.context.getHostContext() as common.UIAbilityContext;
  private windowClass = this.uiAbilityContext.windowStage.getMainWindowSync();
  private keyboardAvoidMode = KeyboardAvoidMode.OFFSET

  build() {
    Column() {
      Column({ space: 10 }) {
        Text('ManageAvoidZone Page')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)

        Button('hideSystemBar')
          .onClick(() =&amp;gt; {
            this.hide()
          })

        Button('showSystemBar')
          .onClick(() =&amp;gt; {
            this.show()
          })

        Button('setSystemBarBgBlack')
          .onClick(() =&amp;gt; {
            let sysBarProps: window.SystemBarProperties = {
              statusBarColor: '#000000',
              statusBarContentColor: '#ffffff'
            };
            this.windowClass.setWindowSystemBarProperties(sysBarProps);
          })

        Button('setSystemBarBgWhite')
          .onClick(() =&amp;gt; {
            let sysBarProps: window.SystemBarProperties = {
              statusBarColor: '#ffffff',
              statusBarContentColor: '#000000'
            };
            this.windowClass.setWindowSystemBarProperties(sysBarProps);
          })

        TextInput()

        Button('changeKeyboardAvoidMode')
          .onClick(() =&amp;gt; {
            if (this.keyboardAvoidMode === KeyboardAvoidMode.OFFSET) {
              this.keyboardAvoidMode =KeyboardAvoidMode.RESIZE
              this.getUIContext().setKeyboardAvoidMode(this.keyboardAvoidMode);
            } else {
              this.keyboardAvoidMode =KeyboardAvoidMode.OFFSET
              this.getUIContext().setKeyboardAvoidMode(this.keyboardAvoidMode);
            }
          })
      }
      .width('100%')

      Button('submit')
        .margin(10)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    .backgroundColor('#fffffae5')
  }

  hide() {
    this.windowClass.setWindowLayoutFullScreen(true);
    this.windowClass.setWindowSystemBarEnable([]);
  }

  show() {
    this.windowClass.setWindowLayoutFullScreen(false);
    this.windowClass.setWindowSystemBarEnable(['status', 'navigation']);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Window Immersive Effect</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:24:33 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practicewindow-immersive-effect-27o0</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practicewindow-immersive-effect-27o0</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overview of Immersive Effects&lt;br&gt;
Immersive mode usually refers to making the interface of an application more focused on content, without allowing users to be distracted by irrelevant elements. In mobile applications, full screen window elements include a status bar, application interface, and navigation bar (as shown below). Immersive page development often achieves the following goals by extending the application page to the status bar and navigation bar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unify the color tone of the page and avoidance areas to provide users with a better visual experience.&lt;/li&gt;
&lt;li&gt;Maximize the use of the screen's visible area to provide a larger layout space for the page.&lt;/li&gt;
&lt;li&gt;Provide a fully immersive experience, allowing users to immerse themselves without being distracted by other things.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two solutions to achieve immersive effects&lt;br&gt;
Option 1: Set the window to full screen mode&lt;br&gt;
Option 2: Expand Component Security Zone&lt;br&gt;
Recommend using option one, which has the advantage of achieving immersive effects for the entire application (all pages).&lt;/p&gt;

&lt;p&gt;interface&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setWindowLayoutFullScreen(isLayoutFullScreen: boolean): Promise&amp;lt;void&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set whether the layout of the main window or sub window is immersive layout, using Promise asynchronous callback. Starting from API version 14, this interface does not take effect when used in the free multi window mode of 2-in1 devices or tablet devices (which can be turned on by clicking the free multi window button in the device control center).&lt;/li&gt;
&lt;li&gt;When the immersive layout takes effect, the layout does not avoid the status bar and bottom navigation area, and components may overlap with them.&lt;/li&gt;
&lt;li&gt;When the non immersive layout takes effect, the layout avoids the status bar and bottom navigation area, and components do not overlap with them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prerequisite:&lt;br&gt;
Windows provide some basic capabilities for managing windows, including creating and destroying the current window, setting various properties, and managing and scheduling between windows.&lt;br&gt;
This module provides the following commonly used functions related to windows:&lt;br&gt;
Window: The current window instance, the basic unit managed by the window manager.&lt;br&gt;
WindowStage: Window Manager. Manage various basic window units.&lt;/p&gt;

&lt;p&gt;Here is the practical code to achieve immersive effects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct SetFullWindowPage {
  @StorageProp('topRectHeight')
  topRectHeight: number = 0;
  @StorageProp('bottomRectHeight')
  bottomRectHeight: number = 0;

  build() {
    Column({ space: 10 }) {
      Text('SetFullWindow Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text(`topRectHeight = ${this.topRectHeight}`)
      Text(`bottomRectHeight = ${this.bottomRectHeight}`)

      Button('SetFullWindow')
        .onClick(() =&amp;gt; {
          this.setFullWindow(true)
        })
      Button('CancelFullWindow')
        .onClick(() =&amp;gt; {
          this.setFullWindow(false)
        })
    }
    .height('100%')
    .width('100%')
    .backgroundColor('#cccccc')
    .padding({ top: this.topRectHeight, bottom: this.bottomRectHeight })
  }

  async setFullWindow(isLayoutFullScreen: boolean = true) {
    let context = getContext(this) as common.UIAbilityContext;
    let windowClass = await window.getLastWindow(context);
    // 1. 设置窗口全屏
    windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() =&amp;gt; {
      console.info('Succeeded in setting the window layout to full-screen mode.');
    }).catch((err: BusinessError) =&amp;gt; {
      console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
    });
    // 2. 获取布局避让遮挡的区域
    let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 以导航条避让为例
    let avoidArea = windowClass.getWindowAvoidArea(type);
    let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航条区域的高度
    AppStorage.setOrCreate('bottomRectHeight', px2vp(bottomRectHeight));
    type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例
    avoidArea = windowClass.getWindowAvoidArea(type);
    let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度
    AppStorage.setOrCreate('topRectHeight', px2vp(topRectHeight));

    // 3. 注册监听函数，动态获取避让区域数据
    windowClass.on('avoidAreaChange', (data) =&amp;gt; {
      if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
        let topRectHeight = data.area.topRect.height;
        AppStorage.setOrCreate('topRectHeight', px2vp(topRectHeight));
      } else if (data.type == window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
        let bottomRectHeight = data.area.bottomRect.height;
        AppStorage.setOrCreate('bottomRectHeight', px2vp(bottomRectHeight));
      }
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Get window properties</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:20:01 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceget-window-properties-2ppj</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceget-window-properties-2ppj</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-window#getwindowproperties9" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-window#getwindowproperties9&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Stage model, typical scenarios for managing application windows include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set the main window properties and target page of the application&lt;/li&gt;
&lt;li&gt;Set application sub window properties and target page&lt;/li&gt;
&lt;li&gt;Immersive ability in the experience window&lt;/li&gt;
&lt;li&gt;Set floating window&lt;/li&gt;
&lt;li&gt;Listening window non interactive and interactive events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following is an introduction to how to obtain window properties:&lt;br&gt;
Step 1: Get the Window class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getLastWindow(ctx: BaseContext): Promise&amp;lt;Window&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieve the top-level child window within the current application. If there are no application child windows, return to the main application window and use Promise asynchronous callback.&lt;br&gt;
Step 2: Obtain the properties of the current window&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getWindowProperties(): WindowProperties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieve the properties of the current window and return WindowProperties.&lt;/p&gt;

&lt;p&gt;Explanation of each attribute of WindowProperties&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WindowRect: Window size, which can be obtained during the onPageShow or onForeground stages of the page lifecycle or application lifecycle.&lt;/li&gt;
&lt;li&gt;DrawableRect: The size of the drawable area within the window, where the upper boundary on the left is calculated relative to the window. In the Stage model, this interface needs to be used after calling loadContent() or setUIContent() to load the page content.&lt;/li&gt;
&lt;li&gt;Type: Window type.&lt;/li&gt;
&lt;li&gt;IsFullScreen: Whether it is full screen, default is false. True represents full screen; False indicates non full screen.&lt;/li&gt;
&lt;li&gt;IsLayoutFullScreen: Whether the window is immersive and in full screen mode (not in floating windows, split screens, or other scenes), defaults to false. True means immersive and in full screen mode; False indicates non immersive or non full screen mode.&lt;/li&gt;
&lt;li&gt;Focused: Whether the window can be focused, default is true. True indicates that it can be focused; False means unfocused.&lt;/li&gt;
&lt;li&gt;Touchable: Whether the window is touchable, defaults to true. True means touchable; False means not touchable.&lt;/li&gt;
&lt;li&gt;Brightness: Screen brightness. This parameter is a floating point number, and the adjustable brightness range is [0.0, 1.0]. When taken as 1.0, it represents the maximum brightness value. If the window does not have a brightness value set, it indicates that the brightness follows the system, and the obtained brightness value is -1.&lt;/li&gt;
&lt;li&gt;IsKeepScreenOn: Whether the screen is constantly on, default is false. True indicates constant brightness; False means not frequently lit.&lt;/li&gt;
&lt;li&gt;IsPrivacy Mode: Privacy mode, default to false. True indicates that the mode is enabled; False indicates that the mode is turned off.&lt;/li&gt;
&lt;li&gt;IsTransparent: Whether the window background is transparent. The default is false. True represents transparency; False indicates opacity.&lt;/li&gt;
&lt;li&gt;ID: Window ID, default value is 0, this parameter should be an integer.&lt;/li&gt;
&lt;li&gt;Display ID: The ID of the screen where the window is located, which defaults to the main screen ID. This parameter should be an integer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taking the width and height of obtaining window properties as an example, the actual code is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { common } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct GetWindowPropertiesPage {
  @State windowWidth: number = 0
  @State windowHeight: number = 0

  aboutToAppear(): void {
    try {
      let context = getContext(this) as common.UIAbilityContext;
      let promise = window.getLastWindow(context);
      promise.then((data) =&amp;gt; {
        //获取窗口对象
        let windowClass = data;
        try {
          //获取窗口属性
          let properties = windowClass.getWindowProperties();
          let rect = properties.windowRect;
          //rect.width: 窗口宽度；rect.height: 窗口高度
          this.windowWidth = px2vp(rect.width)
          this.windowHeight = px2vp(rect.height)
        } catch (exception) {
          console.error('Failed to obtain the window properties. Cause: ' + JSON.stringify(exception));
        }
        console.info('Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));
      }).catch((err: BusinessError) =&amp;gt; {
        console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(err));
      });
    } catch (exception) {
      console.error('Failed to obtain the top window. Cause: ' + JSON.stringify(exception));
    }
  }

  build() {
    Column({ space: 10 }) {
      Text('GetWindowProperties Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text(`windowWidth = ${this.windowWidth}`)
      Text(`windowHeight = ${this.windowHeight}`)
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：use openCustomDialog</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:15:18 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceuse-opencustomdialog-2hl8</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceuse-opencustomdialog-2hl8</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-uicontext-custom-dialog" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-uicontext-custom-dialog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to various limitations in the use of the Customs Dialogue Controller, it does not support dynamic creation or refresh. In relatively complex application scenarios, it is recommended to use the openCustoms Dialog interface provided by the PromptAction object obtained from UIContext to implement custom pop ups.&lt;/p&gt;

&lt;p&gt;The openCustoms dialog can be configured with isModal to achieve modal and non modal pop ups. When isModal is true, the pop-up box is a modal pop-up window. When isModal is false, the pop-up box is a non modal pop-up window.&lt;/p&gt;

&lt;p&gt;life cycle&lt;br&gt;
The pop-up box provides a lifecycle function to notify users of the lifecycle of the pop-up box. The triggering sequence of the lifecycle is: onWillAppeal -&amp;gt;onDiAppeal -&amp;gt;onWillDisappear -&amp;gt;onDiDisappear.&lt;/p&gt;

&lt;p&gt;There are two ways to create custom pop ups for openCustoms dialog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenCustoms Dialog (passed as Component Content): Encapsulating content through Component Content can decouple it from the UI interface, making calls more flexible and meeting the encapsulation needs of developers. It has high flexibility, with completely customizable pop-up box styles, and can dynamically update the parameters of the pop-up box using the updateCustoms Dialog method after it is opened.&lt;/li&gt;
&lt;li&gt;OpenCustoms Dialog (in the form of a builder): Compared to Component Content, the builder must be bound to the context and have a certain coupling with the UI. This method uses a default pop-up style, which is suitable for developers who want to achieve the same effect as the default style of system pop ups.
This article introduces the creation of custom pop ups for WidgetContent through parameter input, and the usage of pop ups in builder format can refer to openCustomizalDialog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementation steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create WidgetContent.
WidgetContent is used to define the content of custom pop ups. Among them, wrapBuilder (buildText) encapsulates custom components, and new Params (this. message) is the input parameter for custom components, which can be defaulted or passed in as the basic data type.&lt;/li&gt;
&lt;li&gt;Open the custom pop-up box.
The pop-up box opened by calling the openCustomizalDialog interface defaults to a pop-up box with customStyle set to true, which means that the content style of the pop-up box is displayed completely according to the contentNode custom style.&lt;/li&gt;
&lt;li&gt;Close the custom pop-up box.
Due to the need to pass in the Component Content corresponding to the pop-up box to be closed for the closeCustoms Dialog interface. Therefore, if you need to set a closing method in the pop-up box, you can refer to the complete example to encapsulate the static method for implementation.
If you need to release the corresponding WidgetContent after closing the pop-up box, you need to call the dispose method of WidgetContent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { BusinessError } from '@kit.BasicServicesKit';
import { ComponentContent, promptAction, UIContext } from '@kit.ArkUI';


@Entry
@Component
struct OpenCustomDialogPage {
  build() {
    Column({ space: 10 }) {
      Text('OpenCustomDialogPage')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Button('open dialog').onClick(() =&amp;gt; {
        Dialog.setContext(this.getUIContext());
        Dialog.setOptions({ alignment: DialogAlignment.Center });
        let contentNode: ComponentContent&amp;lt;Object&amp;gt; =
          new ComponentContent(this.getUIContext(), wrapBuilder(buildText), new Params('hello, you open a dialog'));
        Dialog.setContentNode(contentNode);
        Dialog.openDialog()
      })
    }
    .height('100%')
    .width('100%')
  }
}

@Builder
function buildText(params: Params) {
  Column() {
    Text(params.text)
      .fontSize(30)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 36 })
    Button('Close')
      .onClick(() =&amp;gt; {
        Dialog.closeDialog();
      })
  }
  .backgroundColor('#FFF0F0F0')
  .padding(20)
  .borderRadius(8)
  .clip(true)
  .margin(20)
}

class Dialog {
  static ctx: UIContext;
  static contentNode: ComponentContent&amp;lt;Object&amp;gt;;
  static options: promptAction.BaseDialogOptions;

  static setContext(context: UIContext) {
    Dialog.ctx = context;
  }

  static setContentNode(node: ComponentContent&amp;lt;Object&amp;gt;) {
    Dialog.contentNode = node;
  }

  static setOptions(options: promptAction.BaseDialogOptions) {
    Dialog.options = options;
  }

  static openDialog() {
    if (Dialog.contentNode !== null) {
      Dialog.ctx.getPromptAction()
        .openCustomDialog(Dialog.contentNode, Dialog.options)
        .then(() =&amp;gt; {
          console.info('OpenCustomDialog complete.');
        })
        .catch((error: BusinessError) =&amp;gt; {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }

  static updateDialog(options: promptAction.BaseDialogOptions) {
    if (Dialog.contentNode !== null) {
      Dialog.ctx.getPromptAction().updateCustomDialog(Dialog.contentNode, options)
        .then(() =&amp;gt; {
          console.info('UpdateCustomDialog complete.');
        })
        .catch((error: BusinessError) =&amp;gt; {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }

  static closeDialog() {
    if (Dialog.contentNode !== null) {
      Dialog.ctx.getPromptAction()
        .closeCustomDialog(Dialog.contentNode)
        .then(() =&amp;gt; {
          console.info('CloseCustomDialog complete.');
        })
        .catch((error: BusinessError) =&amp;gt; {
          let message = (error as BusinessError).message;
          let code = (error as BusinessError).code;
          console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`);
        })
    }
  }
}

class Params {
  text: string = "";

  constructor(text: string) {
    this.text = text;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：import and use axios</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 09:04:26 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceimport-and-use-axios-18d5</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceimport-and-use-axios-18d5</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios" rel="noopener noreferrer"&gt;https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What is Axios?&lt;br&gt;
Axios is a promise based network request library that works on Node.js and browsers. It is polymorphic (i.e. the same set of code can run in both the browser and Node.js). On the server side, it uses the native Node.js HTTP module, while on the client side (browser side), it uses XMLHttpRequests.&lt;/p&gt;

&lt;p&gt;Introduction to Axios of HarmonyOS Third Party Library:&lt;br&gt;
This is a promise based network request library that can run Node.js and in browsers. This library is adapted based on the Axios original library v1.3.4 version, allowing it to run on OpenHarmony while retaining its existing usage and features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request&lt;/li&gt;
&lt;li&gt;Promise API&lt;/li&gt;
&lt;li&gt;Request and response interceptors&lt;/li&gt;
&lt;li&gt;Convert the data of request and response&lt;/li&gt;
&lt;li&gt;Automatically convert JSON data data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initiate a GET request:&lt;br&gt;
Axios supports generic parameters, but since ArkTS no longer supports any type, the specific type of the parameter needs to be specified. For example: Axios.get, D=any&amp;gt;(URL)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;T: It is a response data type. When sending a POST request, the client may receive a JSON object. T is the type of this JSON object. By default, T is any, which means it can receive any type of data.&lt;/li&gt;
&lt;li&gt;R: It is the type of response body. When the server returns a response, the response body is usually a JSON object. R is the type of this JSON object. By default, R is AxiosResponse, which means that the response body is an AxiosResponse object with a data property of type T&lt;/li&gt;
&lt;li&gt;D: It is the type of request parameter. When sending a GET request, some query parameters may be added to the URL. D is the type of these query parameters. When the parameter is empty, D is of null type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;app store&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ohpm install @ohos/axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Permission required&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ohos.permission.INTERNET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify the modular.json5 configuration file to add network permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create BaseRequest utility class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse }  from '@ohos/axios'
import { promptAction } from '@kit.ArkUI'

class BaseRequest {
  instance: AxiosInstance;

  //构造器
  constructor(config: AxiosRequestConfig&amp;lt;AxiosResponse&amp;gt;) {
    this.instance = axios.create(config);
    // 请求拦截
    this.instance.interceptors.request.use((config) =&amp;gt; {
        const token = '获取自己本地储存的token';
        if (token) {
          config.headers.token = token;
        }
        console.log('Request config', config);
        return config;
      }, (err) =&amp;gt; {
        console.error('Request error', err);
        return Promise.reject(err);
      }
    );

    // 响应拦截
    this.instance.interceptors.response.use((response: AxiosResponse&amp;lt;any, any&amp;gt;) =&amp;gt; {
        let data = response.data;
        console.log('Response data', data);
        if (typeof data === 'string') {
          data = JSON.parse(data.trim());
        }
        const { code, msg } = data;
        if (code === 200) {  // 处理成功情况
            return response.data;
        } else if (code === 400) { // 处理错误码
          promptAction.showToast({
            message: msg
          });
          return Promise.reject(new Error(msg));
        } else if (code === 500) {
          promptAction.showToast({
            message: msg
          });
          return response.data;
        } else { // 处理其他错误码
          promptAction.showToast({
            message: msg
          });
          return Promise.reject(new Error(msg));
        }
      }, (err) =&amp;gt; {
        console.error('Response error', err);
        return Promise.reject(err);
      }
    );
  }

  request&amp;lt;T = any&amp;gt;(config: AxiosRequestConfig): Promise&amp;lt;T&amp;gt; {
    console.log('Request config', config);
    return this.instance.request&amp;lt;any, T&amp;gt;(config);
  }

  get&amp;lt;T = any&amp;gt;(config: AxiosRequestConfig): Promise&amp;lt;T&amp;gt; {
    return this.request&amp;lt;T&amp;gt;({ ...config, method: 'GET' });
  }

  post&amp;lt;T = any&amp;gt;(config: AxiosRequestConfig): Promise&amp;lt;T&amp;gt; {
    return this.request&amp;lt;T&amp;gt;({ ...config, method: 'POST' });
  }
}

export const axiosAPI = new BaseRequest ({
  baseURL: '自己接口地址',
  timeout: 60000
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { axiosAPI } from '../BaseRequest'

export const getList = (id:string) =&amp;gt;{
  return axiosAPI.get&amp;lt;object&amp;gt;({url:'自己的请求地址',
    params:{
      "id":id
    }})
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Network status monitoring</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 08:59:11 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practicenetwork-status-monitoring-4246</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practicenetwork-status-monitoring-4246</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-network-61" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-network-61&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;@ohos.net connection (network connection management)&lt;br&gt;
Network connection management provides basic capabilities for managing networks, including priority management of multiple network connections such as WiFi/cellular/Ethernet, network quality assessment, subscribing to default/specified network connection status changes, querying network connection information, DNS resolution, and other functions.&lt;/p&gt;

&lt;p&gt;connection.createNetConnection&lt;br&gt;
Create a NetConnection object, netSpecifier, to specify the various features of the network to be focused on; Timeout is the timeout period (in milliseconds); NetSpecifier is a necessary condition for timeout, and if neither is present, it indicates attention to the default network.&lt;/p&gt;

&lt;p&gt;Idea: By using the ability of @ ohos.net.connection, when the network connection status changes, judge whether the current network can access the Internet, and store the judgment results in AppStorage. When it is necessary to determine the network connection status, directly obtain the results from AppStore.&lt;/p&gt;

&lt;p&gt;prerequisite:&lt;br&gt;
Modify the modular.json5 configuration file to add network permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO"
      }
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the NetworkUtil utility class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { connection } from "@kit.NetworkKit";
import { BusinessError } from "@kit.BasicServicesKit";
import { promptAction } from "@kit.ArkUI";
import { hilog } from "@kit.PerformanceAnalysisKit";

export class NetworkUtil {
  private static netConnection: connection.NetConnection | undefined = undefined;
  public static JUDGE_NET_TAG: string = 'NetworkUtil.netConnection.isUseful';

  /**
   * 工具注册。
   * 作用：监控网络状态
   */
  static register() {
    if (NetworkUtil.netConnection === undefined) {
      NetworkUtil.init();
    }
  }

  /**
   * 获取网络连接状态
   * @returns boolean
   * true: 有网络
   * false: 无网络
   */
  static getStatus(): boolean {
    return NetworkUtil.judgeHasNet()
  }

  static continueWhenNetUsable(callback: () =&amp;gt; void) {
    if (NetworkUtil.getStatus()) {
      callback()
    } else {
      promptAction.showToast({
        message: 'The network is not worked, please check your network',
        duration: 2000
      });
    }
  }

  private static init() {
    NetworkUtil.netConnection = connection.createNetConnection();
    NetworkUtil.netConnection.register(() =&amp;gt; {
      Logger.info('connection register success');
    });

    NetworkUtil.netConnection.on('netAvailable', (data) =&amp;gt; {
      Logger.info('NetworkUtil netAvailable ');
      AppStorage.setOrCreate(NetworkUtil.JUDGE_NET_TAG, NetworkUtil.judgeHasNet());
    });

    NetworkUtil.netConnection.on('netUnavailable', () =&amp;gt; {
      Logger.info('NetworkUtil netUnavailable ');
      AppStorage.setOrCreate(NetworkUtil.JUDGE_NET_TAG, NetworkUtil.judgeHasNet());
    });

    NetworkUtil.netConnection.on('netCapabilitiesChange', (data: connection.NetCapabilityInfo) =&amp;gt; {
      Logger.info('NetworkUtil netCapabilitiesChange');
      AppStorage.setOrCreate(NetworkUtil.JUDGE_NET_TAG, NetworkUtil.judgeHasNet());
    });

    // 订阅网络连接信息变化事件。调用register后，才能接收到此事件通知
    NetworkUtil.netConnection.on('netConnectionPropertiesChange', (data: connection.NetConnectionPropertyInfo) =&amp;gt; {
      Logger.info('NetworkUtil netConnectionPropertiesChange');
      AppStorage.setOrCreate(NetworkUtil.JUDGE_NET_TAG, NetworkUtil.judgeHasNet());
    });

    NetworkUtil.netConnection.on('netLost', () =&amp;gt; {
      Logger.info('NetworkUtil netLost');
      AppStorage.setOrCreate(NetworkUtil.JUDGE_NET_TAG, NetworkUtil.judgeHasNet());
    });
  }

  private static judgeHasNet(): boolean {
    try { // 获取当前网络连接
      let netHandle = connection.getDefaultNetSync();

      // 0-100 为系统预留的连接
      if (!netHandle || netHandle.netId &amp;lt; 100) {
        return false;
      }

      // 获取连接的属性
      let netCapability = connection.getNetCapabilitiesSync(netHandle);
      let cap = netCapability.networkCap;
      if (!cap) {
        return false;
      }

      for (let em of cap) {
        if (connection.NetCap.NET_CAPABILITY_VALIDATED === em) {
          return true;
        }
      }
    } catch (e) {
      let err = e as BusinessError;
      Logger.info('get netInfo error ：' + JSON.stringify(err));
    }
    return false;
  }
}

class Logger{
  static info(...args: string[]){
    hilog.info(0x0000, '-logger-', getFormat(args), args);
  }
}

function getFormat(args: string[]) {
  let format = ''
  for (let i = 0; i &amp;lt; args.length; i++) {
    if (i == 0) {
      format = '%{public}s'
    } else {
      format += ', %{public}s'
    }
  }
  return format
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample code for using the NetworkUtilPage page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NetworkUtil } from '../../utils/NetworkUtil'
import { promptAction } from '@kit.ArkUI';

@Entry
@Component
struct NetworkUtilPage {
  //用法一：通过状态管理实时获取网络状态
  @StorageProp(NetworkUtil.JUDGE_NET_TAG)
  isNetConnectionUseful: boolean = true;

  aboutToAppear(): void {
    NetworkUtil.register()
  }

  build() {
    Column({ space: 10 }) {
      Text('NetworkUtil Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text() {
        Span('watch network status is ')
        Span(JSON.stringify(this.isNetConnectionUseful))
          .fontColor(this.isNetConnectionUseful ? Color.Green : Color.Red)
          .fontWeight(600)
      }

      Button('getNetworkStatus').onClick(() =&amp;gt; {
        //用法二：获取当前的网络状态
        const status = NetworkUtil.getStatus()
        promptAction.showToast({
          message: 'The network status is ' + JSON.stringify(status),
          duration: 5000
        });
      })

      Button('continue When Net Usable').onClick(() =&amp;gt; {
        //用法三：有网络继续后续动作，无网则中断后续动作并且弹窗提示用户设置网络。
        NetworkUtil.continueWhenNetUsable(() =&amp;gt; {
          //当网络中断，弹窗提示用户设置网络且不执行后续动作
          //当网络可用，继续执行
          promptAction.showToast({
            message: 'have net, continue!',
            duration: 5000
          });
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Using an emitter for inter thread communication</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 08:54:23 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceusing-an-emitter-for-inter-thread-communication-54m5</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceusing-an-emitter-for-inter-thread-communication-54m5</guid>
      <description>&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/itc-with-emitter" rel="noopener noreferrer"&gt;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/itc-with-emitter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An emitter is an event handling mechanism that operates within a process, providing applications with the ability to subscribe to events, publish events, and unsubscribe from events.&lt;/p&gt;

&lt;p&gt;Scene introduction:&lt;br&gt;
The emitter is used for event processing within the same process or between different threads, with asynchronous execution of events. When using, you need to subscribe to an event first, and then publish the event. After the publication is completed, the emitter will distribute the published event to the subscribers, and the subscribers will execute the callback method set when subscribing to the event. When there is no need to subscribe to the event, the subscription should be cancelled in a timely manner to release the emitter resources.&lt;/p&gt;

&lt;p&gt;Operating mechanism:&lt;br&gt;
The emitter distributes tasks by maintaining an internal event queue. The application needs to subscribe to an event and set the callback method for that event first. After the application publishes the event, it will insert an event into the queue. The task queue will execute the tasks in the queue sequentially, and the callback method of the task subscriber will be called for event processing during task execution.&lt;/p&gt;

&lt;p&gt;Interface Description:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send: Publish an event once.&lt;/li&gt;
&lt;li&gt;On: Continuously subscribe to the event until it is unsubscribed.&lt;/li&gt;
&lt;li&gt;Once: Subscribe to an event once.&lt;/li&gt;
&lt;li&gt;Off: Cancel all subscription events. After canceling the event subscription, all subscribed events will no longer receive messages for that event.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instructions for canceling event subscription:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When there is no need to subscribe to an event, it is necessary to unsubscribe in a timely manner to avoid memory leaks.&lt;/li&gt;
&lt;li&gt;After using the off interface to unsubscribe from an event, events that have been published through the emit interface but have not yet been executed will be canceled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { emitter } from '@kit.BasicServicesKit'

@Entry
@Component
struct EmitterPage {
  @State onResult: string = 'Emitter.on result is : '
  @State onceResult: string = 'Emitter.once result is : '
  @State emitResult: string = 'Emitter.emit result is : '
  @State count: number = 0

  build() {
    Column({ space: 10 }) {
      Text('Emitter Page')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text(`count=${this.count}`)

      Button('Emitter.on').onClick(() =&amp;gt; {
        // 定义一个eventId为1的事件。
        let event: emitter.InnerEvent = {
          eventId: 1
        };
        // 定义一个事件的回调处理函数，当收到对应的事件后执行回调函数
        let callback: Callback&amp;lt;emitter.EventData&amp;gt; = (eventData: emitter.EventData) =&amp;gt; {
          console.info(`eventData: ${JSON.stringify(eventData)}`);
          this.onResult = JSON.stringify(eventData)
        }
        // 收到eventId为1的事件后执行回调函数
        emitter.on(event, callback);
      })
      Text(this.onResult)

      Button('Emitter.once').onClick(() =&amp;gt; {
        // 定义一个eventId为1的事件。
        let event: emitter.InnerEvent = {
          eventId: 1
        };
        // 定义一个事件的回调处理函数，当收到对应的事件后执行回调函数
        let callback: Callback&amp;lt;emitter.EventData&amp;gt; = (eventData: emitter.EventData) =&amp;gt; {
          console.info(`eventData: ${JSON.stringify(eventData)}`);
          this.onceResult = JSON.stringify(eventData)
        }
        // 收到eventId为1的事件后执行回调函数
        emitter.once(event, callback);
      })
      Text(this.onceResult)

      Button('Emitter.emit').onClick(() =&amp;gt; {
        this.count = this.count + 1
        // 定义一个eventId为1的事件，事件优先级为Low。
        let event: emitter.InnerEvent = {
          eventId: 1,
          priority: emitter.EventPriority.LOW
        };
        let eventData: emitter.EventData = {
          data: {
            content: 'emitter',
            count: this.count,
            id: 1,
            isEmpty: false
          }
        };
        // 发送eventId为1的事件，事件内容为eventData。
        emitter.emit(event, eventData);
      })
      Text(this.emitResult)

      Button('Emitter.off').onClick(() =&amp;gt; {
        // 取消eventId为1的事件。
        emitter.off(1);
      })
    }
    .height('100%')
    .width('100%')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：Share content through QQ</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 08:48:33 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceshare-content-through-qq-1man</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceshare-content-through-qq-1man</guid>
      <description>&lt;p&gt;Prerequisite: QQ SDK has been imported&lt;/p&gt;

&lt;p&gt;reference material:&lt;br&gt;
&lt;a href="https://wiki.connect.qq.com/harmonyos_sdk%e6%8e%a5%e5%8f%a3%e8%af%b4%e6%98%8e" rel="noopener noreferrer"&gt;https://wiki.connect.qq.com/harmonyos_sdk%e6%8e%a5%e5%8f%a3%e8%af%b4%e6%98%8e&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following is the actual code practice of the HarmonyOS project shared through QQ:&lt;br&gt;
Preconditions:&lt;br&gt;
Modify the oh-package.json5 file to integrate CryptoJS dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "dependencies": {
    "@tencent/wechat_open_sdk": "1.0.11",
    "@ohos/crypto-js": "^2.0.4"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Function: Generate signatures using the HMAC-SHA1 algorithm&lt;/p&gt;

&lt;p&gt;Share business development process instructions:&lt;br&gt;
To ensure the credibility of business shared data, it is necessary to sign the shared data. Taking the example of sharing graphic and text ark messages, we recommend the following process for business:&lt;br&gt;
Business client: When users share, the shared UGC content is transmitted to the business backend.&lt;br&gt;
Business backend: Use user UGC data to assemble ark business JSON data (ShareData. shareJson), generate timestamps (ShareData. timestamp) and random natural numbers (ShareData. once) in ShareData, and perform signature calculations on these three parts of data. The above data is then called back to the business client, which initiates sharing by calling the interconnection sharing interface.&lt;/p&gt;

&lt;p&gt;Parameter description:&lt;br&gt;
Type: Sharing type, currently supports graphic and text ark type 2&lt;br&gt;
ShareData: Share data, including shared business data and signed partial data&lt;/p&gt;

&lt;p&gt;The signature steps are as follows:&lt;br&gt;
Splicing the original signed text. The splicing rule for the original signature string is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request method+request domain name+request path+? +Request string+Share content JSON string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Request method: Fixed as POST, note all uppercase&lt;/li&gt;
&lt;li&gt;Interface domain name: fixed as connect.qq.com&lt;/li&gt;
&lt;li&gt;Request path: fixed as/share&lt;/li&gt;
&lt;li&gt;Request string: concatenate signature parameters and values in lexicographic order into a string, such as:
appid=222222&amp;amp;nonce=1234&amp;amp;ts=1618924373&lt;/li&gt;
&lt;li&gt;Request body: a JSON string composed of shared content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming the sharing parameters are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; appid：222222&lt;/li&gt;
&lt;li&gt; nonce：1234&lt;/li&gt;
&lt;li&gt; ts：1618924373&lt;/li&gt;
&lt;li&gt; Share content:
{"msc_style": 0, "title": "title", "summary": "content", "brief": "internet sharing", "URL":“ &lt;a href="https://www.qq.com" rel="noopener noreferrer"&gt;https://www.qq.com&lt;/a&gt; ","picture_url":" &lt;a href="https://www.qq.com/picture.png" rel="noopener noreferrer"&gt;https://www.qq.com/picture.png&lt;/a&gt; "}
The original text of the signature spelled out according to the rules is as follows:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POSTconnect.qq.com/share?appid=222222&amp;amp;nonce=1234&amp;amp;ts=1618924373&amp;amp;{"msg_style": 0, "title":"标题", "summary":"内容", "brief":"互联分享", "url":"https://www.qq.com", "picture_url":"https://www.qq.com/picture.png"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Calculate Signature
This step generates a signature string. Firstly, use the HMAC-SHA1 algorithm to sign the original signature string obtained in the previous step, and then encode the generated signature string using Base64 to obtain the final signature string. Assuming the appkey is fakeAppKey, the final signature result obtained is:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ngyk0JS5pQR8ffygeeMHFUNFQQA=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add QQUtil.ets&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CryptoJS } from '@ohos/crypto-js'

export class QQUtil {
  /**
   * 分享
   * @param title 标题
   * @param summary 内容
   * @param brief QQ信息列表显示的内容
   * @param imageUrl 图片链接
   * @param url 跳转链接
   */
  static share(title: string, summary: string, brief: string, imageUrl: string, url: string) {
    let content = new Object({
      msg_style: 0,
      title: title,
      summary: summary,
      brief: brief,
      url: url,
      picture_url: imageUrl
    })
    let shareData: ShareData = new ShareData()
    shareData.timestamp = Date.parse(new Date().toString()) / 1000
    shareData.nonce = Math.floor(Math.random() * 100000000 + 100)
    shareData.shareJson = JSON.stringify(content)
    let signContent = 'POSTconnect.qq.com/share?appid=' + AppConfigs.qqsdkAppId.toString()
      + '&amp;amp;nonce=' + shareData.nonce.toString()
      + '&amp;amp;ts=' + shareData.timestamp.toString()
      + '&amp;amp;' + shareData.shareJson
    const hmac = CryptoJS.HmacSHA1(signContent, AppConfigs.qqsdkAppKey);
    let sign = hmac.toString(CryptoJS.enc.Base64);

    shareData.shareJsonSign = sign
    const qqOpenApi = QQUtil.getQQOpenApi()
    qqOpenApi.share(2, shareData).then((result: ShareResult) =&amp;gt; {
      Logger.info(`qqOpenApi.share, result=${JSON.stringify(result)}`)
      switch (result.resultType) {
        case ShareResultType.Success: {
          promptAction.showToast({ message: "分享成功" })
        }
          break
        case ShareResultType.Cancel: {
          let msg: string = result.message ?? "用户取消分享"
          promptAction.showToast({ message: msg })
        }
          break
        case ShareResultType.Error: {
          let msg: string = result.message ?? "分享失败"
          promptAction.showToast({ message: msg })
        }
          break
      }
    })
      .catch((err: BusinessError) =&amp;gt; {
        Logger.error(`error, code=${JSON.stringify(err.code)}, message=${JSON.stringify(err.message)}`)
      })
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>HarmonyOS NEXT project practice：import QQ SDK</title>
      <dc:creator>victordeng</dc:creator>
      <pubDate>Sun, 29 Jun 2025 08:43:30 +0000</pubDate>
      <link>https://dev.to/victordeng/harmonyos-next-project-practiceimport-qq-sdk-3jic</link>
      <guid>https://dev.to/victordeng/harmonyos-next-project-practiceimport-qq-sdk-3jic</guid>
      <description>&lt;p&gt;reference material&lt;br&gt;
Mobile application access process:&lt;br&gt;
&lt;a href="https://wiki.connect.qq.com/%e7%a7%bb%e5%8a%a8%e5%ba%94%e7%94%a8%e6%8e%a5%e5%85%a5%e6%b5%81%e7%a8%8b" rel="noopener noreferrer"&gt;https://wiki.connect.qq.com/%e7%a7%bb%e5%8a%a8%e5%ba%94%e7%94%a8%e6%8e%a5%e5%85%a5%e6%b5%81%e7%a8%8b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HarmonyOS_SDK environment setup:&lt;br&gt;
&lt;a href="https://wiki.connect.qq.com/harmonyos_sdk%e7%8e%af%e5%a2%83%e6%90%ad%e5%bb%ba" rel="noopener noreferrer"&gt;https://wiki.connect.qq.com/harmonyos_sdk%e7%8e%af%e5%a2%83%e6%90%ad%e5%bb%ba&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK Demo Download:&lt;br&gt;
&lt;a href="https://wiki.connect.qq.com/sdk%e4%b8%8b%e8%bd%bd" rel="noopener noreferrer"&gt;https://wiki.connect.qq.com/sdk%e4%b8%8b%e8%bd%bd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mobile application access process:&lt;br&gt;
Mobile applications can access the Internet Open Platform through the following steps[ &lt;a href="https://connect.qq.com" rel="noopener noreferrer"&gt;https://connect.qq.com&lt;/a&gt;] ：&lt;br&gt;
Developer Registration&amp;gt;Mobile Application Application&amp;gt;Mobile Application Development&amp;gt;Call OpenAPI&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developer registration
On the homepage of QQ Internet Open Platform &lt;a href="http://connect.qq.com/" rel="noopener noreferrer"&gt;http://connect.qq.com/&lt;/a&gt; Click the "Login" button in the upper right corner and log in with your QQ account. After successful login, you will be redirected to the developer registration page, where you need to submit your company or personal basic information.&lt;/li&gt;
&lt;li&gt;Mobile application access application&lt;/li&gt;
&lt;li&gt;Before accessing the mobile application, it is necessary to first apply and obtain the corresponding appid and appkey to ensure that the mobile application and user can be verified and authorized correctly in the subsequent process.&lt;/li&gt;
&lt;li&gt;If your PC application has already been connected to Tencent Open Platform, you do not need to obtain a new appid and appkey. Simply use the appid obtained when connecting to Tencent Open Platform to add it as a mobile application.&lt;/li&gt;
&lt;li&gt;Add mobile application: After the developer successfully registers, they will be redirected to the "Management Center" page. Click on 'Add Mobile App' and fill in the corresponding information.&lt;/li&gt;
&lt;li&gt;After filling in the mobile application information, click "OK" to complete the registration of the mobile application. Enter the management center and you can view the appid and appkey obtained by the mobile application&lt;/li&gt;
&lt;li&gt;Mobile application development
Entering the console page, you can see that the mobile application application is in the "development" status. To launch a mobile application, the first step is to develop the mobile application, which is to complete the QQ login function and place the QQ login button normally.&lt;/li&gt;
&lt;li&gt;Use OpenAPI provided by QQ Internet
After completing the development of the mobile application, you can click on "Apply for Online" under "Current Process" on the "Console" page of the "Management Center", and the process will be in the "Review" state.
After submission for review, Tencent will complete the review within two working days. Once the review is approved, the mobile application will be officially launched.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Development Description&lt;br&gt;
The QQ login function uses the internationally recognized OAuth2.0 protocol for verification and authorization, and can be used for mobile application development through the following methods:&lt;br&gt;
(1) QQ Internet provides SDK development packages for iOS and Android respectively. If QQ is installed on the phone, start QQ on the phone for SSO login. If not installed, log in through the mobile system's browser. The login process has been integrated into the SDK, and it is recommended that developers use this method. See: SDK Download&lt;br&gt;
(2) According to the QQ login OAuth2.0 protocol, independently developed, this method has a high degree of customization and can be used for mobile applications that require integration with existing systems.&lt;/p&gt;

&lt;p&gt;Hongmeng project configuration:&lt;br&gt;
Add dependencies and execute commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ohpm i @tencent/qq-open-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running, you can see the newly added dependency libraries in the project level oh-package.json5 file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "dependencies": {
    "@tencent/qq-open-sdk": "^1.0.3"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify module configuration:&lt;br&gt;
Modify the module.json5 file of entry and configure skills&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        "skills": [
          {
            "entities": [
              "entity.system.home",
              "entity.system.browsable"
            ],
            "actions": [
              "action.system.home",
              "ohos.want.action.viewData"
            ],
            "uris": [
              {
                "scheme": "qqopenapi", // 接收 QQ 回调数据
                "host": "xxxxxxxxx", // 业务申请的互联 appId，如果填错会导致 QQ 无法回调
                "pathRegex": "\\b(auth|share)\\b",
                "linkFeature": "Login",
              }
            ]
          }
        ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Continue to modify the modular.json5 file of entry and add queryPlans&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "querySchemes": [
      "https",
      "qqopenapi"
    ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add SDK tool classes:&lt;br&gt;
Add QQOpenApiHolder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { SdkConfig } from '@heduohao/bases'
import { IQQOpenApi, OpenApiConfig, QQOpenApiFactory } from '@tencent/qq-open-sdk'

export class QQOpenApiHolder {
  private static qqOpenApi: IQQOpenApi

  private constructor() {

  }

  public static create(): IQQOpenApi {
    if (!QQOpenApiHolder.qqOpenApi) {
      let openApiOption: OpenApiConfig = {
        forceEnableWeb: false,
        autoHandleAuthResult: true,
      }

      QQOpenApiHolder.qqOpenApi =
        QQOpenApiFactory.createApi(SdkConfig.QQ_SDK_APP_ID, openApiOption)
    }
    return QQOpenApiHolder.qqOpenApi
  }

  public static getInstance(): IQQOpenApi {
    return QQOpenApiHolder.qqOpenApi
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;EntryAbility connects to QQOpenApiHolder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
    QQOpenApiHolder.create()
  }

  onNewWant(want: Want, _launchParam: AbilityConstant.LaunchParam): void {
    QQOpenApiHolder.getInstance()?.handleResult(want)
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
