mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79c4bc1e15 | ||
|
|
09fddfb56e | ||
|
|
c3c0c7cd15 |
+77
@@ -22,6 +22,20 @@ const {StructCollector} = require('./StructCollector');
|
||||
|
||||
type FilesOutput = Map<string, string>;
|
||||
|
||||
const SwiftCompatibleDeclarationTemplate = ({
|
||||
hasteModuleName,
|
||||
protocolMethods,
|
||||
}: $ReadOnly<{
|
||||
hasteModuleName: string,
|
||||
protocolMethods: string,
|
||||
}>) => `
|
||||
@protocol ${hasteModuleName}Spec <RCTBridgeModule, RCTSwiftTurboModule>
|
||||
|
||||
${protocolMethods}
|
||||
|
||||
@end
|
||||
`
|
||||
|
||||
const ModuleDeclarationTemplate = ({
|
||||
hasteModuleName,
|
||||
structDeclarations,
|
||||
@@ -58,6 +72,51 @@ namespace facebook::react {
|
||||
};
|
||||
} // namespace facebook::react`;
|
||||
|
||||
const SwiftCompatibleHeaderFileTemplate = ({
|
||||
headerFileName,
|
||||
moduleDeclarations,
|
||||
assumeNonnull,
|
||||
}: $ReadOnly<{
|
||||
headerFileName: string,
|
||||
moduleDeclarations: string,
|
||||
assumeNonnull: boolean,
|
||||
}>) => {
|
||||
const headerFileNameWithNoExt = headerFileName
|
||||
.replace(/\.h$/, '')
|
||||
.replace(/-/, '');
|
||||
|
||||
return (
|
||||
`/**
|
||||
* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
||||
*
|
||||
* Do not edit this file as changes may cause incorrect behavior and will be lost
|
||||
* once the code is regenerated.
|
||||
*
|
||||
* ${'@'}generated by codegen project: GenerateModuleObjCpp
|
||||
*
|
||||
* We create an umbrella header (and corresponding implementation) here since
|
||||
* Cxx compilation in BUCK has a limitation: source-code producing genrule()s
|
||||
* must have a single output. More files => more genrule()s => slower builds.
|
||||
*/
|
||||
|
||||
// Avoid multiple includes of ${headerFileNameWithNoExt} symbols
|
||||
#ifndef ${headerFileNameWithNoExt}_H
|
||||
#define ${headerFileNameWithNoExt}_H
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <ReactCommon/RCTSwiftTurboModule.h>
|
||||
|
||||
` +
|
||||
(assumeNonnull ? '\nNS_ASSUME_NONNULL_BEGIN\n' : '') +
|
||||
moduleDeclarations +
|
||||
'\n' +
|
||||
(assumeNonnull ? '\nNS_ASSUME_NONNULL_END\n' : '\n') +
|
||||
`#endif // ${headerFileNameWithNoExt}_H` +
|
||||
'\n'
|
||||
);
|
||||
};
|
||||
|
||||
const HeaderFileTemplate = ({
|
||||
headerFileName,
|
||||
moduleDeclarations,
|
||||
@@ -150,6 +209,7 @@ module.exports = {
|
||||
const nativeModules = getModules(schema);
|
||||
|
||||
const moduleDeclarations: Array<string> = [];
|
||||
const swiftCompatibleModulesDeclarations: Array<string> = [];
|
||||
const structInlineMethods: Array<string> = [];
|
||||
const moduleImplementations: Array<string> = [];
|
||||
|
||||
@@ -209,6 +269,15 @@ module.exports = {
|
||||
}),
|
||||
);
|
||||
|
||||
swiftCompatibleModulesDeclarations.push(
|
||||
SwiftCompatibleDeclarationTemplate({
|
||||
hasteModuleName: hasteModuleName,
|
||||
protocolMethods: methodSerializations
|
||||
.map(({protocolMethod}) => protocolMethod)
|
||||
.join('\n'),
|
||||
}),
|
||||
);
|
||||
|
||||
structInlineMethods.push(methodStrs.join('\n'));
|
||||
|
||||
moduleImplementations.push(
|
||||
@@ -232,6 +301,13 @@ module.exports = {
|
||||
assumeNonnull,
|
||||
});
|
||||
|
||||
const swiftCompatibleHeaderFileName = `${libraryName}-Swift.h`;
|
||||
const swiftHeaderFile = SwiftCompatibleHeaderFileTemplate({
|
||||
headerFileName: swiftCompatibleHeaderFileName,
|
||||
moduleDeclarations: swiftCompatibleModulesDeclarations.join('\n'),
|
||||
assumeNonnull,
|
||||
});
|
||||
|
||||
const sourceFileName = `${libraryName}-generated.mm`;
|
||||
const sourceFile = SourceFileTemplate({
|
||||
headerFileName,
|
||||
@@ -240,6 +316,7 @@ module.exports = {
|
||||
|
||||
return new Map([
|
||||
[headerFileName, headerFile],
|
||||
[swiftCompatibleHeaderFileName, swiftHeaderFile],
|
||||
[sourceFileName, sourceFile],
|
||||
]);
|
||||
},
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// RCTModule.mm
|
||||
// Pods
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 18/07/2025.
|
||||
//
|
||||
|
||||
@protocol RCTModule
|
||||
|
||||
@end
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// RCTSwiftTurboModule.h
|
||||
// Pods
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 18/07/2025.
|
||||
//
|
||||
|
||||
#import "RCTModule.h"
|
||||
|
||||
@protocol RCTSwiftTurboModule <RCTModule>
|
||||
|
||||
@end
|
||||
|
||||
+12
-2
@@ -19,8 +19,10 @@
|
||||
#import <string>
|
||||
#import <unordered_map>
|
||||
|
||||
#import "RCTModule.h"
|
||||
|
||||
#define RCT_IS_TURBO_MODULE_CLASS(klass) \
|
||||
((RCTTurboModuleEnabled() && [(klass) conformsToProtocol:@protocol(RCTTurboModule)]))
|
||||
((RCTTurboModuleEnabled() && [(klass) conformsToProtocol:@protocol(RCTModule)]))
|
||||
#define RCT_IS_TURBO_MODULE_INSTANCE(module) RCT_IS_TURBO_MODULE_CLASS([(module) class])
|
||||
|
||||
namespace facebook::react {
|
||||
@@ -186,13 +188,20 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
|
||||
*/
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
||||
(const facebook::react::ObjCTurboModule::InitParams &)params;
|
||||
|
||||
@optional
|
||||
/**
|
||||
* Return an instance of an Apple Module
|
||||
*/
|
||||
- (Class<RCTModule>)getAppleModule;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* Protocol that objects can inherit to conform to be treated as turbomodules.
|
||||
* It inherits from RCTTurboModuleProvider, meaning that a TurboModule can create itself
|
||||
*/
|
||||
@protocol RCTTurboModule <RCTModuleProvider>
|
||||
@protocol RCTTurboModule <RCTModule, RCTModuleProvider>
|
||||
|
||||
@optional
|
||||
- (void)setEventEmitterCallback:(EventEmitterCallbackWrapper *)eventEmitterCallbackWrapper;
|
||||
@@ -210,3 +219,4 @@ class JSI_EXPORT ObjCTurboModule : public TurboModule {
|
||||
- (std::shared_ptr<facebook::react::NativeMethodCallInvoker>)decorateNativeMethodCallInvoker:
|
||||
(std::shared_ptr<facebook::react::NativeMethodCallInvoker>)nativeMethodCallInvoker;
|
||||
@end
|
||||
|
||||
|
||||
+2
-1
@@ -847,7 +847,7 @@ void ObjCTurboModule::setMethodArgConversionSelector(NSString *methodName, size_
|
||||
|
||||
void ObjCTurboModule::setEventEmitterCallback(EventEmitterCallback eventEmitterCallback)
|
||||
{
|
||||
if ([instance_ conformsToProtocol:@protocol(RCTTurboModule)] &&
|
||||
if ([instance_ conformsToProtocol:@protocol(RCTModule)] &&
|
||||
[instance_ respondsToSelector:@selector(setEventEmitterCallback:)]) {
|
||||
EventEmitterCallbackWrapper *wrapper = [EventEmitterCallbackWrapper new];
|
||||
wrapper->_eventEmitterCallback = std::move(eventEmitterCallback);
|
||||
@@ -859,3 +859,4 @@ void ObjCTurboModule::setEventEmitterCallback(EventEmitterCallback eventEmitterC
|
||||
|
||||
@implementation EventEmitterCallbackWrapper
|
||||
@end
|
||||
|
||||
|
||||
+31
-19
@@ -159,7 +159,7 @@ class LegacyModuleNativeMethodCallInvoker : public ModuleNativeMethodCallInvoker
|
||||
|
||||
bool isTurboModuleClass(Class cls)
|
||||
{
|
||||
return [cls conformsToProtocol:@protocol(RCTTurboModule)];
|
||||
return [cls conformsToProtocol:@protocol(RCTModule)];
|
||||
}
|
||||
|
||||
bool isTurboModuleInstance(id module)
|
||||
@@ -339,18 +339,24 @@ typedef struct {
|
||||
/**
|
||||
* Step 2: Look for platform-specific modules.
|
||||
*/
|
||||
id<RCTModuleProvider> module = [self _moduleProviderForName:moduleName];
|
||||
id<RCTModuleProvider> moduleProvider = [self _moduleProviderForName:moduleName];
|
||||
|
||||
TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);
|
||||
|
||||
// If we request that a TurboModule be created, its respective ObjC class must exist
|
||||
// If the class doesn't exist, then _provideObjCModule returns nil
|
||||
if (!module) {
|
||||
if (!moduleProvider) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
id<RCTModuleProvider> module = nullptr;
|
||||
if ([moduleProvider respondsToSelector:@selector(getAppleModule)]) {
|
||||
module = (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:moduleProvider];
|
||||
}
|
||||
id<RCTModuleProvider> moduleOrProvider = module ? module : moduleProvider;
|
||||
|
||||
std::shared_ptr<NativeMethodCallInvoker> nativeMethodCallInvoker = nullptr;
|
||||
dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(module, &kAssociatedMethodQueueKey);
|
||||
dispatch_queue_t methodQueue = (dispatch_queue_t)objc_getAssociatedObject(moduleOrProvider, &kAssociatedMethodQueueKey);
|
||||
if (methodQueue) {
|
||||
/**
|
||||
* Step 2c: Create and native CallInvoker from the TurboModule's method queue.
|
||||
@@ -370,11 +376,11 @@ typedef struct {
|
||||
* Step 2d: If the moduleClass is a legacy CxxModule, return a TurboCxxModule instance that
|
||||
* wraps CxxModule.
|
||||
*/
|
||||
Class moduleClass = [module class];
|
||||
Class moduleClass = [moduleOrProvider class];
|
||||
if ([moduleClass isSubclassOfClass:RCTCxxModule.class]) {
|
||||
// Use TurboCxxModule compat class to wrap the CxxModule instance.
|
||||
// This is only for migration convenience, despite less performant.
|
||||
auto turboModule = std::make_shared<TurboCxxModule>([((RCTCxxModule *)module) createModule], _jsInvoker);
|
||||
auto turboModule = std::make_shared<TurboCxxModule>([((RCTCxxModule *)moduleOrProvider) createModule], _jsInvoker);
|
||||
_turboModuleCache.insert({moduleName, turboModule});
|
||||
return turboModule;
|
||||
}
|
||||
@@ -385,27 +391,27 @@ typedef struct {
|
||||
* Use respondsToSelector: below to infer conformance to @protocol(RCTTurboModule). Using conformsToProtocol: is
|
||||
* expensive.
|
||||
*/
|
||||
if ([module respondsToSelector:@selector(getTurboModule:)]) {
|
||||
if ([moduleProvider respondsToSelector:@selector(getTurboModule:)]) {
|
||||
ObjCTurboModule::InitParams params = {
|
||||
.moduleName = moduleName,
|
||||
.instance = (id<RCTBridgeModule>)module,
|
||||
.instance = (id<RCTBridgeModule>)moduleOrProvider,
|
||||
.jsInvoker = _jsInvoker,
|
||||
.nativeMethodCallInvoker = nativeMethodCallInvoker,
|
||||
.isSyncModule = methodQueue == RCTJSThread,
|
||||
.shouldVoidMethodsExecuteSync = (bool)RCTTurboModuleSyncVoidMethodsEnabled(),
|
||||
};
|
||||
|
||||
auto turboModule = [(id<RCTTurboModule>)module getTurboModule:params];
|
||||
auto turboModule = [(id<RCTTurboModule>)moduleProvider getTurboModule:params];
|
||||
if (turboModule == nullptr) {
|
||||
RCTLogError(@"TurboModule \"%@\"'s getTurboModule: method returned nil.", moduleClass);
|
||||
}
|
||||
_turboModuleCache.insert({moduleName, turboModule});
|
||||
|
||||
if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:callInvoker:)]) {
|
||||
[(id<RCTTurboModuleWithJSIBindings>)module installJSIBindingsWithRuntime:*runtime callInvoker:_jsInvoker];
|
||||
} else if ([module respondsToSelector:@selector(installJSIBindingsWithRuntime:)]) {
|
||||
if ([moduleOrProvider respondsToSelector:@selector(installJSIBindingsWithRuntime:callInvoker:)]) {
|
||||
[(id<RCTTurboModuleWithJSIBindings>)moduleOrProvider installJSIBindingsWithRuntime:*runtime callInvoker:_jsInvoker];
|
||||
} else if ([moduleOrProvider respondsToSelector:@selector(installJSIBindingsWithRuntime:)]) {
|
||||
// Old API without CallInvoker (deprecated)
|
||||
[(id<RCTTurboModuleWithJSIBindings>)module installJSIBindingsWithRuntime:*runtime];
|
||||
[(id<RCTTurboModuleWithJSIBindings>)moduleOrProvider installJSIBindingsWithRuntime:*runtime];
|
||||
}
|
||||
return turboModule;
|
||||
}
|
||||
@@ -496,16 +502,16 @@ typedef struct {
|
||||
if ([_delegate respondsToSelector:@selector(getModuleProvider:)]) {
|
||||
moduleProvider = [_delegate getModuleProvider:moduleName];
|
||||
}
|
||||
|
||||
|
||||
if (RCTTurboModuleInteropEnabled() && ![self _isTurboModule:moduleName] && !moduleProvider) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
if (moduleProvider) {
|
||||
if ([moduleProvider conformsToProtocol:@protocol(RCTTurboModule)]) {
|
||||
// moduleProvider is also a TM, we need to initialize objectiveC properties, like the dispatch queue
|
||||
if ([moduleProvider conformsToProtocol:@protocol(RCTModule)]) {
|
||||
return (id<RCTModuleProvider>)[self _provideObjCModule:moduleName moduleProvider:moduleProvider];
|
||||
}
|
||||
|
||||
// module is Cxx module
|
||||
return moduleProvider;
|
||||
}
|
||||
@@ -585,7 +591,12 @@ typedef struct {
|
||||
/**
|
||||
* Step 2a: Resolve platform-specific class.
|
||||
*/
|
||||
Class moduleClass = moduleProvider ? [moduleProvider class] : [self _getModuleClassFromName:moduleName];
|
||||
Class moduleClass = moduleProvider ?
|
||||
([moduleProvider respondsToSelector:@selector(getAppleModule)] ?
|
||||
[moduleProvider getAppleModule] :
|
||||
[moduleProvider class]) :
|
||||
[self _getModuleClassFromName:moduleName];
|
||||
|
||||
|
||||
__block id<RCTBridgeModule> module = nil;
|
||||
|
||||
@@ -640,7 +651,7 @@ typedef struct {
|
||||
return [moduleClass conformsToProtocol:@protocol(RCTBridgeModule)];
|
||||
}
|
||||
|
||||
return [moduleClass conformsToProtocol:@protocol(RCTTurboModule)];
|
||||
return [moduleClass conformsToProtocol:@protocol(RCTModule)];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1104,3 +1115,4 @@ typedef struct {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ Pod::Spec.new do |s|
|
||||
s.author = "Meta Platforms, Inc. and its affiliates"
|
||||
s.platforms = min_supported_versions
|
||||
s.source = source
|
||||
s.source_files = "**/RCTAppDependencyProvider.{h,mm}"
|
||||
s.source_files = ["**/RCTAppDependencyProvider.{h,mm}", "**/*-Swift.{h,mm}"]
|
||||
|
||||
# This guard prevent to install the dependencies when we run `pod install` in the old architecture.
|
||||
s.pod_target_xcconfig = {
|
||||
|
||||
+57
-26
@@ -1,42 +1,73 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import React from 'react';
|
||||
import {
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
useColorScheme,
|
||||
TextInput,
|
||||
Button,
|
||||
} from 'react-native';
|
||||
|
||||
function App(): React.ReactNode {
|
||||
const isDarkMode = useColorScheme() === 'dark';
|
||||
import NativeLocalStorage from './specs/NativeLocalStorage';
|
||||
|
||||
const EMPTY = '<empty>';
|
||||
|
||||
function App(): React.JSX.Element {
|
||||
const [value, setValue] = React.useState<string | null>(null);
|
||||
|
||||
const [editingValue, setEditingValue] = React.useState<
|
||||
string | null
|
||||
>(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
const storedValue = NativeLocalStorage?.getItem('myKey');
|
||||
setValue(storedValue ?? '');
|
||||
}, []);
|
||||
|
||||
function saveValue() {
|
||||
NativeLocalStorage?.setItem(editingValue ?? EMPTY, 'myKey');
|
||||
setValue(editingValue);
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
NativeLocalStorage?.clear();
|
||||
setValue('');
|
||||
}
|
||||
|
||||
function deleteValue() {
|
||||
NativeLocalStorage?.removeItem('myKey');
|
||||
setValue('');
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
|
||||
<ScrollView contentInsetAdjustmentBehavior="automatic">
|
||||
<View>
|
||||
<Text style={styles.title}>Hello, World!</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<SafeAreaView style={{flex: 1}}>
|
||||
<Text style={styles.text}>
|
||||
Current stored value is: {value ?? 'No Value'}
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder="Enter the text you want to store"
|
||||
style={styles.textInput}
|
||||
onChangeText={setEditingValue}
|
||||
/>
|
||||
<Button title="Save" onPress={saveValue} />
|
||||
<Button title="Delete" onPress={deleteValue} />
|
||||
<Button title="Clear" onPress={clearAll} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: '600',
|
||||
text: {
|
||||
margin: 10,
|
||||
fontSize: 20,
|
||||
},
|
||||
textInput: {
|
||||
margin: 10,
|
||||
height: 40,
|
||||
borderColor: 'black',
|
||||
borderWidth: 1,
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5,
|
||||
borderRadius: 5,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -12,3 +12,4 @@ gem 'bigdecimal'
|
||||
gem 'logger'
|
||||
gem 'benchmark'
|
||||
gem 'mutex_m'
|
||||
gem 'ffi', '1.17.2'
|
||||
|
||||
@@ -62,7 +62,7 @@ GEM
|
||||
escape (0.0.4)
|
||||
ethon (0.16.0)
|
||||
ffi (>= 1.15.0)
|
||||
ffi (1.17.0)
|
||||
ffi (1.17.2)
|
||||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
@@ -104,6 +104,7 @@ DEPENDENCIES
|
||||
bigdecimal
|
||||
cocoapods (~> 1.13, != 1.15.1, != 1.15.0)
|
||||
concurrent-ruby (<= 1.3.4)
|
||||
ffi (= 1.17.2)
|
||||
logger
|
||||
mutex_m
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//
|
||||
// HelloWorld-Bridging-Header.h
|
||||
// HelloWorld
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 20/07/2025.
|
||||
//
|
||||
|
||||
#import <React-RCTAppDelegate/RCTDefaultReactNativeFactoryDelegate.h>
|
||||
@@ -8,12 +8,14 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00E356F31AD99517003FC87E /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; };
|
||||
03B621F332C31CE9F6F5498B /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 87728D6F9B41932E3190949E /* libPods-HelloWorld-HelloWorldTests.a */; };
|
||||
0B80405BD1BDA4AEC91E6FD6 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 46A81F6F6DFF1CFBA9274965 /* libPods-HelloWorld.a */; };
|
||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
6EA01F72FAC10D00AECACF94 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */; };
|
||||
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
|
||||
CD087E612E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD087E602E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.mm */; };
|
||||
CD087E642E2D0E9F00049510 /* NativeLocalStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD087E632E2D0E9F00049510 /* NativeLocalStorage.swift */; };
|
||||
CDA0ED1A2D0B2D810079F561 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA0ED192D0B2D810079F561 /* AppDelegate.swift */; };
|
||||
D462E9F4436EDF91C8A1FA0A /* Pods_HelloWorld.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B3F2101C8317E5C933C1BD4C /* Pods_HelloWorld.framework */; };
|
||||
D693EA25CB545D6C1C7F8538 /* Pods_HelloWorld_HelloWorldTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A97924660E462ECF2425C3A /* Pods_HelloWorld_HelloWorldTests.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -36,12 +38,16 @@
|
||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = HelloWorld/Info.plist; sourceTree = "<group>"; };
|
||||
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = HelloWorld/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
3B4392A12AC88292D35C810B /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
46A81F6F6DFF1CFBA9274965 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5709B34CF0A7D63546082F79 /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = "<group>"; };
|
||||
5B7EB9410499542E8C5724F5 /* Pods-HelloWorld-HelloWorldTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
7A97924660E462ECF2425C3A /* Pods_HelloWorld_HelloWorldTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HelloWorld_HelloWorldTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = HelloWorld/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
87728D6F9B41932E3190949E /* libPods-HelloWorld-HelloWorldTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld-HelloWorldTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
89C6BE57DB24E9ADA2F236DE /* Pods-HelloWorld-HelloWorldTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld-HelloWorldTests.release.xcconfig"; path = "Target Support Files/Pods-HelloWorld-HelloWorldTests/Pods-HelloWorld-HelloWorldTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||
B3F2101C8317E5C933C1BD4C /* Pods_HelloWorld.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HelloWorld.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CD087E5F2E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTNativeLocalStorageModuleProvider.h; sourceTree = "<group>"; };
|
||||
CD087E602E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTNativeLocalStorageModuleProvider.mm; sourceTree = "<group>"; };
|
||||
CD087E632E2D0E9F00049510 /* NativeLocalStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeLocalStorage.swift; sourceTree = "<group>"; };
|
||||
CD087E652E2D0F9700049510 /* HelloWorld-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HelloWorld-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
CDA0ED192D0B2D810079F561 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = HelloWorld/AppDelegate.swift; sourceTree = "<group>"; };
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -51,7 +57,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D693EA25CB545D6C1C7F8538 /* Pods_HelloWorld_HelloWorldTests.framework in Frameworks */,
|
||||
03B621F332C31CE9F6F5498B /* libPods-HelloWorld-HelloWorldTests.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -59,7 +65,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D462E9F4436EDF91C8A1FA0A /* Pods_HelloWorld.framework in Frameworks */,
|
||||
0B80405BD1BDA4AEC91E6FD6 /* libPods-HelloWorld.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -92,6 +98,7 @@
|
||||
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */,
|
||||
0EC7AB76F90EED035707BA4E /* PrivacyInfo.xcprivacy */,
|
||||
CDA0ED192D0B2D810079F561 /* AppDelegate.swift */,
|
||||
CD087E652E2D0F9700049510 /* HelloWorld-Bridging-Header.h */,
|
||||
);
|
||||
name = HelloWorld;
|
||||
sourceTree = "<group>";
|
||||
@@ -100,8 +107,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
|
||||
B3F2101C8317E5C933C1BD4C /* Pods_HelloWorld.framework */,
|
||||
7A97924660E462ECF2425C3A /* Pods_HelloWorld_HelloWorldTests.framework */,
|
||||
46A81F6F6DFF1CFBA9274965 /* libPods-HelloWorld.a */,
|
||||
87728D6F9B41932E3190949E /* libPods-HelloWorld-HelloWorldTests.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -116,6 +123,7 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD087E5E2E2D0DD100049510 /* NativeLocalStorage */,
|
||||
13B07FAE1A68108700A75B9A /* HelloWorld */,
|
||||
832341AE1AAA6A7D00B99B32 /* Libraries */,
|
||||
00E356EF1AD99517003FC87E /* HelloWorldTests */,
|
||||
@@ -148,6 +156,16 @@
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD087E5E2E2D0DD100049510 /* NativeLocalStorage */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD087E5F2E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.h */,
|
||||
CD087E602E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.mm */,
|
||||
CD087E632E2D0E9F00049510 /* NativeLocalStorage.swift */,
|
||||
);
|
||||
path = NativeLocalStorage;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -206,7 +224,7 @@
|
||||
TestTargetID = 13B07F861A680F5B00A75B9A;
|
||||
};
|
||||
13B07F861A680F5B00A75B9A = {
|
||||
LastSwiftMigration = 1610;
|
||||
LastSwiftMigration = 1640;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -394,7 +412,9 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD087E642E2D0E9F00049510 /* NativeLocalStorage.swift in Sources */,
|
||||
CDA0ED1A2D0B2D810079F561 /* AppDelegate.swift in Sources */,
|
||||
CD087E612E2D0DE600049510 /* RCTNativeLocalStorageModuleProvider.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -484,6 +504,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = HelloWorld;
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../packages/react-native";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "HelloWorld-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -511,6 +532,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = HelloWorld;
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../packages/react-native";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "HelloWorld-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
@@ -596,8 +618,11 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../packages/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
USE_HERMES = true;
|
||||
@@ -676,8 +701,11 @@
|
||||
"-DFOLLY_CFG_NO_COROUTINES=1",
|
||||
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
|
||||
);
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../react-native";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../../../packages/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = true;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<!-- Do not change NSAllowsArbitraryLoads to true, or you will risk app rejection! -->
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<false/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
@@ -34,6 +33,8 @@
|
||||
</dict>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string></string>
|
||||
<key>RCTNewArchEnabled</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// NativeLocalStorage.swift
|
||||
// HelloWorld
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 20/07/2025.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ReactAppDependencyProvider
|
||||
|
||||
class NativeLocalStorage: NSObject, NativeLocalStorageSpec {
|
||||
private let storage: UserDefaults = UserDefaults(suiteName: "local-storage") ?? .standard
|
||||
func setItem(_ value: String, key: String) {
|
||||
storage.setValue(value, forKey: key)
|
||||
}
|
||||
|
||||
func getItem(_ key: String) -> String? {
|
||||
storage.string(forKey: key)
|
||||
}
|
||||
|
||||
func removeItem(_ key: String) {
|
||||
storage.removeObject(forKey: key)
|
||||
}
|
||||
|
||||
func clear() {
|
||||
storage.dictionaryRepresentation().keys.forEach { storage.removeObject(forKey: $0) }
|
||||
}
|
||||
|
||||
static func moduleName() -> String! {
|
||||
return "NativeLocalStorage"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// RCTNativeLocalStorageModuleProvider.h
|
||||
// HelloWorld
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 20/07/2025.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ReactCommon/RCTTurboModule.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface RCTNativeLocalStorageModuleProvider : NSObject <RCTModuleProvider>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// RCTNativeLocalStorageModuleProvider.m
|
||||
// HelloWorld
|
||||
//
|
||||
// Created by Riccardo Cipolleschi on 20/07/2025.
|
||||
//
|
||||
|
||||
#import "RCTNativeLocalStorageModuleProvider.h"
|
||||
#import <NativeLocalStorageSpec/NativeLocalStorageSpec.h>
|
||||
#import "HelloWorld-Swift.h"
|
||||
|
||||
@implementation RCTNativeLocalStorageModuleProvider
|
||||
|
||||
- (Class<RCTModule>)getAppleModule
|
||||
{
|
||||
return [NativeLocalStorage class];
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
|
||||
return std::make_shared<facebook::react::NativeLocalStorageSpecJSI>(params);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -34,5 +34,18 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.4"
|
||||
}
|
||||
},
|
||||
"codegenConfig": {
|
||||
"name": "NativeLocalStorageSpec",
|
||||
"type": "modules",
|
||||
"jsSrcsDir": "specs",
|
||||
"android": {
|
||||
"javaPackageName": "com.nativelocalstorage"
|
||||
},
|
||||
"ios": {
|
||||
"modulesProvider": {
|
||||
"NativeLocalStorage": "RCTNativeLocalStorageModuleProvider"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ program
|
||||
android: {},
|
||||
},
|
||||
root: path.join(__dirname, '../'),
|
||||
reactNativePath: path.join(__dirname, '../../react-native'),
|
||||
reactNativePath: path.join(__dirname, '../../../packages/react-native'),
|
||||
},
|
||||
{
|
||||
experimentalDebugger: false,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import type {TurboModule} from 'react-native';
|
||||
import {TurboModuleRegistry} from 'react-native';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
setItem(value: string, key: string): void;
|
||||
getItem(key: string): string | null;
|
||||
removeItem(key: string): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
export default TurboModuleRegistry.getEnforcing<Spec>(
|
||||
'NativeLocalStorage',
|
||||
);
|
||||
Reference in New Issue
Block a user