今天发现,XCode12.5上,打开RN某工程,环境报错,有两个方法,第一个方法在podfile文件里替换:
post_install do |installer|
## Fix for XCode 12.5
find_and_replace(
"../node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm",
"_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules",
"_initializeModules:(NSArray<Class> *)modules")
find_and_replace(
"../node_modules/react-native/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm",
"RCTBridgeModuleNameForClass(module))",
"RCTBridgeModuleNameForClass(Class(module)))"
)
end
def find_and_replace(dir, findstr, replacestr)
Dir[dir].each do |name|
text = File.read(name)
replace = text.gsub(findstr,replacestr)
if text != replace
puts "Fix: " + name
File.open(name, "w") { |file| file.puts replace }
STDOUT.flush
end
end
Dir[dir + '*/'].each(&method(:find_and_replace))
end
然后pod install即可。
第二个方法:如果没有podfile文件,可以直接替换RCTCxxBridge.mm里的- (void)registerAdditionalModuleClasses方法替换成:
RCTCxxBridge替换.png
RCTTurboModuleManager.mm文件里- (id<RCTTurboModule>)provideRCTTurboModule里出错的地方替换成:
image.png
保存,重新编译即可。
2021.9.29 贴出源码:
1.修改registerAdditionalModuleClasses的传入参数:
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
{
std::lock_guard<std::mutex> guard(_moduleRegistryLock);
if (_moduleRegistryCreated) {
NSArray<RCTModuleData *> *newModules = [self _initializeModules:modules withDispatchGroup:NULL lazilyDiscovered:YES];
assert(_reactInstance); // at this point you must have reactInstance as you already called reactInstance->initialzeBridge
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
} else {
[self registerModulesForClasses:modules];
}
}
- RCTTurboModuleManager.mm文件文件里provideRCTTurboModule函数:
- (id<RCTTurboModule>)provideRCTTurboModule:(const char *)moduleName
{
Class moduleClass;
id<RCTTurboModule> module = nil;
{
std::unique_lock<std::mutex> lock(_rctTurboModuleCacheLock);
auto rctTurboModuleCacheLookup = _rctTurboModuleCache.find(moduleName);
if (rctTurboModuleCacheLookup != _rctTurboModuleCache.end()) {
return rctTurboModuleCacheLookup->second;
}
if (_invalidating) {
// Don't allow creating new instances while invalidating.
return nil;
}
/**
* Step 2a: Resolve platform-specific class.
*/
if ([_delegate respondsToSelector:@selector(getModuleClassFromName:)]) {
moduleClass = [_delegate getModuleClassFromName:moduleName];
}
if (!moduleClass) {
moduleClass = getFallbackClassFromName(moduleName);
}
if (![moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
return nil;
}
/**
* Step 2b: Ask hosting application/delegate to instantiate this class
*/
if ([_delegate respondsToSelector:@selector(getModuleInstanceFromClass:)]) {
module = [_delegate getModuleInstanceFromClass:moduleClass];
} else {
module = [moduleClass new];
}
if ([module respondsToSelector:@selector(setTurboModuleLookupDelegate:)]) {
[module setTurboModuleLookupDelegate:self];
}
_rctTurboModuleCache.insert({moduleName, module});
}
/**
* It is reasonable for NativeModules to not want/need the bridge.
* In such cases, they won't have `@synthesize bridge = _bridge` in their
* implementation, and a `- (RCTBridge *) bridge { ... }` method won't be
* generated by the ObjC runtime. The property will also not be backed
* by an ivar, which makes writing to it unsafe. Therefore, we check if
* this method exists to know if we can safely set the bridge to the
* NativeModule.
*/
if ([module respondsToSelector:@selector(bridge)] && _bridge) {
/**
* Just because a NativeModule has the `bridge` method, it doesn't mean
* that it has synthesized the bridge in its implementation. Therefore,
* we need to surround the code that sets the bridge to the NativeModule
* inside a try/catch. This catches the cases where the NativeModule
* author specifies a `bridge` method manually.
*/
@try {
/**
* RCTBridgeModule declares the bridge property as readonly.
* Therefore, when authors of NativeModules synthesize the bridge
* via @synthesize bridge = bridge;, the ObjC runtime generates
* only a - (RCTBridge *) bridge: { ... } method. No setter is
* generated, so we have have to rely on the KVC API of ObjC to set
* the bridge property of these NativeModules.
*/
[(id)module setValue:_bridge forKey:@"bridge"];
} @catch (NSException *exception) {
RCTLogError(
@"%@ has no setter or ivar for its bridge, which is not "
"permitted. You must either @synthesize the bridge property, "
"or provide your own setter method.",
RCTBridgeModuleNameForClass(Class(module)));
}
}
/**
* Some modules need their own queues, but don't provide any, so we need to create it for them.
* These modules typically have the following:
* `@synthesize methodQueue = _methodQueue`
*/
if ([module respondsToSelector:@selector(methodQueue)]) {
dispatch_queue_t methodQueue = [module performSelector:@selector(methodQueue)];
if (!methodQueue) {
NSString *moduleClassName = NSStringFromClass(module.class);
NSString *queueName = [NSString stringWithFormat:@"com.facebook.react.%@Queue", moduleClassName];
methodQueue = dispatch_queue_create(queueName.UTF8String, DISPATCH_QUEUE_SERIAL);
@try {
[(id)module setValue:methodQueue forKey:@"methodQueue"];
} @catch (NSException *exception) {
RCTLogError(
@"TM: %@ is returning nil for its methodQueue, which is not "
"permitted. You must either return a pre-initialized "
"queue, or @synthesize the methodQueue to let the bridge "
"create a queue for you.",
moduleClassName);
}
}
}
/**
* Broadcast that this TurboModule was created.
*
* TODO(T41180176): Investigate whether we can get rid of this after all
* TurboModules are rolled out
*/
[[NSNotificationCenter defaultCenter]
postNotificationName:RCTDidInitializeModuleNotification
object:_bridge
userInfo:@{@"module" : module, @"bridge" : RCTNullIfNil(_bridge.parentBridge)}];
return module;
}
网友评论