[DoNotCommit] Helloworld example of pure swift TM

This commit is contained in:
Riccardo Cipolleschi
2025-07-20 13:00:36 +01:00
parent 09fddfb56e
commit 79c4bc1e15
11 changed files with 212 additions and 42 deletions
+57 -26
View File
@@ -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,
},
});
+1
View File
@@ -12,3 +12,4 @@ gem 'bigdecimal'
gem 'logger'
gem 'benchmark'
gem 'mutex_m'
gem 'ffi', '1.17.2'
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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
+14 -1
View File
@@ -34,5 +34,18 @@
},
"engines": {
"node": ">= 20.19.4"
}
},
"codegenConfig": {
"name": "NativeLocalStorageSpec",
"type": "modules",
"jsSrcsDir": "specs",
"android": {
"javaPackageName": "com.nativelocalstorage"
},
"ios": {
"modulesProvider": {
"NativeLocalStorage": "RCTNativeLocalStorageModuleProvider"
}
}
}
}
@@ -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',
);