Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/tall-rabbits-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@callstack/react-native-brownfield': minor
'@callstack/brownfield-navigation': minor
'@callstack/brownie': minor
'@callstack/brownfield-cli': minor
---

feat: support proguard/R8 minification
7 changes: 1 addition & 6 deletions apps/ExpoApp56/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,7 @@
}
}
],
[
"@callstack/react-native-brownfield",
{
"debug": true
}
],
"@callstack/react-native-brownfield",
"expo-image",
"expo-font",
"expo-web-browser"
Expand Down
17 changes: 17 additions & 0 deletions apps/ExpoApp56/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@
"brownfield:package:ios": "brownfield package:ios --scheme BrownfieldLib --configuration Release --use-prebuilt-rn-core --use-prebuilt-expo --verbose",
"eas:stg": "EXPO_TOKEN=$EAS_TOKEN eas update --channel production --message 'testing 1st stg channel update' --platform ios --environment staging"
},
"brownfield": {
"debug": true,
"android": {
"expo": {
"minifyEnabled": false,
"extraProguardRules": [
"-keep class com.callstack.rnbrownfield.demo.expoapp56.BrownfieldStore { *; }",
"-keep class com.callstack.rnbrownfield.demo.expoapp56.BrownfieldStore$Companion { *; }",
"-keep class com.callstack.rnbrownfield.demo.expoapp56.User { *; }",
"-keep class com.callstack.rnbrownfield.demo.expoapp56.SettingsStore { *; }",
"-keep class com.callstack.rnbrownfield.demo.expoapp56.SettingsStore$Companion { *; }",
"-keep class com.callstack.rnbrownfield.demo.expoapp56.Theme { *; }",
"-keep class com.callstack.nativebrownfieldnavigation.UserType { *; }"
]
}
}
},
Comment on lines +19 to +35

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we add this to ExpoApp55 too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only required if we use minification enabled and I guess for showcase perspective, doing in one app is fine?

"dependencies": {
"@callstack/brownfield-navigation": "workspace:^",
"@callstack/brownie": "workspace:^",
Expand Down
14 changes: 13 additions & 1 deletion apps/RNApp/android/BrownfieldLib/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,16 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# Public API consumed from the Brownfield AAR.
-keep class com.rnapp.brownfieldlib.BrownfieldStore { *; }
-keep class com.rnapp.brownfieldlib.BrownfieldStore$Companion { *; }
-keep class com.rnapp.brownfieldlib.User { *; }
-keep class com.rnapp.brownfieldlib.SettingsStore { *; }
-keep class com.rnapp.brownfieldlib.SettingsStore$Companion { *; }
-keep class com.rnapp.brownfieldlib.Theme { *; }
-keep class com.rnapp.brownfieldlib.ReactNativeHostManager { *; }

# Generated API for brownfield-navigation API consumed from the Brownfield AAR
-keep class com.callstack.nativebrownfieldnavigation.UserType { *; }
6 changes: 6 additions & 0 deletions docs/docs/docs/api-reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ Example:
"expo": {
"packageName": "com.example.app",
"minSdkVersion": 24,
"extraProguardRules": [
"-keep class com.example.Foo { *; }"
],
"minifyEnabled": false,
"useLocalGradlePlugin": true
}
},
Expand Down Expand Up @@ -187,6 +191,8 @@ All file-based platform options mirror CLI flags, but they use camelCase propert
| `android.expo.artifactId` | `string` | Maven artifact ID used when publishing the AAR. |
| `android.expo.version` | `string` | Maven version used when publishing the AAR. |
| `android.expo.useLocalGradlePlugin` | `boolean` | Load the Brownfield Gradle plugin from `node_modules` via `includeBuild` instead of the Maven classpath dependency. Disabled by default. |
| `android.expo.minifyEnabled` | `boolean` | Controls `minifyEnabled` for the generated Android library build. Disabled by default. |
| `android.expo.extraProguardRules` | `string[]`| Additional Proguard rules appended to the generated `proguard-rules.pro`. |

### iOS keys

