React Native iOS动作扩展:如何从Objective-C传递输入Props?
Got it, let's fix this issue of passing the Safari URL from your Objective-C action extension to your React Native view. I've dealt with this exact scenario before, so here's a step-by-step solution that should work for you:
Step 1: Correctly Retrieve the Safari URL in Your Extension ViewController
The common mistake here is trying to use inputItems directly without handling the attachments where the actual URL is stored. Safari passes the URL as an NSItemProvider with the type identifier public.url. Here's how to fetch it properly:
- (void)viewDidLoad { [super viewDidLoad]; __weak typeof(self) weakSelf = self; for (NSExtensionItem *item in self.extensionContext.inputItems) { for (NSItemProvider *provider in item.attachments) { if ([provider hasItemConformingToTypeIdentifier:@"public.url"]) { [provider loadItemForTypeIdentifier:@"public.url" options:nil completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Nullable error) { if (!error && [item isKindOfClass:[NSURL class]]) { NSString *urlString = [(NSURL *)item absoluteString]; // Always update UI on the main thread dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf setupReactNativeViewWithURL:urlString]; }); } }]; break; } } if (weakSelf.view.subviews.count > 0) break; // Exit once we've loaded the RN view } }
Step 2: Pass the URL as Initial Props to React Native
Once you have the URL string, initialize your RCTRootView with the initialProperties parameter—this is the standard way to pass data from Objective-C to React Native on launch:
- (void)setupReactNativeViewWithURL:(NSString *)url { // Adjust the bundle URL based on your environment: // For debug mode, use the RCTBundleURLProvider NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; // For release mode, use the local bundled file (uncomment below) // NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"YourExtensionModuleName" // Match this to your RN AppRegistry name initialProperties:@{@"inputURL": url} // This is your passed prop launchOptions:nil]; self.view = rootView; }
Step 3: Receive the Prop in Your React Native Component
In your React Native extension component, access the inputURL prop like any standard React prop:
import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { AppRegistry } from 'react-native'; const ExtensionScreen = ({ inputURL }) => { return ( <View style={styles.container}> <Text style={styles.text}>Received URL:</Text> <Text style={styles.urlText}>{inputURL}</Text> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, text: { fontSize: 18, marginBottom: 10, }, urlText: { fontSize: 16, color: '#0066cc', textAlign: 'center', }, }); // Ensure this matches the moduleName in your Objective-C code AppRegistry.registerComponent('YourExtensionModuleName', () => ExtensionScreen);
Critical Checks to Avoid Common Issues
- Main Thread Requirement: The
loadItemForTypeIdentifiercallback runs on a background thread—always dispatch to the main thread when initializing the React Native view, otherwise you'll get crashes or rendering glitches. - Module Name Match: Double-check that the
moduleNameinRCTRootViewexactly matches the name you use inAppRegistry.registerComponentin React Native. - Extension Activation Rule: Verify your extension's
Info.plisthas the correct rule to accept URLs from Safari:<key>NSExtension</key> <dict> <key>NSExtensionAttributes</key> <dict> <key>NSExtensionActivationRule</key> <dict> <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> <integer>1</integer> </dict> </dict> <!-- Other extension configuration --> </dict>
This should resolve your issue—you'll now see the Safari URL displayed in your React Native action extension view.
内容的提问来源于stack exchange,提问作者Alex Gurr

