From 8d570b00ae8226e1fd6eaa8d7bd29a80c4e4adb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Kwas=CC=81niewski?= Date: Wed, 14 Jan 2026 14:07:06 +0100 Subject: [PATCH 1/4] feat: package brownie as xcframework feat: native code generation feat: integrate into tester app feat: create BrownieFollyConvert.h feat: docs fix: popspec improvements fix: compile time issues --- .../project.pbxproj | 6 + .../BrownfieldAppleApp.swift | 3 + .../Brownfield Apple App/ContentView.swift | 12 +- apps/RNApp/App.tsx | 15 +- apps/RNApp/BrownfieldStore.brownie.ts | 21 + .../Generated/BrownfieldStore.kt | 14 + .../brownfieldlib/Generated/SettingsStore.kt | 16 + .../ios/BrownfieldLib/BrownfieldLib.swift | 1 + apps/RNApp/ios/Podfile.lock | 32 + apps/RNApp/metro.config.js | 20 +- apps/RNApp/package.json | 8 +- apps/RNApp/tsconfig.json | 7 + apps/TesterIntegrated/swift/Podfile.lock | 8 +- .../SwiftExample.xcodeproj/project.pbxproj | 18 +- docs/docs/brownie/codegen.mdx | 21 +- docs/docs/brownie/overview.mdx | 6 +- docs/docs/brownie/store-definition.mdx | 14 +- packages/brownie/.gitignore | 2 + packages/brownie/ArchitectureOverview.md | 29 +- packages/brownie/Brownie.podspec | 1 - packages/brownie/ios/BrownieFollyConvert.h | 17 + packages/brownie/ios/BrownieModule.mm | 1 - packages/brownie/ios/BrownieStoreBridge.mm | 2 +- .../cli/src/brownfield/commands/packageIos.ts | 44 +- .../__tests__/commands/codegen.test.ts | 40 +- .../cli/src/brownie/__tests__/config.test.ts | 64 +- packages/cli/src/brownie/commands/codegen.ts | 39 +- packages/cli/src/brownie/config.ts | 45 +- packages/cli/src/brownie/generators/swift.ts | 4 +- yarn.lock | 591 +++++++++++++++++- 30 files changed, 939 insertions(+), 162 deletions(-) create mode 100644 apps/RNApp/BrownfieldStore.brownie.ts create mode 100644 apps/RNApp/android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/BrownfieldStore.kt create mode 100644 apps/RNApp/android/BrownfieldLib/src/main/java/com/rnapp/brownfieldlib/Generated/SettingsStore.kt create mode 100644 apps/RNApp/tsconfig.json create mode 100644 packages/brownie/.gitignore create mode 100644 packages/brownie/ios/BrownieFollyConvert.h diff --git a/apps/AppleApp/Brownfield Apple App.xcodeproj/project.pbxproj b/apps/AppleApp/Brownfield Apple App.xcodeproj/project.pbxproj index a071c601..a031fcfb 100644 --- a/apps/AppleApp/Brownfield Apple App.xcodeproj/project.pbxproj +++ b/apps/AppleApp/Brownfield Apple App.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 798DE8DB2F0EC98F00CFC6F3 /* hermesvm.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 798DE8DC2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */; }; 798DE8DD2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 79A9BC812EF5781F009EC2E3 /* Brownie.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */; }; + 79A9BC832EF5781F009EC2E3 /* Brownie.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,6 +27,7 @@ 798DE8DB2F0EC98F00CFC6F3 /* hermesvm.xcframework in Embed Frameworks */, 798DE8DD2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Embed Frameworks */, 798DE8D82F0EC98E00CFC6F3 /* BrownfieldLib.xcframework in Embed Frameworks */, + 79A9BC832EF5781F009EC2E3 /* Brownie.xcframework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -36,6 +39,7 @@ 79A9BC7E2EF5781F009EC2E3 /* BrownfieldLib.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = BrownfieldLib.xcframework; path = ../RNApp/ios/.brownfield/package/BrownfieldLib.xcframework; sourceTree = SOURCE_ROOT; }; 79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = hermesvm.xcframework; path = ../RNApp/ios/.brownfield/package/hermesvm.xcframework; sourceTree = SOURCE_ROOT; }; 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ReactBrownfield.xcframework; path = ../RNApp/ios/.brownfield/package/ReactBrownfield.xcframework; sourceTree = SOURCE_ROOT; }; + 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Brownie.xcframework; path = ../RNApp/ios/.brownfield/package/Brownie.xcframework; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -54,6 +58,7 @@ 798DE8DA2F0EC98F00CFC6F3 /* hermesvm.xcframework in Frameworks */, 798DE8DC2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Frameworks */, 798DE8D72F0EC98E00CFC6F3 /* BrownfieldLib.xcframework in Frameworks */, + 79A9BC812EF5781F009EC2E3 /* Brownie.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -64,6 +69,7 @@ isa = PBXGroup; children = ( 79A9BC7E2EF5781F009EC2E3 /* BrownfieldLib.xcframework */, + 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */, 79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */, 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */, 793C76A92EEBF938008A2A34 /* Brownfield Apple App */, diff --git a/apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift b/apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift index 648ff5ba..b215ee1a 100644 --- a/apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift +++ b/apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift @@ -1,4 +1,5 @@ import BrownfieldLib +import Brownie import ReactBrownfield import SwiftUI @@ -15,6 +16,8 @@ struct BrownfieldAppleApp: App { ReactNativeBrownfield.shared.startReactNative { print("React Native has been loaded") } + + _ = Store(initialState, key: BrownfieldStore.storeName) } var body: some Scene { diff --git a/apps/AppleApp/Brownfield Apple App/ContentView.swift b/apps/AppleApp/Brownfield Apple App/ContentView.swift index ff3d1478..582a2f92 100644 --- a/apps/AppleApp/Brownfield Apple App/ContentView.swift +++ b/apps/AppleApp/Brownfield Apple App/ContentView.swift @@ -1,6 +1,12 @@ import ReactBrownfield +import Brownie import SwiftUI +let initialState = BrownfieldStore( + counter: 0, + user: User(name: "Username") +) + struct ContentView: View { var body: some View { NavigationView { @@ -27,7 +33,7 @@ struct MainScreen: View { struct GreetingCard: View { let name: String - @State private var counter: Int = 0 + @UseStore(\BrownfieldStore.counter) var counter var body: some View { VStack(spacing: 12) { @@ -36,13 +42,13 @@ struct GreetingCard: View { .multilineTextAlignment(.center) Text( - "You clicked the button \(counter) time\(counter == 1 ? "" : "s")" + "You clicked the button \(Int(counter)) time\(counter == 1 ? "" : "s")" ) .multilineTextAlignment(.center) .font(.body) Button("Increment counter") { - counter += 1 + $counter.set { $0 + 1 } } .buttonStyle(.borderedProminent) } diff --git a/apps/RNApp/App.tsx b/apps/RNApp/App.tsx index 8c52685f..7cb00ce8 100644 --- a/apps/RNApp/App.tsx +++ b/apps/RNApp/App.tsx @@ -1,5 +1,7 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; import { StyleSheet, Text, View, Button } from 'react-native'; +import { useStore } from '@callstack/brownie'; +import './BrownfieldStore.brownie'; import { createNativeStackNavigator, type NativeStackScreenProps, @@ -26,6 +28,7 @@ type Props = NativeStackScreenProps; function HomeScreen({ navigation, route }: Props) { const colors = route.params?.theme || getRandomTheme(); + const [counter, setState] = useStore('BrownfieldStore', (s) => s.counter); useEffect(() => { const unsubscribe = navigation.addListener('focus', () => { @@ -41,6 +44,16 @@ function HomeScreen({ navigation, route }: Props) { React Native Screen + + Count: {counter} + + +