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 }} /> - Image 1 sandbox actual path:
-
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 asresource://RAWFILE/assets/, and the relative path of image to project packing path as suffix, forming the complete path. There is an assets directory here.
- Image 1 rawfile actual path:
Modal Dialog Still Displays at Top Layer After Route Navigation
-
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 supporttranslateXproperty in Animated, cannot set useNativeDriver totrue). This also causes other performance issues.When using
react-native-page-viewlibrary, configuring useNativeDriver method inonPageScrollalso has this issue. -
Cause
Not a bug, caused by improper usage.
-
Solution
Use
transforminstead oftop, i.e., usescaleXandscaleYoftransformto 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
UIAbilityscenario, 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.
- Symptom 1: Same bundle package, in custom
-
Cause
This version of RNOH's
RNInstancesCoordinatoraddedfontSizeScaleparameter, corresponding to nativefontSizeScale, 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
fontScalevalue through RNInstancesCoordinator'sfontSizeScale. If RNInstancesCoordinator is created too late and RN page is loaded beforehand, CPP side rendering will havefontScaleas 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
RNInstancesCoordinatorinAbility.onWindowStageCreate()lifecycle. - Symptom 2 solution: Delay the execution of pre-loading Metro bundle code.
- Symptom 1 solution: Submit initialization of
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
- Extract har package: Find an empty directory (e.g., temp), copy har package to this directory, then extract. After extraction, you'll see a
packagefolder. - Download hermes source code: Download hermes source code through hermes source code link, then replace the
package/src/main/cpp/third-party/hermesfolder. - Download compilation script: Download compilation script through above link, then copy to
package/src/main/cpp/third-party/scriptspath (create scripts directory if not exists). - Configure SDK environment variable: Configure the path of
sdk/default/openharmonyin IDE in system environment variable, environment variable name isOHOS_SDK, or write this path in compilation script. - 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 \ - Adjust
hermes/CMakeLists.txt: Comment out lines 619 and 632, compilation will also give hints. - Compile: Open command line tool in scripts directory, then execute
./build-hermes.sh. - Compilation complete, compiled so will overwrite original files in
prebuiltdirectory.
- Extract har package: Find an empty directory (e.g., temp), copy har package to this directory, then extract. After extraction, you'll see a
-
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
- Not using rnability
- 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 executethis.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
- In native @Entry page,
onBackPressmethod intercepts return action, defined as:onBackPress(): boolean | undefined { if (this.rnohCoreContext) { this.rnohCoreContext!.dispatchBackPress() } return true } - When creating instance, custom return intercept handling method
backPressHandlerdefined as:const rnInstance: RNInstance = await this.rnohCoreContext.createAndRegisterRNInstance({ createRNPackages: createRNPackages, ... backPressHandler: () => { router.back() } } - 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.
- In native @Entry page,
-
Solution
There are two methods to choose:
- In
backPressHandlermethod, 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
backPressHandlerintercept method from instance, and skipdispatchBackPressmethod defined inonBackPress, directly execute return logic, e.g., below method:onBackPress(): boolean | undefined { if (this.rnohCoreContext) { router.back() } return true }
- In
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.
Release Package Related Issues
-
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
- Open Harmony project with DevEco, right-click -> New -> Module -> Static Library, fill in module name.
- Extract the react_native_openharmony-x.x.x.xxx.har provided by Huawei.
- Copy the extracted src/main/cpp folder, ets.ets file, ts.ts file to the new module.
- Replace the new module's src/main/ets folder with the extracted src/main/ets folder.
- Replace the new module's index.ets file with the extracted index.ets file.
- New module's build-profile.json5 as below:
```json5
{
"apiType": "stageMode",
"targets": [
{
"name": "default",
"runtimeOS": "HarmonyOS",
}
]
}
```
- 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',
}
```
- 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"}
]
}
}
```
- Delete new module's obfuscation config files consumer-rules.txt and obfuscation-rules.txt.
II. Compile rnoh release
- Extract the react_native_openharmony_release-x.x.x.xxx.har provided by Huawei.
- Copy the extracted src/main/include folder to the new module.
- Modify new module's src/main/cpp/CMakeLists.txt.
- Modify new module's build-profile.json5.
{
"apiType": "stageMode",
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": ""
+ }
+ },
"targets": [
{
"name": "default",
"runtimeOS": "HarmonyOS",
}
]
}
- Switch to release mode build. There's a button on the left side of entry product, select build Mode as release.
- 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:
- Adjust RN display window, let it display in
lastWindow. - 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. - Adjust RN display window, let it display in
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.json5file'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
onScrollevent on native scroll component. In this event's handling logic, call the wrapped React Native componentrnInstanceorrnohCoreContext'scancelTouchesmethod, 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 lineset(ALL_CONTAINERS_CLICKABLE OFF)in module'sCMakeLists.txtfile to remove default onClick listening.Note: When setting
ALL_CONTAINERS_CLICKABLEtoOFF, 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
StatusBarrelated 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:
-
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.
-
Page Switch Related Scenario
When page switch or page unload, RN recalculates and synchronizes current effective
StatusBarconfiguration. 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
StatusBarsetting, expects to use system default status bar style
Example Flow:
-
Application enters Page A When Page A mounts, calls RN
StatusBarinterface, successfully modifies system status bar style. -
From Page A navigate to Page B If at this time Page A is unloaded, its corresponding
StatusBarconfiguration is removed from RN internal stack. -
RN triggers status bar rollback logic When no other page's
StatusBarconfiguration exists, RN merges status bar state toStatusBar._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: falseetc.)
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
StatusBardestruction 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
StatusBarrelated 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
- Page A: Business page, needs immersive effect, proactively set
-
Explanation
The above phenomenon is not RNOH framework or RN
StatusBarinterface 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
StatusBardoesn'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
StatusBarin multiple pages -
If business has special needs (e.g., immersive page), suggest:
- Limit
StatusBarusage 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
- Limit
-
-
Cross-platform Code Consistency Suggestions
To maintain Android / iOS / HarmonyOS three-platform RN code structure consistent, suggest unified encapsulation for
StatusBarusage:-
Platform Adaptation Encapsulation (Recommended) Inside encapsulation component judge by platform:
- Android / iOS: Normally use RN
StatusBar - HarmonyOS: Not render or directly return empty component
- Android / iOS: Normally use RN
This approach can avoid global state pollution on HarmonyOS, while maintaining business code consistency.
-