React Native下检测NativeModule运行状态及视图展示类型的方案问询
问题原因说明
你之前用到的两个API都不适用当前场景:
useIsFocused是React Navigation维护的路由栈状态,原生视图不在RN路由栈范围内,所以会一直认为触发跳转的RN页面处于聚焦状态AppState仅检测应用整体是否在系统前台,不会区分应用内当前展示的是原生视图还是RN视图,因此只要应用没切后台就始终返回active
可行解决方案
核心思路是自己在原生层维护视图展示状态,通过自定义NativeModule暴露状态查询和变更监听能力给JS层,实现逻辑双端统一:
1. 原生侧实现
iOS端(Swift)
首先自定义事件类型的NativeModule,对外暴露状态查询接口和状态变更事件:
import React @objc(NativeViewStatusModule) class NativeViewStatusModule: RCTEventEmitter { static var isNativeViewShown: Bool = false override static func requiresMainQueueSetup() -> Bool { return true } override func supportedEvents() -> [String]! { return ["nativeViewStatusChanged"] } @objc func getNativeViewStatus(_ resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) { resolve(Self.isNativeViewShown) } static func notifyNativeViewAppeared() { Self.isNativeViewShown = true guard let module = RCTBridge.current().module(for: Self.self) as? Self else { return } module.sendEvent(withName: "nativeViewStatusChanged", body: ["isShown": true]) } static func notifyNativeViewDisappeared() { Self.isNativeViewShown = false guard let module = RCTBridge.current().module(for: Self.self) as? Self else { return } module.sendEvent(withName: "nativeViewStatusChanged", body: ["isShown": false]) } }
之后在所有接管页面的原生ViewController生命周期方法里触发状态通知:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NativeViewStatusModule.notifyNativeViewAppeared() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NativeViewStatusModule.notifyNativeViewDisappeared() }
Android端(Kotlin)
和iOS逻辑一致,先实现自定义NativeModule:
import com.facebook.react.bridge.* import com.facebook.react.modules.core.DeviceEventManagerModule class NativeViewStatusModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { private var isNativeViewShown = false override fun getName(): String = "NativeViewStatusModule" @ReactMethod fun getNativeViewStatus(promise: Promise) { promise.resolve(isNativeViewShown) } fun notifyNativeViewAppeared() { isNativeViewShown = true reactApplicationContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) .emit("nativeViewStatusChanged", Arguments.createMap().apply { putBoolean("isShown", true) }) } fun notifyNativeViewDisappeared() { isNativeViewShown = false reactApplicationContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) .emit("nativeViewStatusChanged", Arguments.createMap().apply { putBoolean("isShown", false) }) } }
之后在所有接管页面的原生Activity生命周期方法里触发通知:
override fun onResume() { super.onResume() // 按你项目实际的ReactInstanceManager获取方式调整 val module = reactInstanceManager.currentReactContext?.getNativeModule(NativeViewStatusModule::class.java) module?.notifyNativeViewAppeared() } override fun onPause() { super.onPause() val module = reactInstanceManager.currentReactContext?.getNativeModule(NativeViewStatusModule::class.java) module?.notifyNativeViewDisappeared() }
2. JS侧封装使用
可以直接封装成自定义Hook,业务侧调用非常方便:
import { useEffect, useState } from 'react'; import { NativeModules, NativeEventEmitter } from 'react-native'; const { NativeViewStatusModule } = NativeModules; const statusEmitter = new NativeEventEmitter(NativeViewStatusModule); export const useIsNativeViewPresented = () => { const [isPresented, setIsPresented] = useState(false); useEffect(() => { // 初始化时主动拉取当前状态 NativeViewStatusModule.getNativeViewStatus().then(status => { setIsPresented(status); }); // 监听状态变更事件 const listener = statusEmitter.addListener( 'nativeViewStatusChanged', event => setIsPresented(event.isShown) ); return () => listener.remove(); }, []); return isPresented; };
3. 扩展适配
如果存在多个不同类型的原生视图需要区分,可以在事件参数里加viewType字段标识不同页面,无需额外新增模块。
内容的提问来源于stack exchange,提问作者UnknownFrequency
相关产品推荐
相关产品推荐

