Usage FAQs

Image Display Issue When Loading Bundle from Sandbox

  • Symptom

    When loading a bundle from local rawfile in an OpenHarmony project, the Image component on the RN page can properly display local images. However, when loading the bundle from sandbox, the Image component cannot display images.

  • Cause

    For loading images from sandbox, resource files need to be placed according to the decompression location of the bundle files.

  • Solution

    For reading image resources in sandbox, refer to Document.

    For loading images from sandbox, resource files need to be placed according to the decompression location of the bundle files. Refer to the following:

  • Packing Scenario

    • Packing Path

      Assume the packing path is root path: /, RN code path: /aaa/bbb/c.tsx,

      Image 1 path: /aaa/bbb/d.png, RN usage: require('./d.png'),

      Image 2 path: /eee/f.png, RN usage: require('../../eee/f.png'),

      Image 3 path: /aaa/ggg/h.png, RN usage: require('../ggg/h.png').

    • Image Path Prefix

      Image 1 generated path prefix: /aaa/bbb/

      Image 2 generated path prefix: /eee/

      Image 3 generated path prefix: /aaa/ggg/

    • Resource Packing Result

      assets is the directory specified in package.json. Developers can set any subdirectory under assets.

      Reference example, users can customize subdirectories such as aaa, bbb, ggg, eee:

      assets/aaa/bbb/d.png, assets/aaa/ggg/h.png, assets/eee/f.png.

  • Sandbox Scenario Image Path

    In sandbox scenario, assume bundle path is /data/storage/base/files/dir1/bundle.harmony.js.

    • Image 1 sandbox actual path: /data/storage/base/files/dir1/aaa/bbb/d.png.
    • Image 2 sandbox actual path: /data/storage/base/files/dir1/eee/f.png.
    • Image 3 sandbox actual path: /data/storage/base/files/dir1/aaa/ggg/h.png.

    Important: In sandbox scenario, the image path uses the bundle path as prefix, and the relative path of image to project packing path as suffix, forming the complete path. There is no assets directory here.

    Path Example:

    <Image source={{ uri: 'file:///data/storage/el2/base/files/10.png' }}
              style={{ width: 200, height: 200 }} />
    
  • RAWFILE Scenario Image Path

    In RAWFILE scenario, assume bundle path is resource://RAWFILE/dir1/bundle.harmony.js.

    • Image 1 rawfile actual path: resource://RAWFILE/assets/aaa/bbb/d.png.
    • Image 2 rawfile actual path: resource://RAWFILE/assets/eee/f.png.
    • Image 3 rawfile actual path: resource://RAWFILE/assets/aaa/ggg/h.png. Important: In RAWFILE scenario, the image path prefix is specified as resource://RAWFILE/assets/, and the relative path of image to project packing path as suffix, forming the complete path. There is an assets directory here.
  • Symptom

    The modal dialog still displays at the top layer after route navigation.

  • Cause

    This is a specification issue. OpenHarmony's modal corresponds to ArkUI's Dialog. Currently, Dialog's UI specification is at the top layer of the window, hence this issue.

  • Solution

    There are two workaround solutions:

    • Close the modal proactively when navigating.
    • Do not use modal, implement modal's UI effect through view.
  • Reference

    OpenHarmony specification document.

How to Hide the Scrollbar on the Right Side of FlashList

  • Symptom

    Want to hide the scrollbar on the right side of FlashList.

  • Cause

    None.

  • Solution

    • Hide vertical scrollbar

      showsVerticalScrollIndicator={false}// Hide vertical scrollbar

    • Hide horizontal scrollbar

      showsHorizontalScrollIndicator={false}// Hide horizontal scrollbar

