You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 15:51:02