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

第三方iOS框架中从ObjC/Swift获取React Native组件层级方法问询

Great question! Since React Native has moved away from exposing direct access to JSContext, using RCTCxxBridge's enqueueJSCall is the right approach here. Here's a step-by-step solution to run custom JS code and retrieve the React Native component hierarchy from Objective-C/Swift:

Step 1: Register a Native Module to Receive Results

First, you'll need a Native Module to act as a callback channel—this lets the JS side send the component hierarchy data back to your iOS code.

Objective-C Implementation

#import <React/RCTBridgeModule.h>

@interface ComponentHierarchyReporter : NSObject <RCTBridgeModule>
@end

@implementation ComponentHierarchyReporter

// Register the module with React Native
RCT_EXPORT_MODULE();

// Define a method to receive the hierarchy JSON from JS
RCT_EXPORT_METHOD(reportHierarchy:(NSString *)hierarchyJSON) {
    // Parse the JSON and process the hierarchy data
    NSError *error;
    NSDictionary *hierarchy = [NSJSONSerialization JSONObjectWithData:[hierarchyJSON dataUsingEncoding:NSUTF8StringEncoding]
                                                              options:0
                                                                error:&error];
    
    if (!error) {
        NSLog(@"Received React Native Component Hierarchy:\n%@", hierarchy);
        // Add your custom logic here (e.g., analyze, display, or store the hierarchy)
    } else {
        NSLog(@"Failed to parse hierarchy JSON: %@", error.localizedDescription);
    }
}

@end

Swift Implementation

import React

class ComponentHierarchyReporter: NSObject, RCTBridgeModule {
    static func moduleName() -> String! {
        return "ComponentHierarchyReporter"
    }
    
    static func requiresMainQueueSetup() -> Bool {
        return true
    }
    
    @objc func reportHierarchy(_ hierarchyJSON: String) {
        guard let data = hierarchyJSON.data(using: .utf8),
              let hierarchy = try? JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] else {
            print("Failed to parse component hierarchy JSON")
            return
        }
        
        print("Received React Native Component Hierarchy:\n\(hierarchy)")
        // Add your custom logic here
    }
}

Step 2: Execute Custom JS to Fetch the Hierarchy

Use enqueueJSCall to run a JS snippet that traverses the React Native component tree, then sends the result back to your Native Module. We'll leverage React DevTools' global hook (a stable way to access root components) for this.

Objective-C Call

// Define the JS code to fetch and report the hierarchy
NSString *fetchHierarchyJS = @"(() => { "
    "// Helper function to traverse component trees"
    "function traverseComponent(component) { "
        "const componentData = { "
            "name: component.type.displayName || component.type.name || 'UnknownComponent', "
            "children: [] "
        "};"
        "if (component.props.children) { "
            "const children = Array.isArray(component.props.children) ? component.props.children : [component.props.children];"
            "children.forEach(child => { "
                "if (React.isValidElement(child)) { "
                    "componentData.children.push(traverseComponent(child));"
                "}"
            "});"
        "}"
        "return componentData;"
    "}"
    "let hierarchy = [];"
    "// Use React DevTools hook to access root components (works in debug and production if DevTools are enabled)"
    "if (global.__REACT_DEVTOOLS_GLOBAL_HOOK__) { "
        "const renderer = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(1); // RN renderer ID is typically 1"
        "if (renderer) { "
            "hierarchy = renderer.getRoots().map(root => traverseComponent(root));"
        "}"
    "}"
    "// Send the hierarchy back to Native"
    "NativeModules.ComponentHierarchyReporter.reportHierarchy(JSON.stringify(hierarchy));"
"})();";

// Execute the JS via RCTCxxBridge
[self.bridge enqueueJSCall:@"global" method:@"eval" args:@[fetchHierarchyJS] completion:nil];

Swift Call

let fetchHierarchyJS = """
(() => {
    function traverseComponent(component) {
        const componentData = {
            name: component.type.displayName || component.type.name || 'UnknownComponent',
            children: []
        };
        if (component.props.children) {
            const children = Array.isArray(component.props.children) ? component.props.children : [component.props.children];
            children.forEach(child => {
                if (React.isValidElement(child)) {
                    componentData.children.push(traverseComponent(child));
                }
            });
        }
        return componentData;
    }
    let hierarchy = [];
    if (global.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
        const renderer = global.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.get(1);
        if (renderer) {
            hierarchy = renderer.getRoots().map(root => traverseComponent(root));
        }
    }
    NativeModules.ComponentHierarchyReporter.reportHierarchy(JSON.stringify(hierarchy));
})();
"""

bridge.enqueueJSCall("global", method: "eval", args: [fetchHierarchyJS], completion: nil)

Key Notes & Caveats

  • Internal API Compatibility: The __REACT_DEVTOOLS_GLOBAL_HOOK__ is a de facto standard but isn't officially supported. For production apps without DevTools access, ask the RN team to expose a root component reference to the global scope (e.g., global.rootApp = <App /> in their entry file) and modify the JS snippet to traverse that reference instead.
  • Component Names: Ensure RN components have explicit displayName properties—without them, the hierarchy will show "UnknownComponent" for minified/production builds.
  • Async Flow: The hierarchy retrieval is asynchronous, so all processing logic must live in the reportHierarchy method of your Native Module.

内容的提问来源于stack exchange,提问作者Aaron Ash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:48:23