mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Generate code to allow for linking custom Module that conforms to some protocols (#42923)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/42923 This Diff implement the logic to: - Read some lists of class names provided by libraries that conforms to some protocols we defined as extension points. - Generate a provider in the React-Codegen podspec, whose code lives alongside the app code. - Glue the app and the generated code together, allowing to link custom protocols ## Changelog [iOS][Added] - Allow libraries to provide module which conforms to protocols meant to be extension points. Reviewed By: RSNara Differential Revision: D53441411 fbshipit-source-id: f53bc6ea0417e6122d8918df2614bcb9937a515a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f9a5b30e5a
commit
46d7f8a669
@@ -24,6 +24,20 @@
|
||||
#import <React/RCTFabricSurface.h>
|
||||
#import <React/RCTSurfaceHostingProxyRootView.h>
|
||||
|
||||
// jsinspector-modern
|
||||
#import <jsinspector-modern/InspectorFlags.h>
|
||||
|
||||
#if __has_include(<React-Codegen/RCTModulesConformingToProtocolsProvider.h>)
|
||||
#define USE_OSS_CODEGEN 1
|
||||
#import <React-Codegen/RCTModulesConformingToProtocolsProvider.h>
|
||||
#elif __has_include(<React_Codegen/RCTModulesConformingToProtocolsProvider.h>)
|
||||
#define USE_OSS_CODEGEN 1
|
||||
#import <React_Codegen/RCTModulesConformingToProtocolsProvider.h>
|
||||
#else
|
||||
// Meta internal system do not generate the RCTModulesConformingToProtocolsProvider.h file
|
||||
#define USE_OSS_CODEGEN 0
|
||||
#endif
|
||||
|
||||
void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled)
|
||||
{
|
||||
RCTEnableTurboModule(turboModuleEnabled);
|
||||
@@ -49,23 +63,59 @@ RCTAppSetupDefaultRootView(RCTBridge *bridge, NSString *moduleName, NSDictionary
|
||||
|
||||
id<RCTTurboModule> RCTAppSetupDefaultModuleFromClass(Class moduleClass)
|
||||
{
|
||||
// private block used to filter out modules depending on protocol conformance
|
||||
NSArray * (^extractModuleConformingToProtocol)(RCTModuleRegistry *, Protocol *) =
|
||||
^NSArray *(RCTModuleRegistry *moduleRegistry, Protocol *protocol)
|
||||
{
|
||||
NSArray<NSString *> *classNames = @[];
|
||||
|
||||
#if USE_OSS_CODEGEN
|
||||
if (protocol == @protocol(RCTImageURLLoader)) {
|
||||
classNames = [RCTModulesConformingToProtocolsProvider imageURLLoaderClassNames];
|
||||
} else if (protocol == @protocol(RCTImageDataDecoder)) {
|
||||
classNames = [RCTModulesConformingToProtocolsProvider imageDataDecoderClassNames];
|
||||
} else if (protocol == @protocol(RCTURLRequestHandler)) {
|
||||
classNames = [RCTModulesConformingToProtocolsProvider URLRequestHandlerClassNames];
|
||||
}
|
||||
#endif
|
||||
|
||||
NSMutableArray *modules = [NSMutableArray new];
|
||||
|
||||
for (NSString *className in classNames) {
|
||||
const char *cModuleName = [className cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
id moduleFromLibrary = [moduleRegistry moduleForName:cModuleName];
|
||||
if (![moduleFromLibrary conformsToProtocol:protocol]) {
|
||||
continue;
|
||||
}
|
||||
[modules addObject:moduleFromLibrary];
|
||||
}
|
||||
return modules;
|
||||
};
|
||||
|
||||
// Set up the default RCTImageLoader and RCTNetworking modules.
|
||||
if (moduleClass == RCTImageLoader.class) {
|
||||
return [[moduleClass alloc] initWithRedirectDelegate:nil
|
||||
loadersProvider:^NSArray<id<RCTImageURLLoader>> *(RCTModuleRegistry *moduleRegistry) {
|
||||
return @[ [RCTBundleAssetImageLoader new] ];
|
||||
NSArray *imageURLLoaderModules =
|
||||
extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTImageURLLoader));
|
||||
|
||||
return [@[ [RCTBundleAssetImageLoader new] ] arrayByAddingObjectsFromArray:imageURLLoaderModules];
|
||||
}
|
||||
decodersProvider:^NSArray<id<RCTImageDataDecoder>> *(RCTModuleRegistry *moduleRegistry) {
|
||||
return @[ [RCTGIFImageDecoder new] ];
|
||||
NSArray *imageDataDecoder = extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTImageDataDecoder));
|
||||
return [@[ [RCTGIFImageDecoder new] ] arrayByAddingObjectsFromArray:imageDataDecoder];
|
||||
}];
|
||||
} else if (moduleClass == RCTNetworking.class) {
|
||||
return [[moduleClass alloc]
|
||||
initWithHandlersProvider:^NSArray<id<RCTURLRequestHandler>> *(RCTModuleRegistry *moduleRegistry) {
|
||||
return [NSArray arrayWithObjects:[RCTHTTPRequestHandler new],
|
||||
[RCTDataRequestHandler new],
|
||||
[RCTFileRequestHandler new],
|
||||
[moduleRegistry moduleForName:"BlobModule"],
|
||||
nil];
|
||||
NSArray *URLRequestHandlerModules =
|
||||
extractModuleConformingToProtocol(moduleRegistry, @protocol(RCTURLRequestHandler));
|
||||
return [@[
|
||||
[RCTHTTPRequestHandler new],
|
||||
[RCTDataRequestHandler new],
|
||||
[RCTFileRequestHandler new],
|
||||
[moduleRegistry moduleForName:"BlobModule"],
|
||||
] arrayByAddingObjectsFromArray:URLRequestHandlerModules];
|
||||
}];
|
||||
}
|
||||
// No custom initializer here.
|
||||
|
||||
@@ -76,6 +76,7 @@ Pod::Spec.new do |s|
|
||||
s.dependency "React-RCTImage"
|
||||
s.dependency "React-CoreModules"
|
||||
s.dependency "React-nativeconfig"
|
||||
s.dependency "React-Codegen"
|
||||
|
||||
add_dependency(s, "ReactCommon", :subspec => "turbomodule/core", :additional_framework_paths => ["react/nativemodule/core"])
|
||||
add_dependency(s, "React-NativeModulesApple")
|
||||
|
||||
@@ -60,6 +60,22 @@ const CORE_LIBRARIES_WITH_OUTPUT_FOLDER = {
|
||||
};
|
||||
const REACT_NATIVE = 'react-native';
|
||||
|
||||
const MODULES_PROTOCOLS_H_TEMPLATE_PATH = path.join(
|
||||
REACT_NATIVE_PACKAGE_ROOT_FOLDER,
|
||||
'scripts',
|
||||
'codegen',
|
||||
'templates',
|
||||
'RCTModulesConformingToProtocolsProviderH.template',
|
||||
);
|
||||
|
||||
const MODULES_PROTOCOLS_MM_TEMPLATE_PATH = path.join(
|
||||
REACT_NATIVE_PACKAGE_ROOT_FOLDER,
|
||||
'scripts',
|
||||
'codegen',
|
||||
'templates',
|
||||
'RCTModulesConformingToProtocolsProviderMM.template',
|
||||
);
|
||||
|
||||
// HELPERS
|
||||
|
||||
function pkgJsonIncludesGeneratedCode(pkgJson) {
|
||||
@@ -503,6 +519,52 @@ function findCodegenEnabledLibraries(pkgJson, projectRoot) {
|
||||
}
|
||||
}
|
||||
|
||||
function generateCustomURLHandlers(libraries, outputDir) {
|
||||
const customImageURLLoaderClasses = libraries
|
||||
.flatMap(
|
||||
library =>
|
||||
library?.config?.ios?.modulesConformingToProtocol?.RCTImageURLLoader,
|
||||
)
|
||||
.filter(Boolean)
|
||||
.map(className => `@"${className}"`)
|
||||
.join(',\n\t\t');
|
||||
|
||||
const customImageDataDecoderClasses = libraries
|
||||
.flatMap(
|
||||
library =>
|
||||
library?.config?.ios?.modulesConformingToProtocol?.RCTImageDataDecoder,
|
||||
)
|
||||
.filter(Boolean)
|
||||
.map(className => `@"${className}"`)
|
||||
.join(',\n\t\t');
|
||||
|
||||
const customURLHandlerClasses = libraries
|
||||
.flatMap(
|
||||
library =>
|
||||
library?.config?.ios?.modulesConformingToProtocol?.RCTURLRequestHandler,
|
||||
)
|
||||
.filter(Boolean)
|
||||
.map(className => `@"${className}"`)
|
||||
.join(',\n\t\t');
|
||||
|
||||
const template = fs.readFileSync(MODULES_PROTOCOLS_MM_TEMPLATE_PATH, 'utf8');
|
||||
const finalMMFile = template
|
||||
.replace(/{imageURLLoaderClassNames}/, customImageURLLoaderClasses)
|
||||
.replace(/{imageDataDecoderClassNames}/, customImageDataDecoderClasses)
|
||||
.replace(/{requestHandlersClassNames}/, customURLHandlerClasses);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(outputDir, 'RCTModulesConformingToProtocolsProvider.mm'),
|
||||
finalMMFile,
|
||||
);
|
||||
|
||||
const templateH = fs.readFileSync(MODULES_PROTOCOLS_H_TEMPLATE_PATH, 'utf8');
|
||||
fs.writeFileSync(
|
||||
path.join(outputDir, 'RCTModulesConformingToProtocolsProvider.h'),
|
||||
templateH,
|
||||
);
|
||||
}
|
||||
|
||||
// It removes all the empty files and empty folders
|
||||
// it finds, starting from `filepath`, recursively.
|
||||
//
|
||||
@@ -615,6 +677,8 @@ function execute(projectRoot, targetPlatform, baseOutputPath) {
|
||||
|
||||
createComponentProvider(schemas, supportedApplePlatforms);
|
||||
}
|
||||
|
||||
generateCustomURLHandlers(libraries, outputPath);
|
||||
cleanupEmptyFilesAndFolders(outputPath);
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface RCTModulesConformingToProtocolsProvider: NSObject
|
||||
|
||||
+(NSArray<NSString *> *)imageURLLoaderClassNames;
|
||||
|
||||
+(NSArray<NSString *> *)imageDataDecoderClassNames;
|
||||
|
||||
+(NSArray<NSString *> *)URLRequestHandlerClassNames;
|
||||
|
||||
@end
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTModulesConformingToProtocolsProvider.h"
|
||||
|
||||
@implementation RCTModulesConformingToProtocolsProvider
|
||||
|
||||
+(NSArray<NSString *> *)imageURLLoaderClassNames
|
||||
{
|
||||
return @[
|
||||
{imageURLLoaderClassNames}
|
||||
];
|
||||
}
|
||||
|
||||
+(NSArray<NSString *> *)imageDataDecoderClassNames
|
||||
{
|
||||
return @[
|
||||
{imageDataDecoderClassNames}
|
||||
];
|
||||
}
|
||||
|
||||
+(NSArray<NSString *> *)URLRequestHandlerClassNames
|
||||
{
|
||||
return @[
|
||||
{requestHandlersClassNames}
|
||||
];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user