From ebb5ac3714e9db2f6dfb0aaa623f2efb953663ed Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 25 Sep 2024 12:51:36 +0200 Subject: [PATCH] Setup new architecture --- .../com/newarchtricks/NewArchTricksModule.kt | 20 ++--- .../com/newarchtricks/NewArchTricksPackage.kt | 32 ++++++-- .../newarchtricks/NewArchTricksViewManager.kt | 31 ++++++++ example/android/gradle.properties | 2 +- example/ios/Podfile | 1 + example/ios/Podfile.lock | 2 +- example/src/App.tsx | 15 ++-- ios/NewArchTricks.h | 12 +-- ios/NewArchTricks.mm | 24 +++--- ios/NewArchTricksViewComponentView.h | 6 ++ ios/NewArchTricksViewComponentView.mm | 73 +++++++++++++++++++ ios/NewArchTricksViewManager.mm | 11 +++ package.json | 8 ++ react-native-new-arch-tricks.podspec | 23 +----- src/NewArchTricksModule.tsx | 5 ++ src/NewArchTricksView.tsx | 3 + src/index.tsx | 24 +----- src/specs/NativeNewArchTricksModule.ts | 8 ++ src/specs/NewArchTricksNativeComponent.ts | 8 ++ 19 files changed, 212 insertions(+), 96 deletions(-) create mode 100644 android/src/main/java/com/newarchtricks/NewArchTricksViewManager.kt create mode 100644 ios/NewArchTricksViewComponentView.h create mode 100644 ios/NewArchTricksViewComponentView.mm create mode 100644 ios/NewArchTricksViewManager.mm create mode 100644 src/NewArchTricksModule.tsx create mode 100644 src/NewArchTricksView.tsx create mode 100644 src/specs/NativeNewArchTricksModule.ts create mode 100644 src/specs/NewArchTricksNativeComponent.ts diff --git a/android/src/main/java/com/newarchtricks/NewArchTricksModule.kt b/android/src/main/java/com/newarchtricks/NewArchTricksModule.kt index 396b355..4d53b62 100644 --- a/android/src/main/java/com/newarchtricks/NewArchTricksModule.kt +++ b/android/src/main/java/com/newarchtricks/NewArchTricksModule.kt @@ -1,22 +1,14 @@ package com.newarchtricks import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.bridge.ReactMethod -import com.facebook.react.bridge.Promise +import com.facebook.react.module.annotations.ReactModule -class NewArchTricksModule(reactContext: ReactApplicationContext) : - ReactContextBaseJavaModule(reactContext) { +@ReactModule(name = NewArchTricksModule.NAME) +class NewArchTricksModule(reactContext: ReactApplicationContext) : NativeNewArchTricksModuleSpec(reactContext) { + override fun getName() = NAME - override fun getName(): String { - return NAME - } - - // Example method - // See https://reactnative.dev/docs/native-modules-android - @ReactMethod - fun multiply(a: Double, b: Double, promise: Promise) { - promise.resolve(a * b) + override fun multiply(a: Double, b: Double): Double { + return a * b } companion object { diff --git a/android/src/main/java/com/newarchtricks/NewArchTricksPackage.kt b/android/src/main/java/com/newarchtricks/NewArchTricksPackage.kt index 64e16b8..13dc3f8 100644 --- a/android/src/main/java/com/newarchtricks/NewArchTricksPackage.kt +++ b/android/src/main/java/com/newarchtricks/NewArchTricksPackage.kt @@ -1,17 +1,35 @@ package com.newarchtricks -import com.facebook.react.ReactPackage +import com.facebook.react.TurboReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider import com.facebook.react.uimanager.ViewManager -class NewArchTricksPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf(NewArchTricksModule(reactContext)) - } - +class NewArchTricksPackage : TurboReactPackage() { override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return emptyList() + return listOf(NewArchTricksViewManager()) } + + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = + if (name == NewArchTricksModule.NAME) { + NewArchTricksModule(reactContext) + } else { + null + } + + override fun getReactModuleInfoProvider() = ReactModuleInfoProvider { + mapOf( + NewArchTricksModule.NAME to ReactModuleInfo( + NewArchTricksModule.NAME, + NewArchTricksModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // isCxxModule + true // isTurboModule + ) + ) + } } diff --git a/android/src/main/java/com/newarchtricks/NewArchTricksViewManager.kt b/android/src/main/java/com/newarchtricks/NewArchTricksViewManager.kt new file mode 100644 index 0000000..eaad240 --- /dev/null +++ b/android/src/main/java/com/newarchtricks/NewArchTricksViewManager.kt @@ -0,0 +1,31 @@ +package com.newarchtricks + +import android.graphics.Color +import android.view.View +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.viewmanagers.NewArchTricksViewManagerDelegate +import com.facebook.react.viewmanagers.NewArchTricksViewManagerInterface + +@ReactModule(name = NewArchTricksViewManager.NAME) +class NewArchTricksViewManager : SimpleViewManager(), NewArchTricksViewManagerInterface { + private val delegate = NewArchTricksViewManagerDelegate(this) + + override fun getDelegate() = delegate + override fun getName() = NAME + + override fun createViewInstance(reactContext: ThemedReactContext): View { + return View(reactContext) + } + + @ReactProp(name = "color") + override fun setColor(view: View?, color: String?) { + view!!.setBackgroundColor(Color.parseColor(color)) + } + + companion object { + const val NAME = "NewArchTricksView" + } +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 9fb1566..5e24e3a 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -32,7 +32,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/example/ios/Podfile b/example/ios/Podfile index d7c6fcf..a06bc5c 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,3 +1,4 @@ +ENV['RCT_NEW_ARCH_ENABLED'] = '1' # Resolve react_native_pods.rb with node to allow for hoisting require Pod::Executable.execute_command('node', ['-p', 'require.resolve( diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a546c0a..3074d91 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1803,6 +1803,6 @@ SPEC CHECKSUMS: SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 659904f0b473181ce89df322ba464fd98aeb691c -PODFILE CHECKSUM: 6ae25aa93d9d88784af0e95de45db492e4ffbdcc +PODFILE CHECKSUM: 5a43c81d384e2cb7bb11df6f2f4dbe0be6375976 COCOAPODS: 1.15.2 diff --git a/example/src/App.tsx b/example/src/App.tsx index de8eef7..c150049 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,17 +1,12 @@ -import { useState, useEffect } from 'react'; -import { StyleSheet, View, Text } from 'react-native'; -import { multiply } from 'react-native-new-arch-tricks'; +import { StyleSheet, View, Pressable } from 'react-native'; +import { NewArchTricksView, multiply } from 'react-native-new-arch-tricks'; export default function App() { - const [result, setResult] = useState(); - - useEffect(() => { - multiply(3, 7).then(setResult); - }, []); - return ( - Result: {result} + console.log(multiply(3, 7))}> + + ); } diff --git a/ios/NewArchTricks.h b/ios/NewArchTricks.h index 7f7007a..43febc0 100644 --- a/ios/NewArchTricks.h +++ b/ios/NewArchTricks.h @@ -1,12 +1,4 @@ +#import -#ifdef RCT_NEW_ARCH_ENABLED -#import "RNNewArchTricksSpec.h" - -@interface NewArchTricks : NSObject -#else -#import - -@interface NewArchTricks : NSObject -#endif - +@interface NewArchTricks : NSObject @end diff --git a/ios/NewArchTricks.mm b/ios/NewArchTricks.mm index dbf02e9..a1857f3 100644 --- a/ios/NewArchTricks.mm +++ b/ios/NewArchTricks.mm @@ -1,19 +1,25 @@ #import "NewArchTricks.h" +#import +#import +#import +#import +#import +#import + +#import + @implementation NewArchTricks RCT_EXPORT_MODULE() -// Example method -// See // https://reactnative.dev/docs/native-modules-ios -RCT_EXPORT_METHOD(multiply:(double)a - b:(double)b - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject) +- (NSNumber *)multiply:(double)a b:(double)b { - NSNumber *result = @(a * b); - - resolve(result); + return [[NSNumber alloc] initWithDouble:a * b]; } +- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} @end diff --git a/ios/NewArchTricksViewComponentView.h b/ios/NewArchTricksViewComponentView.h new file mode 100644 index 0000000..e1f8f02 --- /dev/null +++ b/ios/NewArchTricksViewComponentView.h @@ -0,0 +1,6 @@ +#import +#import + +@interface NewArchTricksViewComponentView : RCTViewComponentView + +@end diff --git a/ios/NewArchTricksViewComponentView.mm b/ios/NewArchTricksViewComponentView.mm new file mode 100644 index 0000000..ea69a55 --- /dev/null +++ b/ios/NewArchTricksViewComponentView.mm @@ -0,0 +1,73 @@ +#import "NewArchTricksViewComponentView.h" + +// without this header the provider won't be found by RN +#import + +#import +#import +#import +#import + +using namespace facebook::react; + +@interface NewArchTricksViewComponentView () +@end + +@implementation NewArchTricksViewComponentView { + UIView *_customView; +} + +// Needed because of this: https://github.com/facebook/react-native/pull/37274 ++ (void)load +{ + [super load]; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + _customView = [[UIView alloc] initWithFrame:self.bounds]; + + self.contentView = _customView; + } + + return self; +} + +- hexStringToColor:(NSString *)stringToConvert +{ + NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""]; + NSScanner *stringScanner = [NSScanner scannerWithString:noHashString]; + + unsigned hex; + if (![stringScanner scanHexInt:&hex]) return nil; + int r = (hex >> 16) & 0xFF; + int g = (hex >> 8) & 0xFF; + int b = (hex) & 0xFF; + + return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f]; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps +{ + const auto &newProps = *std::static_pointer_cast(props); + + [_customView setBackgroundColor:[self hexStringToColor:[NSString stringWithUTF8String:newProps.color.c_str()]]]; + + [super updateProps:props oldProps:oldProps]; +} +@end + +Class NewArchTricksViewCls(void) +{ + return NewArchTricksViewComponentView.class; +} diff --git a/ios/NewArchTricksViewManager.mm b/ios/NewArchTricksViewManager.mm new file mode 100644 index 0000000..50b649f --- /dev/null +++ b/ios/NewArchTricksViewManager.mm @@ -0,0 +1,11 @@ +#import + +@interface NewArchTricksViewManager : RCTViewManager +@end + +@implementation NewArchTricksViewManager + +RCT_EXPORT_MODULE(NewArchTricksView) +RCT_EXPORT_VIEW_PROPERTY(color, NSString) + +@end diff --git a/package.json b/package.json index 3bdf678..5e32d2b 100644 --- a/package.json +++ b/package.json @@ -183,5 +183,13 @@ "type": "module-legacy", "languages": "kotlin-objc", "version": "0.41.2" + }, + "codegenConfig": { + "name": "NewArchTricksSpec", + "type": "all", + "jsSrcsDir": "./src/specs", + "android": { + "javaPackageName": "com.newarchtricks" + } } } diff --git a/react-native-new-arch-tricks.podspec b/react-native-new-arch-tricks.podspec index 3b745c8..9c228c8 100644 --- a/react-native-new-arch-tricks.podspec +++ b/react-native-new-arch-tricks.podspec @@ -16,26 +16,5 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm}" - # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. - # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79. - if respond_to?(:install_modules_dependencies, true) - install_modules_dependencies(s) - else - s.dependency "React-Core" - - # Don't install the dependencies when we run `pod install` in the old architecture. - if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then - s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" - s.pod_target_xcconfig = { - "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", - "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", - "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" - } - s.dependency "React-Codegen" - s.dependency "RCT-Folly" - s.dependency "RCTRequired" - s.dependency "RCTTypeSafety" - s.dependency "ReactCommon/turbomodule/core" - end - end + install_modules_dependencies(s) end diff --git a/src/NewArchTricksModule.tsx b/src/NewArchTricksModule.tsx new file mode 100644 index 0000000..9842254 --- /dev/null +++ b/src/NewArchTricksModule.tsx @@ -0,0 +1,5 @@ +import NativeNewArchTricksModule from './specs/NativeNewArchTricksModule'; + +export function multiply(a: number, b: number): number { + return NativeNewArchTricksModule.multiply(a, b); +} diff --git a/src/NewArchTricksView.tsx b/src/NewArchTricksView.tsx new file mode 100644 index 0000000..bb08df2 --- /dev/null +++ b/src/NewArchTricksView.tsx @@ -0,0 +1,3 @@ +import NewArchTricksNativeComponent from './specs/NewArchTricksNativeComponent'; + +export { NewArchTricksNativeComponent as NewArchTricksView }; diff --git a/src/index.tsx b/src/index.tsx index b568884..978e91f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,22 +1,2 @@ -import { NativeModules, Platform } from 'react-native'; - -const LINKING_ERROR = - `The package 'react-native-new-arch-tricks' doesn't seem to be linked. Make sure: \n\n` + - Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + - '- You rebuilt the app after installing the package\n' + - '- You are not using Expo Go\n'; - -const NewArchTricks = NativeModules.NewArchTricks - ? NativeModules.NewArchTricks - : new Proxy( - {}, - { - get() { - throw new Error(LINKING_ERROR); - }, - } - ); - -export function multiply(a: number, b: number): Promise { - return NewArchTricks.multiply(a, b); -} +export { NewArchTricksView } from './NewArchTricksView'; +export { multiply } from './NewArchTricksModule'; diff --git a/src/specs/NativeNewArchTricksModule.ts b/src/specs/NativeNewArchTricksModule.ts new file mode 100644 index 0000000..65485fb --- /dev/null +++ b/src/specs/NativeNewArchTricksModule.ts @@ -0,0 +1,8 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + multiply(a: number, b: number): number; +} + +export default TurboModuleRegistry.getEnforcing('NewArchTricks'); diff --git a/src/specs/NewArchTricksNativeComponent.ts b/src/specs/NewArchTricksNativeComponent.ts new file mode 100644 index 0000000..bfd6bd5 --- /dev/null +++ b/src/specs/NewArchTricksNativeComponent.ts @@ -0,0 +1,8 @@ +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import type { ViewProps } from 'react-native'; + +interface NativeProps extends ViewProps { + color: string; +} + +export default codegenNativeComponent('NewArchTricksView');