Skip to content

Commit 2ced426

Browse files
authored
feat: brownie packaging as XCFramework (#185)
* 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 * feat: docs * fix: bump down deployment targets * fix: codegen before packaging
1 parent ac4efd6 commit 2ced426

File tree

32 files changed

+1007
-168
lines changed

32 files changed

+1007
-168
lines changed

apps/AppleApp/Brownfield Apple App.xcodeproj/project.pbxproj

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
798DE8DB2F0EC98F00CFC6F3 /* hermesvm.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1414
798DE8DC2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */; };
1515
798DE8DD2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
16+
79A9BC812EF5781F009EC2E3 /* Brownie.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */; };
17+
79A9BC832EF5781F009EC2E3 /* Brownie.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
1618
/* End PBXBuildFile section */
1719

1820
/* Begin PBXCopyFilesBuildPhase section */
@@ -25,6 +27,7 @@
2527
798DE8DB2F0EC98F00CFC6F3 /* hermesvm.xcframework in Embed Frameworks */,
2628
798DE8DD2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Embed Frameworks */,
2729
798DE8D82F0EC98E00CFC6F3 /* BrownfieldLib.xcframework in Embed Frameworks */,
30+
79A9BC832EF5781F009EC2E3 /* Brownie.xcframework in Embed Frameworks */,
2831
);
2932
name = "Embed Frameworks";
3033
runOnlyForDeploymentPostprocessing = 0;
@@ -36,6 +39,7 @@
3639
79A9BC7E2EF5781F009EC2E3 /* BrownfieldLib.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = BrownfieldLib.xcframework; path = ../RNApp/ios/.brownfield/package/BrownfieldLib.xcframework; sourceTree = SOURCE_ROOT; };
3740
79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = hermesvm.xcframework; path = ../RNApp/ios/.brownfield/package/hermesvm.xcframework; sourceTree = SOURCE_ROOT; };
3841
79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ReactBrownfield.xcframework; path = ../RNApp/ios/.brownfield/package/ReactBrownfield.xcframework; sourceTree = SOURCE_ROOT; };
42+
79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Brownie.xcframework; path = ../RNApp/ios/.brownfield/package/Brownie.xcframework; sourceTree = SOURCE_ROOT; };
3943
/* End PBXFileReference section */
4044

4145
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -54,6 +58,7 @@
5458
798DE8DA2F0EC98F00CFC6F3 /* hermesvm.xcframework in Frameworks */,
5559
798DE8DC2F0EC99000CFC6F3 /* ReactBrownfield.xcframework in Frameworks */,
5660
798DE8D72F0EC98E00CFC6F3 /* BrownfieldLib.xcframework in Frameworks */,
61+
79A9BC812EF5781F009EC2E3 /* Brownie.xcframework in Frameworks */,
5762
);
5863
runOnlyForDeploymentPostprocessing = 0;
5964
};
@@ -64,6 +69,7 @@
6469
isa = PBXGroup;
6570
children = (
6671
79A9BC7E2EF5781F009EC2E3 /* BrownfieldLib.xcframework */,
72+
79A9BC822EF5781F009EC2E3 /* Brownie.xcframework */,
6773
79A9BC7F2EF5781F009EC2E3 /* hermesvm.xcframework */,
6874
79A9BC802EF5781F009EC2E3 /* ReactBrownfield.xcframework */,
6975
793C76A92EEBF938008A2A34 /* Brownfield Apple App */,
@@ -300,10 +306,10 @@
300306
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
301307
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
302308
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
303-
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
309+
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
304310
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
305311
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
306-
MACOSX_DEPLOYMENT_TARGET = 15.6;
312+
MACOSX_DEPLOYMENT_TARGET = 14.0;
307313
MARKETING_VERSION = 1.0;
308314
PRODUCT_BUNDLE_IDENTIFIER = "com.callstack.brownfield.ios.example.Brownfield-iOS-App";
309315
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -317,7 +323,7 @@
317323
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
318324
SWIFT_VERSION = 5.0;
319325
TARGETED_DEVICE_FAMILY = "1,2,7";
320-
XROS_DEPLOYMENT_TARGET = 26.1;
326+
XROS_DEPLOYMENT_TARGET = 2.0;
321327
};
322328
name = Debug;
323329
};
@@ -343,10 +349,10 @@
343349
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
344350
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
345351
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
346-
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
352+
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
347353
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
348354
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
349-
MACOSX_DEPLOYMENT_TARGET = 15.6;
355+
MACOSX_DEPLOYMENT_TARGET = 14.0;
350356
MARKETING_VERSION = 1.0;
351357
PRODUCT_BUNDLE_IDENTIFIER = "com.callstack.brownfield.ios.example.Brownfield-iOS-App";
352358
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -360,7 +366,7 @@
360366
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
361367
SWIFT_VERSION = 5.0;
362368
TARGETED_DEVICE_FAMILY = "1,2,7";
363-
XROS_DEPLOYMENT_TARGET = 26.1;
369+
XROS_DEPLOYMENT_TARGET = 2.0;
364370
};
365371
name = Release;
366372
};