Expand Down
1 change: 1 addition & 0 deletions docs/docs/docs/guides/_meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
"guidelines",
"minification",
"troubleshooting",
{
"type": "dir",
Expand Down
84 changes: 84 additions & 0 deletions docs/docs/docs/guides/minification.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Minification

This guide shows how to enable minification for both Expo and bare React Native brownfield modules.

## Expo

Configure minification through the Brownfield config in `package.json` and let `expo prebuild` apply it to the generated module.

Steps:

1. Add a `brownfield` block to `package.json` and enable `android.expo.minifyEnabled`.
2. Add keep rules in `android.expo.extraProguardRules` for generated Brownie store types, navigation types, and host manager classes you need to keep.
3. Run `expo prebuild` to regenerate the Android module with the new settings.

Example (see [apps/ExpoApp56](https://github.com/callstack/react-native-brownfield/blob/main/apps/ExpoApp56/package.json)):

```json
{
"brownfield": {
"debug": true,
"android": {
"expo": {
"minifyEnabled": true,
"extraProguardRules": [
// If you're using Brownie, add the generated store here
"-keep class com.your.expoapp.BrownfieldStore { *; }",
"-keep class com.your.expoapp.BrownfieldStore$Companion { *; }",
"-keep class com.your.expoapp.User { *; }",
"-keep class com.your.expoapp.SettingsStore { *; }",
"-keep class com.your.expoapp.SettingsStore$Companion { *; }",
"-keep class com.your.expoapp.Theme { *; }",

// If you're using Brownfield Navigation, add the generated types here
"-keep class com.callstack.nativebrownfieldnavigation.UserType { *; }",

// Any other rule to add
//"-keep class ..."
]
}
}
}
}
```

## Bare React Native

For bare React Native, you do not need any Brownfield config. Enable minification in the module itself and add Proguard rules manually.

Steps:

1. In your `brownfieldlib/build.gradle.kts`, enable `isMinifyEnabled = true` in the `release` build type.
2. Ensure `proguard-rules.pro` keeps the generated Brownie store types, navigation types, and your host manager if you have one.

Example (see [apps/RNApp](https://github.com/callstack/react-native-brownfield/blob/main/apps/RNApp/android/app/proguard-rules.pro)):

```kts
android {
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
```

```json
// If you're using Brownie, add the generated store here
-keep class com.rnapp.brownfieldlib.BrownfieldStore { *; }
-keep class com.rnapp.brownfieldlib.BrownfieldStore$Companion { *; }
-keep class com.rnapp.brownfieldlib.User { *; }
-keep class com.rnapp.brownfieldlib.SettingsStore { *; }
-keep class com.rnapp.brownfieldlib.SettingsStore$Companion { *; }
-keep class com.rnapp.brownfieldlib.Theme { *; }

// If you're using Brownfield Navigation, add the generated types here
-keep class com.callstack.nativebrownfieldnavigation.UserType { *; }

// Any other rule to add
//"-keep class ..."
```
1 change: 1 addition & 0 deletions packages/brownfield-navigation/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ android {
defaultConfig {
minSdkVersion getExtOrDefault("minSdkVersion")
targetSdkVersion getExtOrDefault("targetSdkVersion")
consumerProguardFiles "consumer-rules.pro"
}

buildFeatures {
Expand Down
4 changes: 4 additions & 0 deletions packages/brownfield-navigation/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-keep class com.callstack.nativebrownfieldnavigation.NativeBrownfieldNavigationPackage { *; }
-keep class com.callstack.nativebrownfieldnavigation.NativeBrownfieldNavigationModule { *; }
-keep interface com.callstack.nativebrownfieldnavigation.BrownfieldNavigationDelegate { *; }
-keep class com.callstack.nativebrownfieldnavigation.BrownfieldNavigationManager { *; }
7 changes: 7 additions & 0 deletions packages/brownie/android/consumer-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@
void onStoreDidChange(java.lang.String);
native <methods>;
}

-keep class com.callstack.brownie.Store { *; }
-keep class com.callstack.brownie.StoreKt { *; }
-keep class com.callstack.brownie.StoreManager { *; }
-keep class com.callstack.brownie.StoreManager$Companion { *; }
-keep class com.callstack.brownie.StoreManagerKt { *; }
-keep class com.callstack.brownie.BrownieStoreRegistrationKt { *; }
11 changes: 11 additions & 0 deletions packages/cli/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@
"description": "Compile SDK version for the Android library.",
"type": "number"
},
"extraProguardRules": {
"description": "Extra Proguard rules appended to the default rules.",
"items": {
"type": "string"
},
"type": "array"
},
"groupId": {
"description": "Maven group ID used when publishing the AAR.",
"type": "string"
Expand All @@ -65,6 +72,10 @@
"description": "Minimum SDK version for the Android library.",
"type": "number"
},
"minifyEnabled": {
"description": "Toggle minification for the generated Android library.",
"type": "boolean"
},
"packageName": {
"description": "The package name for the Android library module.",
"type": "string"
Expand Down
52 changes: 52 additions & 0 deletions packages/cli/src/__tests__/expoPluginConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ describe('resolveBrownfieldPluginConfig', () => {
artifactId: 'brownfieldlib',
version: '0.0.1-SNAPSHOT',
useLocalGradlePlugin: false,
minifyEnabled: false,
extraProguardRules: [],
},
});
});
Expand Down Expand Up @@ -309,6 +311,8 @@ describe('resolveBrownfieldPluginConfig', () => {
moduleName: 'mylib',
minSdkVersion: 26,
version: '2.0.0',
minifyEnabled: false,
extraProguardRules: [],
});
expect(resolved.ios).toMatchObject({
frameworkName: 'MyLib',
Expand All @@ -334,6 +338,31 @@ describe('resolveBrownfieldPluginConfig', () => {
expect(resolved.android?.useLocalGradlePlugin).toBe(true);
});

it('maps android.expo.minifyEnabled and extraProguardRules from file config', () => {
const resolved = resolveBrownfieldPluginConfig(
{},
{
android: {
moduleName: 'mylib',
expo: {
minifyEnabled: true,
extraProguardRules: [
'-keep class com.example.Foo { *; }',
'-dontwarn com.example.Bar',
],
},
},
},
baseExpoConfig
);

expect(resolved.android?.minifyEnabled).toBe(true);
expect(resolved.android?.extraProguardRules).toEqual([
'-keep class com.example.Foo { *; }',
'-dontwarn com.example.Bar',
]);
});

it('maps android.useLocalGradlePlugin from legacy app.json plugin props', () => {
const resolved = resolveBrownfieldPluginConfig(
{
Expand All @@ -348,4 +377,27 @@ describe('resolveBrownfieldPluginConfig', () => {

expect(resolved.android?.useLocalGradlePlugin).toBe(true);
});

it('maps android minifyEnabled and extraProguardRules from legacy app.json plugin props', () => {
const resolved = resolveBrownfieldPluginConfig(
{
android: {
moduleName: 'mylib',
minifyEnabled: true,
extraProguardRules: [
'-keep class com.example.Legacy { *; }',
'-dontwarn com.example.Legacy',
],
},
},
null,
baseExpoConfig
);

expect(resolved.android?.minifyEnabled).toBe(true);
expect(resolved.android?.extraProguardRules).toEqual([
'-keep class com.example.Legacy { *; }',
'-dontwarn com.example.Legacy',
]);
});
});
6 changes: 6 additions & 0 deletions packages/cli/src/expoPluginConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export type BrownfieldPluginProps = {
artifactId?: string;
version?: string;
useLocalGradlePlugin?: boolean;
minifyEnabled?: boolean;
extraProguardRules?: string[];
};
};

Expand All @@ -37,6 +39,8 @@ export type ResolvedBrownfieldPluginAndroidConfig = {
artifactId: string;
version: string;
useLocalGradlePlugin: boolean;
minifyEnabled: boolean;
extraProguardRules: string[];
};

export type ResolvedBrownfieldPluginIosConfig = {
Expand Down Expand Up @@ -189,6 +193,8 @@ export function resolveBrownfieldPluginConfig(
version: effectiveProps.android?.version ?? '0.0.1-SNAPSHOT',
useLocalGradlePlugin:
effectiveProps.android?.useLocalGradlePlugin ?? false,
minifyEnabled: effectiveProps.android?.minifyEnabled ?? false,
extraProguardRules: effectiveProps.android?.extraProguardRules ?? [],
}
: null,
};
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ export type BrownfieldExpoAndroidConfig = {
*/
packageName?: string;

/**
* Toggle minification for the generated Android library.
*/
minifyEnabled?: boolean;

/**
* Extra Proguard rules appended to the default rules.
*/
extraProguardRules?: string[];

/**
* Minimum SDK version for the Android library.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-brownfield/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ android {
defaultConfig {
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
consumerProguardFiles "consumer-rules.pro"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
buildConfigField "boolean", "IS_HERMES_ENABLED", isHermesEnabled().toString()
buildConfigField "String", "RN_VERSION", "\"$reactNativeVersion\""
Expand Down
11 changes: 11 additions & 0 deletions packages/react-native-brownfield/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-keep class com.callstack.reactnativebrownfield.ReactNativeBrownfield { *; }
-keep class com.callstack.reactnativebrownfield.ReactNativeBrownfield$Companion { *; }
-keep interface com.callstack.reactnativebrownfield.OnJSBundleLoaded { *; }
-keep interface com.callstack.reactnativebrownfield.OnMessageListener { *; }
-keep class com.callstack.reactnativebrownfield.ReactNativeFragment { *; }
-keep class com.callstack.reactnativebrownfield.ReactNativeFragment$Companion { *; }
-keep class com.callstack.reactnativebrownfield.ReactDelegateWrapper { *; }
-keep class com.callstack.reactnativebrownfield.ReactNativeBrownfieldPackage { *; }
-keep class com.callstack.reactnativebrownfield.ReactNativeBrownfieldModule { *; }
-keep class com.callstack.reactnativebrownfield.constants.ReactNativeFragmentArgNames { *; }
-keep class com.callstack.reactnativebrownfield.constants.ReactNativeFragmentArgNames$Companion { *; }
Loading
Loading