From 7177b9e927fd40c7fb671170c42ffd8779a1388a Mon Sep 17 00:00:00 2001 From: Artur Gurgul Date: Sat, 2 Aug 2025 15:19:12 +0200 Subject: [PATCH] Add emitter so I can now send events to the RN core --- App.tsx | 35 ++++++++++++------- ios/Native/Application/RootView.swift | 3 +- .../Application/Shared/Emitter/Emitter.swift | 32 +++++++++++++++++ .../Shared/Emitter/EventEmitter.swift | 28 +++++++++++++++ .../Application/Shared/ModuleProvider.swift | 0 .../{ => Shared}/SharedState.swift | 5 +++ .../Application/Views/ToolboxHeader.swift | 22 ++++++++++++ 7 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 ios/Native/Application/Shared/Emitter/Emitter.swift create mode 100644 ios/Native/Application/Shared/Emitter/EventEmitter.swift create mode 100644 ios/Native/Application/Shared/ModuleProvider.swift rename ios/Native/Application/{ => Shared}/SharedState.swift (70%) create mode 100644 ios/Native/Application/Views/ToolboxHeader.swift diff --git a/App.tsx b/App.tsx index d091223..e7f33cf 100644 --- a/App.tsx +++ b/App.tsx @@ -1,19 +1,30 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - * - * @format - */ +import { NewAppScreen } from '@react-native/new-app-screen' +import { useEffect, useState } from 'react' +import { StatusBar, Text, StyleSheet, useColorScheme, View } from 'react-native' +import { NativeEventEmitter, NativeModules } from 'react-native' +const { Emitter } = NativeModules; -import { NewAppScreen } from '@react-native/new-app-screen'; -import { StatusBar, StyleSheet, useColorScheme, View } from 'react-native'; +export default function App() { + const isDarkMode = useColorScheme() === 'dark' + const [message, setMessage] = useState(null) + + useEffect(() => { + const emitter = new NativeEventEmitter(Emitter); + const subscription = emitter.addListener('onMessage', (event) => { + if (event?.message) { + setMessage(event.message) + } + }) -function App() { - const isDarkMode = useColorScheme() === 'dark'; + return () => { + subscription.remove() + }; + }, []) return ( + {message ?? 'Waiting for message...'} ); @@ -23,6 +34,4 @@ const styles = StyleSheet.create({ container: { flex: 1, }, -}); - -export default App; +}) diff --git a/ios/Native/Application/RootView.swift b/ios/Native/Application/RootView.swift index c13bc1e..0cee3a5 100644 --- a/ios/Native/Application/RootView.swift +++ b/ios/Native/Application/RootView.swift @@ -15,10 +15,11 @@ struct RootView: View { var body: some View { VStack { - Text("Hello to SwiftUI!") + ToolboxHeader() if let reactNativeFactory = sharedState.reactNativeFactory { UIReactNativeView(reactNativeFactory) } } + .environmentObject(sharedState) } } diff --git a/ios/Native/Application/Shared/Emitter/Emitter.swift b/ios/Native/Application/Shared/Emitter/Emitter.swift new file mode 100644 index 0000000..1f66fd1 --- /dev/null +++ b/ios/Native/Application/Shared/Emitter/Emitter.swift @@ -0,0 +1,32 @@ +// +// Emitter.swift +// RNPlayground +// +// Created by Artur Gurgul on 02/08/2025. +// + +import Combine +import React +//import React_RCTAppDelegate +//import ReactAppDependencyProvider + +@objc(Emitter) +class Emitter: RCTEventEmitter { + override static func requiresMainQueueSetup() -> Bool { + return true + } + + override init() { + super.init() + EventEmitter.sharedInstance.register(eventEmitter: self) + + } + + override func supportedEvents() -> [String]! { + return ["onMessage"] + } + + @objc func send(message: String) { + sendEvent(withName: "onMessage", body: ["message": message]) + } +} diff --git a/ios/Native/Application/Shared/Emitter/EventEmitter.swift b/ios/Native/Application/Shared/Emitter/EventEmitter.swift new file mode 100644 index 0000000..f1a0e18 --- /dev/null +++ b/ios/Native/Application/Shared/Emitter/EventEmitter.swift @@ -0,0 +1,28 @@ +// +// EventEmitter.swift +// RNPlayground +// +// Created by Artur Gurgul on 02/08/2025. +// + +import Foundation + +class EventEmitter { + static let sharedInstance = EventEmitter() + + private var eventEmitter: Emitter? + + private init() {} + + func register(eventEmitter: Emitter) { + self.eventEmitter = eventEmitter + } + + func send(message: String) { + eventEmitter?.send(message: message) + } + + var isReady: Bool { + return eventEmitter != nil + } +} diff --git a/ios/Native/Application/Shared/ModuleProvider.swift b/ios/Native/Application/Shared/ModuleProvider.swift new file mode 100644 index 0000000..e69de29 diff --git a/ios/Native/Application/SharedState.swift b/ios/Native/Application/Shared/SharedState.swift similarity index 70% rename from ios/Native/Application/SharedState.swift rename to ios/Native/Application/Shared/SharedState.swift index b491d6e..cc073ba 100644 --- a/ios/Native/Application/SharedState.swift +++ b/ios/Native/Application/Shared/SharedState.swift @@ -13,4 +13,9 @@ import ReactAppDependencyProvider final class SharedState: ObservableObject { var reactNativeFactory: RCTReactNativeFactory? + private let emitter = EventEmitter.sharedInstance + + func send(message: String) { + emitter.send(message: message) + } } diff --git a/ios/Native/Application/Views/ToolboxHeader.swift b/ios/Native/Application/Views/ToolboxHeader.swift new file mode 100644 index 0000000..bee5d0c --- /dev/null +++ b/ios/Native/Application/Views/ToolboxHeader.swift @@ -0,0 +1,22 @@ +// +// ToolboxHeader.swift +// RNPlayground +// +// Created by Artur Gurgul on 02/08/2025. +// + +import SwiftUI + +struct ToolboxHeader: View { + @EnvironmentObject var sharedState: SharedState + + var body: some View { + HStack { + Text("Actions") + Button("Make it blue") { + print("Making it blue") + sharedState.send(message: "hello from Swift!") + } + } + } +}