apps/AppleApp/Brownfield Apple App/BrownfieldAppleApp.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import BrownfieldLib
2+
import Brownie
23
import ReactBrownfield
34
import SwiftUI
45

@@ -15,6 +16,8 @@ struct BrownfieldAppleApp: App {
1516
ReactNativeBrownfield.shared.startReactNative {
1617
print("React Native has been loaded")
1718
}
19+
20+
_ = Store(initialState, key: BrownfieldStore.storeName)
1821
}
1922

2023
var body: some Scene {

apps/AppleApp/Brownfield Apple App/ContentView.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import ReactBrownfield
2+
import Brownie
23
import SwiftUI
34

5+
let initialState = BrownfieldStore(
6+
counter: 0,
7+
user: User(name: "Username")
8+
)
9+
410
struct ContentView: View {
511
var body: some View {
612
NavigationView {
@@ -27,7 +33,7 @@ struct MainScreen: View {
2733

2834
struct GreetingCard: View {
2935
let name: String
30-
@State private var counter: Int = 0
36+
@UseStore(\BrownfieldStore.counter) var counter
3137

3238
var body: some View {
3339
VStack(spacing: 12) {
@@ -36,13 +42,13 @@ struct GreetingCard: View {
3642
.multilineTextAlignment(.center)
3743

3844
Text(
39-
"You clicked the button \(counter) time\(counter == 1 ? "" : "s")"
45+
"You clicked the button \(Int(counter)) time\(counter == 1 ? "" : "s")"
4046
)
4147
.multilineTextAlignment(.center)
4248
.font(.body)
4349

4450
Button("Increment counter") {
45-
counter += 1
51+
$counter.set { $0 + 1 }
4652
}
4753
.buttonStyle(.borderedProminent)
4854
}

apps/RNApp/App.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import React, { useEffect } from 'react';
1+
import { useEffect } from 'react';
22
import { StyleSheet, Text, View, Button } from 'react-native';
3+
import { useStore } from '@callstack/brownie';
4+
import './BrownfieldStore.brownie';
35
import {
46
createNativeStackNavigator,
57
type NativeStackScreenProps,
@@ -26,6 +28,7 @@ type Props = NativeStackScreenProps<RootStackParamList, 'Home'>;
2628

2729
function HomeScreen({ navigation, route }: Props) {
2830
const colors = route.params?.theme || getRandomTheme();
31+
const [counter, setState] = useStore('BrownfieldStore', (s) => s.counter);
2932

3033
useEffect(() => {
3134
const unsubscribe = navigation.addListener('focus', () => {
@@ -41,6 +44,16 @@ function HomeScreen({ navigation, route }: Props) {
4144
React Native Screen
4245
</Text>
4346

47+
<Text style={[styles.text, { color: colors.secondary }]}>
48+
Count: {counter}
49+
</Text>
50+
51+
<Button
52+
onPress={() => setState((prev) => ({ counter: prev.counter + 1 }))}
53+
color={colors.secondary}
54+
title="Increment"
55+
/>
56+
4457
<Button
4558
onPress={() => {
4659
navigation.push('Home', {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { BrownieStore } from '@callstack/brownie';
2+
3+
interface BrownfieldStore extends BrownieStore {
4+
counter: number;
5+
user: {
6+
name: string;
7+
};
8+
}
9+
10+
interface SettingsStore extends BrownieStore {
11+
theme: 'light' | 'dark';
12+
notificationsEnabled: boolean;
13+
privacyMode: boolean;
14+
}
15+
16+
declare module '@callstack/brownie' {
17+
interface BrownieStores {
18+
BrownfieldStore: BrownfieldStore;
19+
SettingsStore: SettingsStore;
20+
}
21+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.rnapp.brownfieldlib
2+
3+
data class BrownfieldStore (
4+
val counter: Double,
5+
val user: User
6+
) {
7+
companion object {
8+
const val STORE_NAME = "BrownfieldStore"
9+
}
10+
}
11+
12+
data class User (
13+
val name: String
14+
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.rnapp.brownfieldlib
2+
3+
data class SettingsStore (
4+
val notificationsEnabled: Boolean,
5+
val privacyMode: Boolean,
6+
val theme: Theme
7+
) {
8+
companion object {
9+
const val STORE_NAME = "SettingsStore"
10+
}
11+
}
12+
13+
enum class Theme {
14+
Dark,
15+
Light
16+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Export helpers from @callstack/react-native-brownfield library
22
@_exported import ReactBrownfield
3+
@_exported import Brownie
34
// Initializes a Bundle instance that points at the framework target.
45
public let ReactNativeBundle = Bundle(for: InternalClassForBundle.self)
56
class InternalClassForBundle {}

apps/RNApp/ios/Podfile.lock

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
PODS:
22
- boost (1.84.0)
3+
- Brownie (0.0.1):
4+
- boost
5+
- DoubleConversion
6+
- fast_float
7+
- fmt
8+
- glog
9+
- hermes-engine
10+
- RCT-Folly
11+
- RCT-Folly/Fabric
12+
- RCTRequired
13+
- RCTTypeSafety
14+
- React-Core
15+
- React-debug
16+
- React-Fabric
17+
- React-featureflags
18+
- React-graphics
19+
- React-ImageManager
20+
- React-jsi
21+
- React-NativeModulesApple
22+
- React-RCTFabric
23+
- React-renderercss
24+
- React-rendererdebug
25+
- React-utils
26+
- ReactCodegen
27+
- ReactCommon/turbomodule/bridging
28+
- ReactCommon/turbomodule/core
29+
- SocketRocket
30+
- Yoga
331
- DoubleConversion (1.1.6)
432
- fast_float (8.0.0)
533
- FBLazyVector (0.82.1)
@@ -2502,6 +2530,7 @@ PODS:
25022530

25032531
DEPENDENCIES:
25042532
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
2533+
- "Brownie (from `../node_modules/@callstack/brownie`)"
25052534
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
25062535
- fast_float (from `../node_modules/react-native/third-party-podspecs/fast_float.podspec`)
25072536
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
@@ -2587,6 +2616,8 @@ SPEC REPOS:
25872616
EXTERNAL SOURCES:
25882617
boost:
25892618
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
2619+
Brownie:
2620+
:path: "../node_modules/@callstack/brownie"
25902621
DoubleConversion:
25912622
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
25922623
fast_float:
@@ -2741,6 +2772,7 @@ EXTERNAL SOURCES:
27412772

27422773
SPEC CHECKSUMS:
27432774
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
2775+
Brownie: 6d3a2e0ddd7d92e80f53220569f42357436ef269
27442776
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
27452777
fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6
27462778
FBLazyVector: 0aa6183b9afe3c31fc65b5d1eeef1f3c19b63bfa

apps/RNApp/metro.config.js

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
const path = require('node:path');
2-
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
2+
const { getDefaultConfig } = require('@react-native/metro-config');
3+
const { withMetroConfig } = require('react-native-monorepo-config');
34

4-
const root = path.resolve(__dirname, '..', '..');
5-
6-
/**
7-
* Metro configuration
8-
* https://reactnative.dev/docs/metro
9-
*
10-
* @type {import('@react-native/metro-config').MetroConfig}
11-
*/
12-
const config = {
13-
watchFolders: [root],
14-
};
15-
16-
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
5+
module.exports = withMetroConfig(getDefaultConfig(__dirname), {
6+
root: path.resolve(__dirname, '../..'),
7+
dirname: __dirname,
8+
});

0 commit comments

Comments
 (0)