Animated Component Performance Issue When useNativeDriver is Set to false

  • Symptom

    When using RN Animated component and setting useNativeDriver to false, lagging occurs (because useNativeDriver doesn't support translateX property in Animated, cannot set useNativeDriver to true). This also causes other performance issues.

    When using react-native-page-view library, configuring useNativeDriver method in onPageScroll also has this issue.

  • Cause

    Not a bug, caused by improper usage.

  • Solution

    Use transform instead of top, i.e., use scaleX and scaleY of transform to transform width and height.

    (1) Original problematic code example:

    <Animated.View
        style={{
          width: 300,
          height: 204,
          position: 'absolute',
          top:macTop,
          left:macTop,
        }}>
        <Image ref="image" style={{ width: 375, height: 242 }}
          source={require('./keli.png')}>
        </Image>
      </Animated.View>
    

    (2) Solution code example:

    // Initialize animation values
    const scaleX = useRef(new Animated.Value(1)).current;
      const scaleY = useRef(new Animated.Value(1)).current;
    
      return (
         <View style={styles.container}>
            <Animated.View
              style={[
                styles.box,
                {
                  transform: [
                  { scaleX: scaleX }, // Transform width
                  { scaleY: scaleY }, // Transform height
                  ],
                },
              ]}
            />
            <Button title="Start Animation" onPress={startScaleAnimation} />
         </View>
      );
    

Font Size Display Issue in Version 5.0.0.500

  • Symptom

    • Symptom 1: Same bundle package, in custom UIAbility scenario, font display may appear significantly smaller.
    • Symptom 2: Project using RNAbility, when using Metro service to load RN page, font becomes smaller; when loading local bundle, font displays normally.
  • Cause

    This version of RNOH's RNInstancesCoordinator added fontSizeScale parameter, corresponding to native fontSizeScale, representing font size scaling ratio. Value range: 0~3.2, default value is 1.

    The two recent cases about RN page font becoming smaller, analysis found that both were caused by loading bundle too early or creating RNInstancesCoordinator too late. CPP side gets fontScale value through RNInstancesCoordinator's fontSizeScale. If RNInstancesCoordinator is created too late and RN page is loaded beforehand, CPP side rendering will have fontScale as 0, while normal value is 1, causing significantly smaller display.

    The specific causes for these two scenarios are:

    - Symptom 1 cause: When using custom `UIAbility`, when creating RNInstancesCoordinator and opening RN page, RNInstancesCoordinator was not initialized beforehand, causing `fontSizeScale` to not be successfully passed to CPP side.
    - Symptom 2 cause: Code in `onWindowStageCreate` executed pre-loading Metro bundle operation. When loading Metro, RNOH's CPP side had not yet received the default `fontScale` value passed by RNInstancesCoordinator, so Metro service loaded RN page with smaller font.
    
  • Solution

    • Symptom 1 solution: Submit initialization of RNInstancesCoordinator in Ability.onWindowStageCreate() lifecycle.
    • Symptom 2 solution: Delay the execution of pre-loading Metro bundle code.

Horizontal Swipe Triggering RN Page Click Events When TABHost Nested with RN Page

  • Symptom

    When a page's TABHost nests an RN page, horizontal swipe will easily trigger click events in the RN page.

  • Cause

    Horizontal swipe causes gesture conflicts at native level, need to call corresponding method to cancel click events during native swipe.

  • Solution

    Call this.rnohCoreContext?.cancelTouches() method during native swipe. Specific code:

    private rnContext:RNOHCoreContext|undefined = AppStorage.get('RNOHCoreContext'); // RN-500 version
      .onGestureSwipe((index: number, event: TabsAnimationEvent) => {
      if(this.rnContext) {
      this.rnContext.cancelTouches();
      }
      })
    

Hermes Compilation Guide

  • Symptom

    If business scenario has requirements, need to customize compile hermes, can refer to the following steps.

  • Cause

    None.

  • Solution

    Not recommended to compile hermes yourself unless necessary.

    • Resource Preparation

      • Compilation script: Can be obtained from RN Harmony repository;

      • Hermes source code and dependencies: Compilation requires hermes source code and JSI source code (can be obtained by extracting rnoh source package, e.g.: react_native_openharmony-5.0.0.601.har);

      • SDK: Use IDE's built-in SDK;

      • Operating System: MacOS or Linux.

    • Compilation Process

      1. Extract har package: Find an empty directory (e.g., temp), copy har package to this directory, then extract. After extraction, you'll see a package folder.
      2. Download hermes source code: Download hermes source code through hermes source code link, then replace the package/src/main/cpp/third-party/hermes folder.
      3. Download compilation script: Download compilation script through above link, then copy to package/src/main/cpp/third-party/scripts path (create scripts directory if not exists).
      4. Configure SDK environment variable: Configure the path of sdk/default/openharmony in IDE in system environment variable, environment variable name is OHOS_SDK, or write this path in compilation script.
      5. Adjust compilation script according to below code:
        #!/bin/bash
        
        + OHOS_SDK=Your SDK path # If step 3 was done, this can be ignored
        ...
        - THIRD_PARTY_DIR=$SCRIPT_DIR/../harmony/cpp/third-party
        + THIRD_PARTY_DIR=../
        ...
        - OHOS_SDK_NATIVE_DIR=$OHOS_SDK/10/native
        + OHOS_SDK_NATIVE_DIR=$OHOS_SDK/native
        ...
        - JSI_DIR=$THIRD_PARTY_DIR/rn/ReactCommon/jsi
        + JSI_DIR=Absolute path to jsi
        ...
        - -DJSI_DIR=$THIRD_PARTY_DIR/rn/ReactCommon/jsi \
        + -DJSI_DIR=$JSI_DIR \
        
      6. Adjust hermes/CMakeLists.txt: Comment out lines 619 and 632, compilation will also give hints.
      7. Compile: Open command line tool in scripts directory, then execute ./build-hermes.sh.
      8. Compilation complete, compiled so will overwrite original files in prebuilt directory.

Font Size Too Small When Switching from Native Page to RN Page

  • Symptom
    Using non-phone devices (foldable screen, tablet), with CAPI architecture enabled, font appears too small when switching from native page to RN page.
  • Cause
  1. Not using rnability
  2. Switching from native page to RN page doesn't trigger onWindowSizeChange, causing DisplayMetricsManager's displayMetrics default scale to be 1, inconsistent with expectation.
  • Solution
    Need to manually execute this.rnInstancesCoordinator.onWindowSizeChange(windowSize) to trigger displayMetrics update.

Page Abnormally Raised When Using KeyboardAvoidingView Component

  • Symptom

    Using KeyboardAvoidingView wrapping TextInput for a bottom popup, when keyboard pops up, popup bottom doesn't align with keyboard top, there's a gap in between.

  • Cause

    When TextInput focuses and keyboard pops up, TextInput itself will automatically avoid keyboard and raise component height. When TextInput is wrapped by KeyboardAvoidingView, not only TextInput height is raised, but also the page recalculates height to avoid keyboard, whole page is raised by keyboard height. Hence there's a gap between keyboard top and popup bottom, not aligned.

  • Solution

    In the native container where KeyboardAvoidingView page is located, set keyboard safe area property .expandSafeArea([SafeAreaType.KEYBOARD]), as shown below:

    build() {
      Stack() {
        if (this.shouldShow) {
          RNSurface({
            ctx: this.ctx,
            surfaceConfig: {
              initialProps: this.initialProps ?? {},
              appKey: this.appKey,
            } as SurfaceConfig2,
          })
        }
        if (this.rnohCoreContext!.isDebugModeEnabled) {
          RNDevLoadingView({ useSafeAreaInsets: true, ctx: this.rnohCoreContext }).position({ x: 0, y: 0 })
        }
      }
      .expandSafeArea([SafeAreaType.KEYBOARD])
      .width("100%")
      .height("100%")
    }
    
  • Reference

    OpenHarmony specification document.

Multiple Return Actions Executed After Single Gesture Swipe Back When Loading Multiple Instances

  • Symptom

    After loading multiple instances, only performing one gesture swipe back, but page executes multiple return actions.

  • Cause

    1. In native @Entry page, onBackPress method intercepts return action, defined as:
        onBackPress(): boolean | undefined {
          if (this.rnohCoreContext) {
            this.rnohCoreContext!.dispatchBackPress()
          }
          return true
        }
      
    2. When creating instance, custom return intercept handling method backPressHandler defined as:
        const rnInstance: RNInstance = await this.rnohCoreContext.createAndRegisterRNInstance({
          createRNPackages: createRNPackages,
          ...
          backPressHandler: () => {
            router.back()
          }
        }
      
    3. Assuming developer opens two pages sequentially from home page, each page loads through its own instance rnInstance. When swipe back from second page, should return to first page, but actually executes two return actions, directly returns to home page.
  • Solution

    There are two methods to choose:

    • In backPressHandler method, add judgment logic based on actual situation, e.g., get current page path name through routing, compare with name defined when creating current page instance, if consistent, execute page return logic, otherwise do nothing.
    • Remove backPressHandler intercept method from instance, and skip dispatchBackPress method defined in onBackPress, directly execute return logic, e.g., below method:
        onBackPress(): boolean | undefined {
          if (this.rnohCoreContext) {
            router.back()
          }
          return true
        }
      

Native Component Nesting RNSurface, Scroll Easily Triggers RN Page Click Events

  • Symptom

    When native Scroll component nests RNSurface, scrolling native component easily triggers RN click events.

  • Cause

    When touch scrolling native Scroll, RN listens to touch events and triggers click events.

  • Solution

    Call this.rnohCoreContext?.cancelTouches() in scroll event to proactively prevent RN touch events.

    Scroll() {
      RNApp({
        rnInstanceConfig: {
          createRNPackages,
          enableNDKTextMeasuring: true,
          enableBackgroundExecutor: true,
          enableCAPIArchitecture: true,
          enablePartialSyncOfDescriptorRegistryInCAPI: true,
        },
        initialProps: { "foo": "bar" } as Record<string, string>,
        appKey: "app_name",
        wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
        onSetUp: (rnInstance) => {
          rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
        },
        jsBundleProvider: new TraceJSBundleProviderDecorator(
          new AnyJSBundleProvider([
            new MetroJSBundleProvider(),
            new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
            new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
            new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
          ]),
          this.rnohCoreContext.logger),
      })
    }.height(2000).backgroundColor("red").onScroll(() => {
      this.rnohCoreContext?.cancelTouches()
    })
    

RN StatusBar Scope Issue

  • Symptom

    Setting StatusBar style after entering RN page from native page, then returning to native page, native page's StatusBar style doesn't restore, becomes the style set in RN page.

  • Cause

    ArkUI's StatusBar setting takes effect for whole window, not for page.

  • Solution

    Reset StatusBar style after returning to native page from RN page.

  • Symptom

    • Scrollbar scrolling slowly, flickering issue.
    • Lagging, delay when two scrollViews linked scrolling.
    • Animation lagging in RN.
  • Cause

    Debug package has certain performance bottleneck.

  • Solution

    Use release version RN package to compile release version package, performance will be much better.

How to Improve Compilation Efficiency

  • Symptom

    When using release package, due to no x86_64 architecture, cannot compile to Windows emulator; colleagues using Windows or Intel chip Mac need to use source code version to compile to emulator, if there are C++ changes, one compilation takes about 30 minutes.

  • Cause

    Mainly C++ compilation is slow.

  • Solution

I. Create rnoh static module

  1. Open Harmony project with DevEco, right-click -> New -> Module -> Static Library, fill in module name.
  2. Extract the react_native_openharmony-x.x.x.xxx.har provided by Huawei.
  3. Copy the extracted src/main/cpp folder, ets.ets file, ts.ts file to the new module.
  4. Replace the new module's src/main/ets folder with the extracted src/main/ets folder.
  5. Replace the new module's index.ets file with the extracted index.ets file.
  6. New module's build-profile.json5 as below:
```json5
{
    "apiType": "stageMode",
    "targets": [
        {
            "name": "default",
            "runtimeOS": "HarmonyOS",
        }
    ]
}
```
  1. New module's oh-package.json5 as below:
```json5
{
    license: 'ISC',
    types: '',
    devDependencies: {},
    name: '@rnoh/react-native-openharmony',
    description: 'React Native for OpenHarmony',
    ohos: {
        org: '',
    },
    type: 'module',
    version: '', # Check version number in extracted oh-package.json5 file
    dependencies: {},
    main: 'index.ets',
}
```
  1. New module's src/main/module.json5 content as below:
```json5
{
    "module": {
        "name": "react_native_openharmony",
        "type": "har",
        "deviceTypes": [
            "default"
        ],
        "requestPermissions": [
            {"name": "ohos.permission.INTERNET"},
            {"name": "ohos.permission.VIBRATE"}
        ]
    }
}
```
  1. Delete new module's obfuscation config files consumer-rules.txt and obfuscation-rules.txt.

II. Compile rnoh release

  1. Extract the react_native_openharmony_release-x.x.x.xxx.har provided by Huawei.
  2. Copy the extracted src/main/include folder to the new module.
  3. Modify new module's src/main/cpp/CMakeLists.txt.
  4. Modify new module's build-profile.json5.
  {
      "apiType": "stageMode",
    + "buildOption": {
      + "externalNativeOptions": {
      + "path": "./src/main/cpp/CMakeLists.txt",
      + "arguments": "",
      + "cppFlags": ""
      + }
    + },
      "targets": [
          {
              "name": "default",
              "runtimeOS": "HarmonyOS",
          }
      ]
  }
  1. Switch to release mode build. There's a button on the left side of entry product, select build Mode as release.
  2. Compile, select the new module (rnoh) -> Build -> Make Module xxx, wait for compilation to complete. Compiled file located at build/default/outputs/default, size about 35M.

III. Use release package

Using release version har package requires using release version CMakeLists.txt file, copy this file content to your Harmony project's CMakeLists.txt, and make corresponding adjustments.

Keyboard Listener Event Not Responding Issue

  • Symptom

    Keyboard listener event not responding.

  • Cause

    RNOH only listens to keyboard events of the topmost child window. If encountering above situation, possible reason is current application's RN is not displayed in the topmost child window.

  • Solution

    Based on above analysis, this problem has 2 solutions:

    1. Adjust RN display window, let it display in lastWindow.
    2. Modify RNOH source code, let RNOH listen to keyboard events on corresponding window (e.g., MainWindow).

    In RNOH, keyboard event listening code located at:
    oh_modules/@rnoh/react-native-openharmony/src/main/ets/RNOHCorePackage/turboModules/KeyboardObserverTurboModule.ts
    Specific function implementation can refer to window.

Linking.canOpenURL() Always Returns false Issue

  • Symptom

    When using Linking.canOpenURL() to launch other applications, it always returns false.

  • Cause

    The scheme of specified application needs to be configured in module.json5 file, otherwise cannot be queried.

  • Solution

    In module.json5 file's querySchemes field, configure the scheme of the application you want to launch.

    For example: If you want to launch browser to visit webpage, need to configure http or https

      "querySchemes": ["http", "https"],
    

RNApp/RNSurface as Child Component Nested in ArkTs Native Scroll Component, Scrolling Triggers Child Component Click Events

  • Symptom

    During user scrolling process, when touching React Native component, scroll event and click event trigger simultaneously, causing accidental click on child component during scrolling.

  • Cause

    In ArkTs native Scroll component (or similar ArkTs native components with scroll functionality) scroll event, no cancellation operation for React Native framework click event pass-through.

  • Solution

    When encountering similar problems, can set onScroll event on native scroll component. In this event's handling logic, call the wrapped React Native component rnInstance or rnohCoreContext's cancelTouches method, to prevent React Native internal touch triggering during scrolling.

  • Example Code

    Scroll() {
        RNApp({...})
    }
    .onScroll(() => {
        this.rnInstance!.cancelTouches();
    })  

Why Blank Area Can Be Selected After Enabling Voice Announcement

  • Symptom

    After enabling voice announcement function, blank position can also be selected.

  • Cause

    Main reason is all CustomNode (View component's corresponding ArkUI node) and StackNode (RootView component's corresponding ArkUI node) in RNOH default listen to onClick event, so system considers this node clickable, after enabling voice announcement this position naturally can respond to click.

  • Solution

    The best solution should be removing the default onClick event in RNOH. But considering third-party libraries or some partners' custom components may use this onClick event, from version 0.77.27 added a compilation option ALL_CONTAINERS_CLICKABLE, add one line set(ALL_CONTAINERS_CLICKABLE OFF) in module's CMakeLists.txt file to remove default onClick listening.

    Note: When setting ALL_CONTAINERS_CLICKABLE to OFF, RNOH framework no longer default listens to onClick event, so before setting need to check if used third-party libraries or custom components depend on onClick (corresponding CAPI attribute is NODE_ON_CLICK) event, to avoid affecting other business. If found components depend on onClick event, need to self-register event listener to handle onClick event (can refer to ArkUI document addnodeeventreceiver).

Explanation of RN StatusBar Status Not Meeting Expectations on HarmonyOS

  • Symptom

    When using React Native's StatusBar related interfaces on HarmonyOS platform, in some scenarios the status bar style may not match current page expectation, for example:

    • After page switch, status bar style doesn't change as expected
    • When returning to a page, status bar style doesn't restore to the page's expected state
    • After RN page and native page switch, status bar behavior doesn't match page's own configuration

    The above phenomenon usually manifests as: status bar doesn't strictly change with page switch.


  • Cause

    The root cause of this problem lies in the different capability models of StatusBar between HarmonyOS and React Native.

    Platform Capability Model Difference:

    • In Android / iOS platforms, status bar capability is strongly bound with page-level container (Activity / ViewController) lifecycle Page creation and destruction naturally correspond to status bar style's taking effect and rollback
    • In HarmonyOS, StatusBar belongs to system-level UI capability Status bar configuration is uniformly managed by system, not bound to single page lifecycle

    On this basis, the following two types of scenarios are more likely to expose differences:

    1. System Behavior Intervention Scenario

      System may proactively adjust status bar due to application switching to background, entering system page etc. Such adjustment may not accompany RN page re-rendering, causing page state and status bar state deviation.

    2. Page Switch Related Scenario

      When page switch or page unload, RN recalculates and synchronizes current effective StatusBar configuration. On HarmonyOS, this synchronization behavior directly acts on global system status bar.


  • Typical Scenario Example (Global Rollback Triggered by Page Unload)

    Scenario Description:

    • Page A: Business page, needs immersive effect, proactively set StatusBar
    • Page B: Normal page, no explicit StatusBar setting, expects to use system default status bar style

    Example Flow:

    1. Application enters Page A When Page A mounts, calls RN StatusBar interface, successfully modifies system status bar style.

    2. From Page A navigate to Page B If at this time Page A is unloaded, its corresponding StatusBar configuration is removed from RN internal stack.

    3. RN triggers status bar rollback logic When no other page's StatusBar configuration exists, RN merges status bar state to StatusBar._defaultProps, and synchronizes to platform side.

      Note:

      • This "default state" is not system native default state
      • But a set of default configurations defined by RN (e.g., barStyle: "default"hidden: false etc.)

    Actual Result on HarmonyOS

    • On HarmonyOS platform, StatusBar belongs to system-level UI capability, its state is uniformly managed by system, not strictly bound to single page lifecycle.
    • When RN page unloads, RN internal StatusBar destruction logic recalculates current effective state, and directly applies default configuration obtained by merging to current application window's system status bar.
    • Note: In HarmonyOS scenario, StatusBar's default configuration (obtained by RN merging default Props during page unload phase) some visual attributes won't automatically rollback to "real state before system entered page", but rollback to RN internal default configuration's mapping result on HarmonyOS status bar capability. This behavior originates from the difference between HarmonyOS status bar capability model and React Native's page-centered design philosophy.

    Finally causing:

    • Page B itself doesn't explicitly set any StatusBar related logic
    • But system status bar has been applied RN's default rollback configuration when Page A unloaded
    • Page B's actually displayed status bar style doesn't match its page design expectation

  • Explanation

    The above phenomenon is not RNOH framework or RN StatusBar interface implementation defect, but determined by HarmonyOS platform system capability boundary.

    On HarmonyOS, page lifecycle and status bar state don't have one-to-one correspondence. RN's StatusBar doesn't "stop controlling status bar" when page unloads, but explicitly restores status bar to a set of default values, and acts on global system window.


  • Usage Suggestions

    • In HarmonyOS scenario, prioritize using system default status bar strategy

    • Avoid frequent or dynamic control of StatusBar in multiple pages

    • If business has special needs (e.g., immersive page), suggest:

      • Limit StatusBar usage scope within closed page
      • Clarify expected status bar state when page enters and exits
      • Don't rely on page unload automatically restoring status bar style

  • Cross-platform Code Consistency Suggestions

    To maintain Android / iOS / HarmonyOS three-platform RN code structure consistent, suggest unified encapsulation for StatusBar usage:

    • Platform Adaptation Encapsulation (Recommended) Inside encapsulation component judge by platform:

      • Android / iOS: Normally use RN StatusBar
      • HarmonyOS: Not render or directly return empty component

    This approach can avoid global state pollution on HarmonyOS, while maintaining business code consistency.