expo-build-properties 1.0.0-canary-20241021-c4b5a93 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,12 +4,94 @@
4
4
 
5
5
  ### 🛠 Breaking changes
6
6
 
7
- - Bumped iOS deployment target to 15.1. ([#30840](https://github.com/expo/expo/pull/30840) by [@tsapeta](https://github.com/tsapeta))
7
+ ### 🎉 New features
8
+
9
+ ### 🐛 Bug fixes
10
+
11
+ ### 💡 Others
12
+
13
+ ## 1.0.1 — 2025-08-15
14
+
15
+ ### 🎉 New features
16
+
17
+ - Add `ios.reactNativeReleaseLevel` option ([#38840](https://github.com/expo/expo/pull/38840) by [@gabrieldonadel](https://github.com/gabrieldonadel))
18
+
19
+ ## 1.0.0 — 2025-08-13
20
+
21
+ ### 🎉 New features
22
+
23
+ - [ios] Added default support for prebuilt React Native Core. Can be disabled via `ios.buildReactNativeFromSource` in eas.json. (Renamed Android prop as well to align) ([#38400](https://github.com/expo/expo/pull/38400) by [@chrfalch](https://github.com/chrfalch))
24
+ - Added support for prebuilt React Native iOS dependencies via `ios.buildFromSource: false` in the iOS build properties. When `buildFromSource` is disabled, it sets `ENV['RCT_USE_RN_DEP'] = '1'` in the Podfile to use prebuilt third-party dependencies, as described in the [React Native 0.80 release blog post](https://reactnative.dev/blog/2025/06/12/react-native-0.80#experimental---react-native-ios-dependencies-are-now-prebuilt). ([#37678](https://github.com/expo/expo/pull/37678) by [@huextrat](https://github.com/huextrat))
25
+ - Add `android.buildArchs` option to override the default `reactNativeArchitectures` value in gradle.properties ([#37831](https://github.com/expo/expo/pull/37831) by [@gabrieldonadel](https://github.com/gabrieldonadel))
26
+ - Add support for setting Android's exclusiveMavenMirror gradle property ([#37864](https://github.com/expo/expo/pull/37864) by [@gabrieldonadel](https://github.com/gabrieldonadel))
27
+ - Add android.reactNativeReleaseLevel option ([#38698](https://github.com/expo/expo/pull/38698) by [@gabrieldonadel](https://github.com/gabrieldonadel))
28
+
29
+ ### 💡 Others
30
+
31
+ - [android] Deprecate `enableProguardInReleaseBuilds` in favor of `enableMinifyInReleaseBuilds` ([#38627](https://github.com/expo/expo/pull/38627) by [@nishan](https://github.com/intergalacticspacehighway))
32
+
33
+ ## 0.14.8 - 2025-07-01
34
+
35
+ ### 💡 Others
36
+
37
+ - Added `System.getenv()` syntax support to the tsdoc for `AndroidMavenRepositoryCredentials`. ([#37344](https://github.com/expo/expo/pull/37344) by [@kudo](https://github.com/kudo))
38
+
39
+ ## 0.14.7 - 2025-06-30
40
+
41
+ ### 🎉 New features
42
+
43
+ - Add `android.buildFromSource` option ([#37745](https://github.com/expo/expo/pull/37745) by [@gabrieldonadel](https://github.com/gabrieldonadel))
44
+
45
+ ## 0.14.6 — 2025-04-30
46
+
47
+ _This version does not introduce any user-facing changes._
48
+
49
+ ## 0.14.5 — 2025-04-25
50
+
51
+ _This version does not introduce any user-facing changes._
52
+
53
+ ## 0.14.4 — 2025-04-14
54
+
55
+ _This version does not introduce any user-facing changes._
56
+
57
+ ## 0.14.3 — 2025-04-11
58
+
59
+ _This version does not introduce any user-facing changes._
60
+
61
+ ## 0.14.2 — 2025-04-11
8
62
 
9
63
  ### 🎉 New features
10
64
 
65
+ - Add `android.enableBundleCompression` option ([#36071](https://github.com/expo/expo/pull/36071) by [@gabrieldonadel](https://github.com/gabrieldonadel))
66
+
67
+ ## 0.14.1 — 2025-04-09
68
+
69
+ _This version does not introduce any user-facing changes._
70
+
71
+ ## 0.14.0 — 2025-04-04
72
+
73
+ ### 🎉 New features
74
+
75
+ - Add `android.useDayNightTheme` to enable overriding the templates use of a light theme. ([#33989](https://github.com/expo/expo/pull/33989) by [@alanjhughes](https://github.com/alanjhughes))
76
+
11
77
  ### 🐛 Bug fixes
12
78
 
79
+ - Fixed generating falsy properties to overwrite existing props. ([#35771](https://github.com/expo/expo/pull/35771) by [@kudo](https://github.com/kudo))
80
+
81
+ ## 0.13.2 - 2025-01-10
82
+
83
+ _This version does not introduce any user-facing changes._
84
+
85
+ ## 0.13.1 — 2024-10-24
86
+
87
+ _This version does not introduce any user-facing changes._
88
+
89
+ ## 0.13.0 — 2024-10-22
90
+
91
+ ### 🛠 Breaking changes
92
+
93
+ - Bumped iOS deployment target to 15.1. ([#30840](https://github.com/expo/expo/pull/30840) by [@tsapeta](https://github.com/tsapeta))
94
+
13
95
  ### 💡 Others
14
96
 
15
97
  - Export missing types. ([#29401](https://github.com/expo/expo/pull/29401) by [@Simek](https://github.com/Simek))
@@ -20,3 +20,9 @@ export declare const withAndroidPurgeProguardRulesOnce: ConfigPlugin;
20
20
  export declare function updateAndroidProguardRules(contents: string, newProguardRules: string | null, updateMode: 'append' | 'overwrite'): string;
21
21
  export declare const withAndroidCleartextTraffic: ConfigPlugin<PluginConfigType>;
22
22
  export declare const withAndroidQueries: ConfigPlugin<PluginConfigType>;
23
+ export declare const withAndroidDayNightTheme: ConfigPlugin<PluginConfigType>;
24
+ export declare const withAndroidSettingsGradle: ConfigPlugin<PluginConfigType>;
25
+ export declare function updateAndroidSettingsGradle({ contents, buildFromSource, }: {
26
+ contents: string;
27
+ buildFromSource?: boolean;
28
+ }): string;
package/build/android.js CHANGED
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.withAndroidQueries = exports.withAndroidCleartextTraffic = exports.updateAndroidProguardRules = exports.withAndroidPurgeProguardRulesOnce = exports.withAndroidProguardRules = exports.withAndroidBuildProperties = void 0;
6
+ exports.withAndroidSettingsGradle = exports.withAndroidDayNightTheme = exports.withAndroidQueries = exports.withAndroidCleartextTraffic = exports.withAndroidPurgeProguardRulesOnce = exports.withAndroidProguardRules = exports.withAndroidBuildProperties = void 0;
7
+ exports.updateAndroidProguardRules = updateAndroidProguardRules;
8
+ exports.updateAndroidSettingsGradle = updateAndroidSettingsGradle;
7
9
  const config_plugins_1 = require("expo/config-plugins");
8
10
  const fs_1 = __importDefault(require("fs"));
9
11
  const path_1 = __importDefault(require("path"));
@@ -57,8 +59,8 @@ exports.withAndroidBuildProperties = createBuildGradlePropsConfigPlugin([
57
59
  propValueGetter: (config) => config.android?.packagingOptions?.doNotStrip?.join(','),
58
60
  },
59
61
  {
60
- propName: 'android.enableProguardInReleaseBuilds',
61
- propValueGetter: (config) => config.android?.enableProguardInReleaseBuilds?.toString(),
62
+ propName: 'android.enableMinifyInReleaseBuilds',
63
+ propValueGetter: (config) => config.android?.enableMinifyInReleaseBuilds?.toString(),
62
64
  },
63
65
  {
64
66
  propName: 'android.enableShrinkResourcesInReleaseBuilds',
@@ -72,9 +74,13 @@ exports.withAndroidBuildProperties = createBuildGradlePropsConfigPlugin([
72
74
  propName: 'EX_DEV_CLIENT_NETWORK_INSPECTOR',
73
75
  propValueGetter: (config) => (config.android?.networkInspector ?? true).toString(),
74
76
  },
77
+ {
78
+ propName: 'reactNativeReleaseLevel',
79
+ propValueGetter: (config) => config.android?.reactNativeReleaseLevel,
80
+ },
75
81
  {
76
82
  propName: 'expo.useLegacyPackaging',
77
- propValueGetter: (config) => (config.android?.useLegacyPackaging ?? false).toString(),
83
+ propValueGetter: (config) => config.android?.useLegacyPackaging?.toString(),
78
84
  },
79
85
  {
80
86
  propName: 'android.extraMavenRepos',
@@ -85,9 +91,25 @@ exports.withAndroidBuildProperties = createBuildGradlePropsConfigPlugin([
85
91
  }
86
92
  return item;
87
93
  });
88
- return JSON.stringify(extraMavenRepos);
94
+ return extraMavenRepos.length > 0 ? JSON.stringify(extraMavenRepos) : undefined;
89
95
  },
90
96
  },
97
+ {
98
+ propName: 'android.useDayNightTheme',
99
+ propValueGetter: (config) => config.android?.useDayNightTheme?.toString(),
100
+ },
101
+ {
102
+ propName: 'android.enableBundleCompression',
103
+ propValueGetter: (config) => config.android?.enableBundleCompression?.toString(),
104
+ },
105
+ {
106
+ propName: 'reactNativeArchitectures',
107
+ propValueGetter: (config) => config.android?.buildArchs?.join(','),
108
+ },
109
+ {
110
+ propName: 'exclusiveEnterpriseRepository',
111
+ propValueGetter: (config) => config.android?.exclusiveMavenMirror,
112
+ },
91
113
  ], 'withAndroidBuildProperties');
92
114
  /**
93
115
  * Appends `props.android.extraProguardRules` content into `android/app/proguard-rules.pro`
@@ -130,7 +152,7 @@ const withAndroidPurgeProguardRulesOnce = (config) => {
130
152
  * });
131
153
  * config = withBuildProperties(config as ExpoConfig, {
132
154
  * android: {
133
- * enableProguardInReleaseBuilds: true,
155
+ * enableMinifyInReleaseBuilds: true,
134
156
  * extraProguardRules: "-keep class com.mycompany.** { *; }",
135
157
  * },
136
158
  * });
@@ -174,7 +196,6 @@ function updateAndroidProguardRules(contents, newProguardRules, updateMode) {
174
196
  }
175
197
  return newContents;
176
198
  }
177
- exports.updateAndroidProguardRules = updateAndroidProguardRules;
178
199
  const withAndroidCleartextTraffic = (config, props) => {
179
200
  return (0, config_plugins_1.withAndroidManifest)(config, (config) => {
180
201
  if (props.android?.usesCleartextTraffic == null) {
@@ -212,3 +233,59 @@ const withAndroidQueries = (config, props) => {
212
233
  });
213
234
  };
214
235
  exports.withAndroidQueries = withAndroidQueries;
236
+ const withAndroidDayNightTheme = (config, props) => {
237
+ return (0, config_plugins_1.withAndroidStyles)(config, (config) => {
238
+ if (!props.android?.useDayNightTheme) {
239
+ return config;
240
+ }
241
+ const { style = [] } = config.modResults.resources;
242
+ if (!style.length) {
243
+ return config;
244
+ }
245
+ // Replace `AppTheme` and remove `ResetEditText`
246
+ const excludedStyles = ['AppTheme', 'ResetEditText'];
247
+ // Remove the hardcoded colors.
248
+ const excludedAttributes = ['android:textColor', 'android:editTextStyle'];
249
+ config.modResults.resources.style = [
250
+ {
251
+ $: {
252
+ name: 'AppTheme',
253
+ parent: 'Theme.AppCompat.DayNight.NoActionBar',
254
+ },
255
+ item: [...style[0].item.filter(({ $ }) => !excludedAttributes.includes($.name))],
256
+ },
257
+ ...style.filter(({ $ }) => !excludedStyles.includes($.name)),
258
+ ];
259
+ return config;
260
+ });
261
+ };
262
+ exports.withAndroidDayNightTheme = withAndroidDayNightTheme;
263
+ const withAndroidSettingsGradle = (config, props) => {
264
+ return (0, config_plugins_1.withSettingsGradle)(config, (config) => {
265
+ config.modResults.contents = updateAndroidSettingsGradle({
266
+ contents: config.modResults.contents,
267
+ buildFromSource: props.android?.buildReactNativeFromSource ?? props.android?.buildFromSource,
268
+ });
269
+ return config;
270
+ });
271
+ };
272
+ exports.withAndroidSettingsGradle = withAndroidSettingsGradle;
273
+ function updateAndroidSettingsGradle({ contents, buildFromSource, }) {
274
+ let newContents = contents;
275
+ if (buildFromSource === true) {
276
+ const addCodeBlock = [
277
+ '', // new line
278
+ 'includeBuild(expoAutolinking.reactNative) {',
279
+ ' dependencySubstitution {',
280
+ ' substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))',
281
+ ' substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))',
282
+ ' substitute(module("com.facebook.react:hermes-android")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))',
283
+ ' substitute(module("com.facebook.react:hermes-engine")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))',
284
+ ' }',
285
+ '}',
286
+ '', // new line
287
+ ];
288
+ newContents += addCodeBlock.join('\n');
289
+ }
290
+ return newContents;
291
+ }
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.renderQueryIntents = exports.renderQueryPackages = exports.renderQueryProviders = void 0;
3
+ exports.renderQueryProviders = renderQueryProviders;
4
+ exports.renderQueryPackages = renderQueryPackages;
5
+ exports.renderQueryIntents = renderQueryIntents;
4
6
  function renderQueryProviders(data) {
5
7
  return (Array.isArray(data) ? data : [data]).filter(Boolean).map((datum) => ({
6
8
  $: {
@@ -8,7 +10,6 @@ function renderQueryProviders(data) {
8
10
  },
9
11
  }));
10
12
  }
11
- exports.renderQueryProviders = renderQueryProviders;
12
13
  function renderQueryPackages(data) {
13
14
  return (Array.isArray(data) ? data : [data]).filter(Boolean).map((datum) => ({
14
15
  $: {
@@ -16,7 +17,6 @@ function renderQueryPackages(data) {
16
17
  },
17
18
  }));
18
19
  }
19
- exports.renderQueryPackages = renderQueryPackages;
20
20
  function renderQueryIntents(queryIntents) {
21
21
  return (queryIntents?.map((intent) => {
22
22
  const { data, category, action } = intent;
@@ -39,4 +39,3 @@ function renderQueryIntents(queryIntents) {
39
39
  };
40
40
  }) ?? []);
41
41
  }
42
- exports.renderQueryIntents = renderQueryIntents;
@@ -6,7 +6,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  return (mod && mod.__esModule) ? mod : { "default": mod };
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.purgeContents = exports.appendContents = void 0;
9
+ exports.appendContents = appendContents;
10
+ exports.purgeContents = purgeContents;
10
11
  const assert_1 = __importDefault(require("assert"));
11
12
  /**
12
13
  * Append new contents to src with generated section comments
@@ -28,7 +29,6 @@ function appendContents(src, contents, sectionOptions) {
28
29
  return `${src}\n${sectionedContents}`;
29
30
  }
30
31
  }
31
- exports.appendContents = appendContents;
32
32
  /**
33
33
  * Purge a generated section
34
34
  */
@@ -38,7 +38,6 @@ function purgeContents(src, sectionOptions) {
38
38
  const regex = new RegExp(`\\n${escapeRegExp(start)}\\n[\\s\\S]*\\n${escapeRegExp(end)}`, 'gm');
39
39
  return src.replace(regex, '');
40
40
  }
41
- exports.purgeContents = purgeContents;
42
41
  /**
43
42
  * Create comments for generated section
44
43
  */
package/build/ios.d.ts CHANGED
@@ -2,3 +2,4 @@ import { ConfigPlugin } from 'expo/config-plugins';
2
2
  import type { PluginConfigType } from './pluginConfig';
3
3
  export declare const withIosBuildProperties: ConfigPlugin<PluginConfigType>;
4
4
  export declare const withIosDeploymentTarget: ConfigPlugin<PluginConfigType>;
5
+ export declare const withIosInfoPlist: ConfigPlugin<PluginConfigType>;
package/build/ios.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withIosDeploymentTarget = exports.withIosBuildProperties = void 0;
3
+ exports.withIosInfoPlist = exports.withIosDeploymentTarget = exports.withIosBuildProperties = void 0;
4
4
  const config_plugins_1 = require("expo/config-plugins");
5
5
  const { createBuildPodfilePropsConfigPlugin } = config_plugins_1.IOSConfig.BuildProperties;
6
6
  exports.withIosBuildProperties = createBuildPodfilePropsConfigPlugin([
@@ -8,7 +8,8 @@ exports.withIosBuildProperties = createBuildPodfilePropsConfigPlugin([
8
8
  propName: 'newArchEnabled',
9
9
  propValueGetter: (config) => {
10
10
  if (config.ios?.newArchEnabled !== undefined) {
11
- config_plugins_1.WarningAggregator.addWarningIOS('withIosBuildProperties', 'ios.newArchEnabled is deprecated, use app config `newArchEnabled` instead.', 'https://docs.expo.dev/versions/latest/config/app/#newarchenabled');
11
+ config_plugins_1.WarningAggregator.addWarningIOS('withIosBuildProperties', 'ios.newArchEnabled is deprecated, use app config `newArchEnabled` instead.\n' +
12
+ 'https://docs.expo.dev/versions/latest/config/app/#newarchenabled');
12
13
  }
13
14
  return config.ios?.newArchEnabled?.toString();
14
15
  },
@@ -23,16 +24,23 @@ exports.withIosBuildProperties = createBuildPodfilePropsConfigPlugin([
23
24
  },
24
25
  {
25
26
  propName: 'apple.extraPods',
26
- propValueGetter: (config) => JSON.stringify(config.ios?.extraPods ?? []),
27
+ propValueGetter: (config) => {
28
+ const extraPods = config.ios?.extraPods ?? [];
29
+ return extraPods.length > 0 ? JSON.stringify(extraPods) : undefined;
30
+ },
27
31
  },
28
32
  {
29
33
  propName: 'apple.ccacheEnabled',
30
- propValueGetter: (config) => (config.ios?.ccacheEnabled ?? false).toString(),
34
+ propValueGetter: (config) => config.ios?.ccacheEnabled?.toString(),
31
35
  },
32
36
  {
33
37
  propName: 'apple.privacyManifestAggregationEnabled',
34
38
  propValueGetter: (config) => (config.ios?.privacyManifestAggregationEnabled ?? true).toString(),
35
39
  },
40
+ {
41
+ propName: 'ios.buildReactNativeFromSource',
42
+ propValueGetter: (config) => config.ios?.buildReactNativeFromSource?.toString(),
43
+ },
36
44
  ], 'withIosBuildProperties');
37
45
  const withIosDeploymentTarget = (config, props) => {
38
46
  const deploymentTarget = props.ios?.deploymentTarget;
@@ -46,6 +54,20 @@ const withIosDeploymentTarget = (config, props) => {
46
54
  return config;
47
55
  };
48
56
  exports.withIosDeploymentTarget = withIosDeploymentTarget;
57
+ const withIosInfoPlist = (config, props) => {
58
+ const reactNativeReleaseLevel = props.ios?.reactNativeReleaseLevel;
59
+ if (reactNativeReleaseLevel) {
60
+ config = withIosReactNativeReleaseLevel(config, { reactNativeReleaseLevel });
61
+ }
62
+ return config;
63
+ };
64
+ exports.withIosInfoPlist = withIosInfoPlist;
65
+ const withIosReactNativeReleaseLevel = (config, { reactNativeReleaseLevel }) => {
66
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
67
+ config.modResults['ReactNativeReleaseLevel'] = reactNativeReleaseLevel;
68
+ return config;
69
+ });
70
+ };
49
71
  const withIosDeploymentTargetXcodeProject = (config, props) => {
50
72
  return (0, config_plugins_1.withXcodeProject)(config, (config) => {
51
73
  config.modResults = updateDeploymentTargetXcodeProject(config.modResults, props.deploymentTarget);
@@ -19,8 +19,10 @@ export interface PluginConfigType {
19
19
  */
20
20
  export interface PluginConfigTypeAndroid {
21
21
  /**
22
- * @deprecated Use app config [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) instead.
23
- * Enable React Native new architecture for Android platform.
22
+ * Enable React Native New Architecture for Android platform.
23
+ *
24
+ * @deprecated Use [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) in
25
+ * app config file instead.
24
26
  */
25
27
  newArchEnabled?: boolean;
26
28
  /**
@@ -44,12 +46,12 @@ export interface PluginConfigTypeAndroid {
44
46
  */
45
47
  kotlinVersion?: string;
46
48
  /**
47
- * Enable [Proguard or R8](https://developer.android.com/studio/build/shrink-code) in release builds to obfuscate Java code and reduce app size.
49
+ * Enable [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) in release builds to obfuscate Java code and reduce app size.
48
50
  */
49
- enableProguardInReleaseBuilds?: boolean;
51
+ enableMinifyInReleaseBuilds?: boolean;
50
52
  /**
51
53
  * Enable [`shrinkResources`](https://developer.android.com/studio/build/shrink-code#shrink-resources) in release builds to remove unused resources from the app.
52
- * This property should be used in combination with `enableProguardInReleaseBuilds`.
54
+ * This property should be used in combination with `enableMinifyInReleaseBuilds`.
53
55
  */
54
56
  enableShrinkResourcesInReleaseBuilds?: boolean;
55
57
  /**
@@ -113,7 +115,8 @@ export interface PluginConfigTypeAndroid {
113
115
  /**
114
116
  * Indicates whether the app intends to use cleartext network traffic.
115
117
  *
116
- * @default false
118
+ * For Android 8 and below, the default platform-specific value is `true`.
119
+ * For Android 9 and above, the default platform-specific value is `false`.
117
120
  *
118
121
  * @see [Android documentation](https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic)
119
122
  */
@@ -133,6 +136,54 @@ export interface PluginConfigTypeAndroid {
133
136
  * @see [Android documentation](https://developer.android.com/guide/topics/manifest/queries-element)
134
137
  */
135
138
  manifestQueries?: PluginConfigTypeAndroidQueries;
139
+ /**
140
+ * Changes the apps theme to a DayNight variant to correctly support dark mode.
141
+ *
142
+ * @see [Android documentation](https://developer.android.com/develop/ui/views/theming/darktheme)
143
+ */
144
+ useDayNightTheme?: boolean;
145
+ /**
146
+ * Enable JavaScript Bundle compression. Turning this on will result in a smaller APK size but may have slower app startup times.
147
+ *
148
+ * @see [Faster App Startup](https://reactnative.dev/blog/2025/04/08/react-native-0.79#android-faster-app-startup)
149
+ *
150
+ * @default false
151
+ */
152
+ enableBundleCompression?: boolean;
153
+ buildReactNativeFromSource?: boolean;
154
+ /**
155
+ * Enable building React Native from source. Turning this on will significantly increase the build times.
156
+ * @deprecated Use `buildReactNativeFromSource` instead.
157
+ * @default false
158
+ */
159
+ buildFromSource?: boolean;
160
+ /**
161
+ * Override the default `reactNativeArchitectures` list of ABIs to build in **gradle.properties**.
162
+ *
163
+ * @see [Android documentation](https://developer.android.com/ndk/guides/abis) for more information.
164
+ *
165
+ * @example
166
+ * ```json
167
+ * ["arm64-v8a", "x86_64"]
168
+ * ```
169
+ *
170
+ * @default ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
171
+ */
172
+ buildArchs?: string[];
173
+ /**
174
+ * Specifies a single Maven repository to be used as an exclusive mirror for all dependency resolution.
175
+ * When set, all other Maven repositories will be ignored and only this repository will be used to fetch dependencies.
176
+ *
177
+ * @see [Using a Maven Mirror](https://reactnative.dev/docs/build-speed#using-a-maven-mirror-android-only)
178
+ */
179
+ exclusiveMavenMirror?: string;
180
+ /**
181
+ * The React Native release level to use for the project.
182
+ * This can be used to enable different sets of internal React Native feature flags.
183
+ *
184
+ * @default 'stable'
185
+ */
186
+ reactNativeReleaseLevel?: 'stable' | 'canary' | 'experimental';
136
187
  }
137
188
  /**
138
189
  * @platform android
@@ -155,25 +206,49 @@ export interface AndroidMavenRepository {
155
206
  authentication?: 'basic' | 'digest' | 'header';
156
207
  }
157
208
  /**
209
+ * The Android Maven repository credentials for basic authentication.
158
210
  * @platform android
159
211
  */
160
212
  export interface AndroidMavenRepositoryPasswordCredentials {
213
+ /**
214
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
215
+ */
161
216
  username: string;
217
+ /**
218
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
219
+ */
162
220
  password: string;
163
221
  }
164
222
  /**
223
+ * The Android Maven repository credentials that are passed as HTTP headers.
165
224
  * @platform android
166
225
  */
167
226
  export interface AndroidMavenRepositoryHttpHeaderCredentials {
227
+ /**
228
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
229
+ */
168
230
  name: string;
231
+ /**
232
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
233
+ */
169
234
  value: string;
170
235
  }
171
236
  /**
237
+ * The Android Maven repository credentials for AWS S3.
172
238
  * @platform android
173
239
  */
174
240
  export interface AndroidMavenRepositoryAWSCredentials {
241
+ /**
242
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
243
+ */
175
244
  accessKey: string;
245
+ /**
246
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
247
+ */
176
248
  secretKey: string;
249
+ /**
250
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
251
+ */
177
252
  sessionToken?: string;
178
253
  }
179
254
  /**
@@ -186,8 +261,10 @@ export type AndroidMavenRepositoryCredentials = AndroidMavenRepositoryPasswordCr
186
261
  */
187
262
  export interface PluginConfigTypeIos {
188
263
  /**
189
- * @deprecated Use app config [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) instead.
190
- * Enable React Native new architecture for iOS platform.
264
+ * Enable React Native New Architecture for iOS platform.
265
+ *
266
+ * @deprecated Use [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) in
267
+ * app config file instead.
191
268
  */
192
269
  newArchEnabled?: boolean;
193
270
  /**
@@ -246,6 +323,29 @@ export interface PluginConfigTypeIos {
246
323
  * and [Apple's documentation on Privacy manifest files](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files).
247
324
  */
248
325
  privacyManifestAggregationEnabled?: boolean;
326
+ /**
327
+ * Enables support for precompiled React Native iOS dependencies (`ReactNativeDependencies.xcframework`).
328
+ * This feature is available from React Native 0.80 and later when using the new architecture.
329
+ * From React Native 0.81, this setting will also use a precompiled React Native Core (`React.xcframework`).
330
+ *
331
+ * @default false
332
+ * @see React Expo blog for details: [Precompiled React Native for iOS: Faster builds are coming in 0.81](https://expo.dev/blog/precompiled-react-native-for-ios) for more information.
333
+ * @experimental
334
+ */
335
+ buildReactNativeFromSource?: boolean;
336
+ /**
337
+ * Enables support for prebuilt React Native iOS dependencies (`ReactNativeDependencies.xcframework`).
338
+ * This feature is available from React Native 0.80 and later.
339
+ * @deprecated Use `buildReactNativeFromSource` instead.
340
+ */
341
+ buildFromSource?: boolean;
342
+ /**
343
+ * The React Native release level to use for the project.
344
+ * This can be used to enable different sets of internal React Native feature flags.
345
+ *
346
+ * @default 'stable'
347
+ */
348
+ reactNativeReleaseLevel?: 'stable' | 'canary' | 'experimental';
249
349
  }
250
350
  /**
251
351
  * Interface representing extra CocoaPods dependency.
@@ -328,15 +428,15 @@ export interface ExtraIosPodDependency {
328
428
  */
329
429
  git?: string;
330
430
  /**
331
- * The git branch to fetch. See the {@link git} property for more information.
431
+ * The git branch to fetch. See the `git` property for more information.
332
432
  */
333
433
  branch?: string;
334
434
  /**
335
- * The git tag to fetch. See the {@link git} property for more information.
435
+ * The git tag to fetch. See the `git` property for more information.
336
436
  */
337
437
  tag?: string;
338
438
  /**
339
- * The git commit to fetch. See the {@link git} property for more information.
439
+ * The git commit to fetch. See the `git` property for more information.
340
440
  */
341
441
  commit?: string;
342
442
  }
@@ -374,12 +474,13 @@ export interface PluginConfigTypeAndroidQueries {
374
474
  * Specifies an intent filter signature. Your app can discover other apps that have matching `<intent-filter>` elements.
375
475
  * These intents have restrictions compared to typical intent filter signatures.
376
476
  *
377
- * @see [Android documentation](https://developer.android.com/training/package-visibility/declaring#intent-filter-signature) for details
477
+ * @see [Android documentation](https://developer.android.com/training/package-visibility/declaring#intent-filter-signature) for more information.
378
478
  */
379
479
  intent?: PluginConfigTypeAndroidQueriesIntent[];
380
480
  /**
381
481
  * Specifies one or more content provider authorities. Your app can discover other apps whose content providers use the specified authorities.
382
- * There are some restrictions on the options that you can include in this `<provider>` element, compared to a typical `<provider>` manifest element. You may only specify the `android:authorities` attribute.
482
+ * There are some restrictions on the options that you can include in this `<provider>` element, compared to a typical `<provider>` manifest element.
483
+ * You may only specify the `android:authorities` attribute.
383
484
  */
384
485
  provider?: string[];
385
486
  }
@@ -388,7 +489,9 @@ export interface PluginConfigTypeAndroidQueries {
388
489
  */
389
490
  export interface PluginConfigTypeAndroidQueriesIntent {
390
491
  /**
391
- * A string naming the action to perform. Usually one of the platform-defined values, such as `ACTION_SEND` or `ACTION_VIEW`.
492
+ * A string naming the action to perform. Usually one of the platform-defined values, such as `SEND` or `VIEW`.
493
+ *
494
+ * @see [Android documentation](https://developer.android.com/guide/topics/manifest/action-element) for more information.
392
495
  */
393
496
  action?: string;
394
497
  /**
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.validateConfig = void 0;
6
+ exports.validateConfig = validateConfig;
7
7
  const ajv_1 = __importDefault(require("ajv"));
8
8
  const semver_1 = __importDefault(require("semver"));
9
9
  /**
@@ -33,7 +33,7 @@ const schema = {
33
33
  targetSdkVersion: { type: 'integer', nullable: true },
34
34
  buildToolsVersion: { type: 'string', nullable: true },
35
35
  kotlinVersion: { type: 'string', nullable: true },
36
- enableProguardInReleaseBuilds: { type: 'boolean', nullable: true },
36
+ enableMinifyInReleaseBuilds: { type: 'boolean', nullable: true },
37
37
  enableShrinkResourcesInReleaseBuilds: { type: 'boolean', nullable: true },
38
38
  enablePngCrunchInReleaseBuilds: { type: 'boolean', nullable: true },
39
39
  extraProguardRules: { type: 'string', nullable: true },
@@ -107,6 +107,7 @@ const schema = {
107
107
  },
108
108
  usesCleartextTraffic: { type: 'boolean', nullable: true },
109
109
  useLegacyPackaging: { type: 'boolean', nullable: true },
110
+ useDayNightTheme: { type: 'boolean', nullable: true },
110
111
  manifestQueries: {
111
112
  type: 'object',
112
113
  properties: {
@@ -135,6 +136,16 @@ const schema = {
135
136
  },
136
137
  nullable: true,
137
138
  },
139
+ enableBundleCompression: { type: 'boolean', nullable: true },
140
+ buildFromSource: { type: 'boolean', nullable: true },
141
+ buildReactNativeFromSource: { type: 'boolean', nullable: true },
142
+ buildArchs: { type: 'array', items: { type: 'string' }, nullable: true },
143
+ exclusiveMavenMirror: { type: 'string', nullable: true },
144
+ reactNativeReleaseLevel: {
145
+ type: 'string',
146
+ enum: ['stable', 'canary', 'experimental'],
147
+ nullable: true,
148
+ },
138
149
  },
139
150
  nullable: true,
140
151
  },
@@ -169,6 +180,13 @@ const schema = {
169
180
  },
170
181
  nullable: true,
171
182
  },
183
+ buildReactNativeFromSource: { type: 'boolean', nullable: true },
184
+ buildFromSource: { type: 'boolean', nullable: true },
185
+ reactNativeReleaseLevel: {
186
+ type: 'string',
187
+ enum: ['stable', 'canary', 'experimental'],
188
+ nullable: true,
189
+ },
172
190
  },
173
191
  nullable: true,
174
192
  },
@@ -228,14 +246,18 @@ function maybeThrowInvalidVersions(config) {
228
246
  */
229
247
  function validateConfig(config) {
230
248
  const validate = new ajv_1.default({ allowUnionTypes: true }).compile(schema);
249
+ // handle deprecated enableProguardInReleaseBuilds
250
+ if (config.android?.enableProguardInReleaseBuilds !== undefined &&
251
+ config.android?.enableMinifyInReleaseBuilds === undefined) {
252
+ config.android.enableMinifyInReleaseBuilds = config.android.enableProguardInReleaseBuilds;
253
+ }
231
254
  if (!validate(config)) {
232
255
  throw new Error('Invalid expo-build-properties config: ' + JSON.stringify(validate.errors));
233
256
  }
234
257
  maybeThrowInvalidVersions(config);
235
258
  if (config.android?.enableShrinkResourcesInReleaseBuilds === true &&
236
- config.android?.enableProguardInReleaseBuilds !== true) {
237
- throw new Error('`android.enableShrinkResourcesInReleaseBuilds` requires `android.enableProguardInReleaseBuilds` to be enabled.');
259
+ config.android?.enableMinifyInReleaseBuilds !== true) {
260
+ throw new Error('`android.enableShrinkResourcesInReleaseBuilds` requires `android.enableMinifyInReleaseBuilds` to be enabled.');
238
261
  }
239
262
  return config;
240
263
  }
241
- exports.validateConfig = validateConfig;
@@ -14,6 +14,7 @@ const withBuildProperties = (config, props) => {
14
14
  config = (0, android_1.withAndroidBuildProperties)(config, pluginConfig);
15
15
  config = (0, android_1.withAndroidProguardRules)(config, pluginConfig);
16
16
  config = (0, android_1.withAndroidCleartextTraffic)(config, pluginConfig);
17
+ config = (0, android_1.withAndroidSettingsGradle)(config, pluginConfig);
17
18
  config = (0, android_1.withAndroidQueries)(config, pluginConfig);
18
19
  // Assuming `withBuildProperties` could be called multiple times from different config-plugins,
19
20
  // the `withAndroidProguardRules` always appends new rules by default.
@@ -22,8 +23,10 @@ const withBuildProperties = (config, props) => {
22
23
  //
23
24
  // plugins order matter: the later one would run first
24
25
  config = (0, android_1.withAndroidPurgeProguardRulesOnce)(config);
26
+ config = (0, android_1.withAndroidDayNightTheme)(config, pluginConfig);
25
27
  config = (0, ios_1.withIosBuildProperties)(config, pluginConfig);
26
28
  config = (0, ios_1.withIosDeploymentTarget)(config, pluginConfig);
29
+ config = (0, ios_1.withIosInfoPlist)(config, pluginConfig);
27
30
  return config;
28
31
  };
29
32
  exports.withBuildProperties = withBuildProperties;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-build-properties",
3
- "version": "1.0.0-canary-20241021-c4b5a93",
3
+ "version": "1.0.1",
4
4
  "description": "Config plugin to customize native build properties on prebuild",
5
5
  "main": "build/withBuildProperties.js",
6
6
  "types": "build/withBuildProperties.d.ts",
@@ -35,10 +35,10 @@
35
35
  "semver": "^7.6.0"
36
36
  },
37
37
  "devDependencies": {
38
- "expo-module-scripts": "3.6.0-canary-20241021-c4b5a93"
38
+ "expo-module-scripts": "^5.0.1"
39
39
  },
40
40
  "peerDependencies": {
41
- "expo": "52.0.0-canary-20241021-c4b5a93"
41
+ "expo": "*"
42
42
  },
43
- "gitHead": "c4b5a932011f3dfab7a0302ff32cce7c33aa7c28"
43
+ "gitHead": "2f7f90d0736af48cb542ccbc8addb836e330693a"
44
44
  }
package/src/android.ts CHANGED
@@ -4,7 +4,9 @@ import {
4
4
  History,
5
5
  WarningAggregator,
6
6
  withAndroidManifest,
7
+ withAndroidStyles,
7
8
  withDangerousMod,
9
+ withSettingsGradle,
8
10
  } from 'expo/config-plugins';
9
11
  import fs from 'fs';
10
12
  import path from 'path';
@@ -68,8 +70,8 @@ export const withAndroidBuildProperties = createBuildGradlePropsConfigPlugin<Plu
68
70
  propValueGetter: (config) => config.android?.packagingOptions?.doNotStrip?.join(','),
69
71
  },
70
72
  {
71
- propName: 'android.enableProguardInReleaseBuilds',
72
- propValueGetter: (config) => config.android?.enableProguardInReleaseBuilds?.toString(),
73
+ propName: 'android.enableMinifyInReleaseBuilds',
74
+ propValueGetter: (config) => config.android?.enableMinifyInReleaseBuilds?.toString(),
73
75
  },
74
76
  {
75
77
  propName: 'android.enableShrinkResourcesInReleaseBuilds',
@@ -83,9 +85,13 @@ export const withAndroidBuildProperties = createBuildGradlePropsConfigPlugin<Plu
83
85
  propName: 'EX_DEV_CLIENT_NETWORK_INSPECTOR',
84
86
  propValueGetter: (config) => (config.android?.networkInspector ?? true).toString(),
85
87
  },
88
+ {
89
+ propName: 'reactNativeReleaseLevel',
90
+ propValueGetter: (config) => config.android?.reactNativeReleaseLevel,
91
+ },
86
92
  {
87
93
  propName: 'expo.useLegacyPackaging',
88
- propValueGetter: (config) => (config.android?.useLegacyPackaging ?? false).toString(),
94
+ propValueGetter: (config) => config.android?.useLegacyPackaging?.toString(),
89
95
  },
90
96
  {
91
97
  propName: 'android.extraMavenRepos',
@@ -96,9 +102,25 @@ export const withAndroidBuildProperties = createBuildGradlePropsConfigPlugin<Plu
96
102
  }
97
103
  return item;
98
104
  });
99
- return JSON.stringify(extraMavenRepos);
105
+ return extraMavenRepos.length > 0 ? JSON.stringify(extraMavenRepos) : undefined;
100
106
  },
101
107
  },
108
+ {
109
+ propName: 'android.useDayNightTheme',
110
+ propValueGetter: (config) => config.android?.useDayNightTheme?.toString(),
111
+ },
112
+ {
113
+ propName: 'android.enableBundleCompression',
114
+ propValueGetter: (config) => config.android?.enableBundleCompression?.toString(),
115
+ },
116
+ {
117
+ propName: 'reactNativeArchitectures',
118
+ propValueGetter: (config) => config.android?.buildArchs?.join(','),
119
+ },
120
+ {
121
+ propName: 'exclusiveEnterpriseRepository',
122
+ propValueGetter: (config) => config.android?.exclusiveMavenMirror,
123
+ },
102
124
  ],
103
125
  'withAndroidBuildProperties'
104
126
  );
@@ -150,7 +172,7 @@ export const withAndroidPurgeProguardRulesOnce: ConfigPlugin = (config) => {
150
172
  * });
151
173
  * config = withBuildProperties(config as ExpoConfig, {
152
174
  * android: {
153
- * enableProguardInReleaseBuilds: true,
175
+ * enableMinifyInReleaseBuilds: true,
154
176
  * extraProguardRules: "-keep class com.mycompany.** { *; }",
155
177
  * },
156
178
  * });
@@ -261,3 +283,71 @@ export const withAndroidQueries: ConfigPlugin<PluginConfigType> = (config, props
261
283
  return config;
262
284
  });
263
285
  };
286
+
287
+ export const withAndroidDayNightTheme: ConfigPlugin<PluginConfigType> = (config, props) => {
288
+ return withAndroidStyles(config, (config) => {
289
+ if (!props.android?.useDayNightTheme) {
290
+ return config;
291
+ }
292
+
293
+ const { style = [] } = config.modResults.resources;
294
+ if (!style.length) {
295
+ return config;
296
+ }
297
+
298
+ // Replace `AppTheme` and remove `ResetEditText`
299
+ const excludedStyles = ['AppTheme', 'ResetEditText'];
300
+ // Remove the hardcoded colors.
301
+ const excludedAttributes = ['android:textColor', 'android:editTextStyle'];
302
+
303
+ config.modResults.resources.style = [
304
+ {
305
+ $: {
306
+ name: 'AppTheme',
307
+ parent: 'Theme.AppCompat.DayNight.NoActionBar',
308
+ },
309
+ item: [...style[0].item.filter(({ $ }) => !excludedAttributes.includes($.name))],
310
+ },
311
+ ...style.filter(({ $ }) => !excludedStyles.includes($.name)),
312
+ ];
313
+
314
+ return config;
315
+ });
316
+ };
317
+
318
+ export const withAndroidSettingsGradle: ConfigPlugin<PluginConfigType> = (config, props) => {
319
+ return withSettingsGradle(config, (config) => {
320
+ config.modResults.contents = updateAndroidSettingsGradle({
321
+ contents: config.modResults.contents,
322
+ buildFromSource: props.android?.buildReactNativeFromSource ?? props.android?.buildFromSource,
323
+ });
324
+ return config;
325
+ });
326
+ };
327
+
328
+ export function updateAndroidSettingsGradle({
329
+ contents,
330
+ buildFromSource,
331
+ }: {
332
+ contents: string;
333
+ buildFromSource?: boolean;
334
+ }) {
335
+ let newContents = contents;
336
+ if (buildFromSource === true) {
337
+ const addCodeBlock = [
338
+ '', // new line
339
+ 'includeBuild(expoAutolinking.reactNative) {',
340
+ ' dependencySubstitution {',
341
+ ' substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))',
342
+ ' substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))',
343
+ ' substitute(module("com.facebook.react:hermes-android")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))',
344
+ ' substitute(module("com.facebook.react:hermes-engine")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))',
345
+ ' }',
346
+ '}',
347
+ '', // new line
348
+ ];
349
+ newContents += addCodeBlock.join('\n');
350
+ }
351
+
352
+ return newContents;
353
+ }
package/src/ios.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import {
2
- IOSConfig,
3
2
  ConfigPlugin,
4
- withXcodeProject,
5
- XcodeProject,
3
+ IOSConfig,
6
4
  WarningAggregator,
5
+ XcodeProject,
6
+ withInfoPlist,
7
+ withXcodeProject,
7
8
  } from 'expo/config-plugins';
8
9
 
9
10
  import type { PluginConfigType } from './pluginConfig';
@@ -18,8 +19,8 @@ export const withIosBuildProperties = createBuildPodfilePropsConfigPlugin<Plugin
18
19
  if (config.ios?.newArchEnabled !== undefined) {
19
20
  WarningAggregator.addWarningIOS(
20
21
  'withIosBuildProperties',
21
- 'ios.newArchEnabled is deprecated, use app config `newArchEnabled` instead.',
22
- 'https://docs.expo.dev/versions/latest/config/app/#newarchenabled'
22
+ 'ios.newArchEnabled is deprecated, use app config `newArchEnabled` instead.\n' +
23
+ 'https://docs.expo.dev/versions/latest/config/app/#newarchenabled'
23
24
  );
24
25
  }
25
26
  return config.ios?.newArchEnabled?.toString();
@@ -35,17 +36,24 @@ export const withIosBuildProperties = createBuildPodfilePropsConfigPlugin<Plugin
35
36
  },
36
37
  {
37
38
  propName: 'apple.extraPods',
38
- propValueGetter: (config) => JSON.stringify(config.ios?.extraPods ?? []),
39
+ propValueGetter: (config) => {
40
+ const extraPods = config.ios?.extraPods ?? [];
41
+ return extraPods.length > 0 ? JSON.stringify(extraPods) : undefined;
42
+ },
39
43
  },
40
44
  {
41
45
  propName: 'apple.ccacheEnabled',
42
- propValueGetter: (config) => (config.ios?.ccacheEnabled ?? false).toString(),
46
+ propValueGetter: (config) => config.ios?.ccacheEnabled?.toString(),
43
47
  },
44
48
  {
45
49
  propName: 'apple.privacyManifestAggregationEnabled',
46
50
  propValueGetter: (config) =>
47
51
  (config.ios?.privacyManifestAggregationEnabled ?? true).toString(),
48
52
  },
53
+ {
54
+ propName: 'ios.buildReactNativeFromSource',
55
+ propValueGetter: (config) => config.ios?.buildReactNativeFromSource?.toString(),
56
+ },
49
57
  ],
50
58
  'withIosBuildProperties'
51
59
  );
@@ -65,6 +73,24 @@ export const withIosDeploymentTarget: ConfigPlugin<PluginConfigType> = (config,
65
73
  return config;
66
74
  };
67
75
 
76
+ export const withIosInfoPlist: ConfigPlugin<PluginConfigType> = (config, props) => {
77
+ const reactNativeReleaseLevel = props.ios?.reactNativeReleaseLevel;
78
+ if (reactNativeReleaseLevel) {
79
+ config = withIosReactNativeReleaseLevel(config, { reactNativeReleaseLevel });
80
+ }
81
+
82
+ return config;
83
+ };
84
+
85
+ const withIosReactNativeReleaseLevel: ConfigPlugin<{
86
+ reactNativeReleaseLevel: 'stable' | 'canary' | 'experimental';
87
+ }> = (config, { reactNativeReleaseLevel }) => {
88
+ return withInfoPlist(config, (config) => {
89
+ config.modResults['ReactNativeReleaseLevel'] = reactNativeReleaseLevel;
90
+ return config;
91
+ });
92
+ };
93
+
68
94
  const withIosDeploymentTargetXcodeProject: ConfigPlugin<{ deploymentTarget: string }> = (
69
95
  config,
70
96
  props
@@ -39,8 +39,10 @@ export interface PluginConfigType {
39
39
  */
40
40
  export interface PluginConfigTypeAndroid {
41
41
  /**
42
- * @deprecated Use app config [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) instead.
43
- * Enable React Native new architecture for Android platform.
42
+ * Enable React Native New Architecture for Android platform.
43
+ *
44
+ * @deprecated Use [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) in
45
+ * app config file instead.
44
46
  */
45
47
  newArchEnabled?: boolean;
46
48
  /**
@@ -64,12 +66,12 @@ export interface PluginConfigTypeAndroid {
64
66
  */
65
67
  kotlinVersion?: string;
66
68
  /**
67
- * Enable [Proguard or R8](https://developer.android.com/studio/build/shrink-code) in release builds to obfuscate Java code and reduce app size.
69
+ * Enable [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) in release builds to obfuscate Java code and reduce app size.
68
70
  */
69
- enableProguardInReleaseBuilds?: boolean;
71
+ enableMinifyInReleaseBuilds?: boolean;
70
72
  /**
71
73
  * Enable [`shrinkResources`](https://developer.android.com/studio/build/shrink-code#shrink-resources) in release builds to remove unused resources from the app.
72
- * This property should be used in combination with `enableProguardInReleaseBuilds`.
74
+ * This property should be used in combination with `enableMinifyInReleaseBuilds`.
73
75
  */
74
76
  enableShrinkResourcesInReleaseBuilds?: boolean;
75
77
  /**
@@ -137,7 +139,8 @@ export interface PluginConfigTypeAndroid {
137
139
  /**
138
140
  * Indicates whether the app intends to use cleartext network traffic.
139
141
  *
140
- * @default false
142
+ * For Android 8 and below, the default platform-specific value is `true`.
143
+ * For Android 9 and above, the default platform-specific value is `false`.
141
144
  *
142
145
  * @see [Android documentation](https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic)
143
146
  */
@@ -157,6 +160,62 @@ export interface PluginConfigTypeAndroid {
157
160
  * @see [Android documentation](https://developer.android.com/guide/topics/manifest/queries-element)
158
161
  */
159
162
  manifestQueries?: PluginConfigTypeAndroidQueries;
163
+ /**
164
+ * Changes the apps theme to a DayNight variant to correctly support dark mode.
165
+ *
166
+ * @see [Android documentation](https://developer.android.com/develop/ui/views/theming/darktheme)
167
+ */
168
+ useDayNightTheme?: boolean;
169
+
170
+ /**
171
+ * Enable JavaScript Bundle compression. Turning this on will result in a smaller APK size but may have slower app startup times.
172
+ *
173
+ * @see [Faster App Startup](https://reactnative.dev/blog/2025/04/08/react-native-0.79#android-faster-app-startup)
174
+ *
175
+ * @default false
176
+ */
177
+ enableBundleCompression?: boolean;
178
+
179
+ /*
180
+ * Enable building React Native from source. Turning this on will significantly increase the build times.
181
+ * @default false
182
+ */
183
+ buildReactNativeFromSource?: boolean;
184
+
185
+ /**
186
+ * Enable building React Native from source. Turning this on will significantly increase the build times.
187
+ * @deprecated Use `buildReactNativeFromSource` instead.
188
+ * @default false
189
+ */
190
+ buildFromSource?: boolean;
191
+ /**
192
+ * Override the default `reactNativeArchitectures` list of ABIs to build in **gradle.properties**.
193
+ *
194
+ * @see [Android documentation](https://developer.android.com/ndk/guides/abis) for more information.
195
+ *
196
+ * @example
197
+ * ```json
198
+ * ["arm64-v8a", "x86_64"]
199
+ * ```
200
+ *
201
+ * @default ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
202
+ */
203
+ buildArchs?: string[];
204
+ /**
205
+ * Specifies a single Maven repository to be used as an exclusive mirror for all dependency resolution.
206
+ * When set, all other Maven repositories will be ignored and only this repository will be used to fetch dependencies.
207
+ *
208
+ * @see [Using a Maven Mirror](https://reactnative.dev/docs/build-speed#using-a-maven-mirror-android-only)
209
+ */
210
+ exclusiveMavenMirror?: string;
211
+
212
+ /**
213
+ * The React Native release level to use for the project.
214
+ * This can be used to enable different sets of internal React Native feature flags.
215
+ *
216
+ * @default 'stable'
217
+ */
218
+ reactNativeReleaseLevel?: 'stable' | 'canary' | 'experimental';
160
219
  }
161
220
 
162
221
  // @docsMissing
@@ -181,31 +240,56 @@ export interface AndroidMavenRepository {
181
240
  authentication?: 'basic' | 'digest' | 'header';
182
241
  }
183
242
 
184
- // @docsMissing
185
243
  /**
244
+ * The Android Maven repository credentials for basic authentication.
186
245
  * @platform android
187
246
  */
188
247
  export interface AndroidMavenRepositoryPasswordCredentials {
248
+ /**
249
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
250
+ */
189
251
  username: string;
252
+
253
+ /**
254
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
255
+ */
190
256
  password: string;
191
257
  }
192
258
 
193
- // @docsMissing
194
259
  /**
260
+ * The Android Maven repository credentials that are passed as HTTP headers.
195
261
  * @platform android
196
262
  */
197
263
  export interface AndroidMavenRepositoryHttpHeaderCredentials {
264
+ /**
265
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
266
+ */
198
267
  name: string;
268
+
269
+ /**
270
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
271
+ */
199
272
  value: string;
200
273
  }
201
274
 
202
- // @docsMissing
203
275
  /**
276
+ * The Android Maven repository credentials for AWS S3.
204
277
  * @platform android
205
278
  */
206
279
  export interface AndroidMavenRepositoryAWSCredentials {
280
+ /**
281
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
282
+ */
207
283
  accessKey: string;
284
+
285
+ /**
286
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
287
+ */
208
288
  secretKey: string;
289
+
290
+ /**
291
+ * The credential value. You can also pass `"System.getenv('ENV_VAR_NAME')"` to get the value from an environment variable.
292
+ */
209
293
  sessionToken?: string;
210
294
  }
211
295
 
@@ -224,8 +308,10 @@ export type AndroidMavenRepositoryCredentials =
224
308
  */
225
309
  export interface PluginConfigTypeIos {
226
310
  /**
227
- * @deprecated Use app config [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) instead.
228
- * Enable React Native new architecture for iOS platform.
311
+ * Enable React Native New Architecture for iOS platform.
312
+ *
313
+ * @deprecated Use [`newArchEnabled`](https://docs.expo.dev/versions/latest/config/app/#newarchenabled) in
314
+ * app config file instead.
229
315
  */
230
316
  newArchEnabled?: boolean;
231
317
  /**
@@ -291,6 +377,32 @@ export interface PluginConfigTypeIos {
291
377
  * and [Apple's documentation on Privacy manifest files](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files).
292
378
  */
293
379
  privacyManifestAggregationEnabled?: boolean;
380
+
381
+ /**
382
+ * Enables support for precompiled React Native iOS dependencies (`ReactNativeDependencies.xcframework`).
383
+ * This feature is available from React Native 0.80 and later when using the new architecture.
384
+ * From React Native 0.81, this setting will also use a precompiled React Native Core (`React.xcframework`).
385
+ *
386
+ * @default false
387
+ * @see React Expo blog for details: [Precompiled React Native for iOS: Faster builds are coming in 0.81](https://expo.dev/blog/precompiled-react-native-for-ios) for more information.
388
+ * @experimental
389
+ */
390
+ buildReactNativeFromSource?: boolean;
391
+
392
+ /**
393
+ * Enables support for prebuilt React Native iOS dependencies (`ReactNativeDependencies.xcframework`).
394
+ * This feature is available from React Native 0.80 and later.
395
+ * @deprecated Use `buildReactNativeFromSource` instead.
396
+ */
397
+ buildFromSource?: boolean;
398
+
399
+ /**
400
+ * The React Native release level to use for the project.
401
+ * This can be used to enable different sets of internal React Native feature flags.
402
+ *
403
+ * @default 'stable'
404
+ */
405
+ reactNativeReleaseLevel?: 'stable' | 'canary' | 'experimental';
294
406
  }
295
407
 
296
408
  /**
@@ -374,15 +486,15 @@ export interface ExtraIosPodDependency {
374
486
  */
375
487
  git?: string;
376
488
  /**
377
- * The git branch to fetch. See the {@link git} property for more information.
489
+ * The git branch to fetch. See the `git` property for more information.
378
490
  */
379
491
  branch?: string;
380
492
  /**
381
- * The git tag to fetch. See the {@link git} property for more information.
493
+ * The git tag to fetch. See the `git` property for more information.
382
494
  */
383
495
  tag?: string;
384
496
  /**
385
- * The git commit to fetch. See the {@link git} property for more information.
497
+ * The git commit to fetch. See the `git` property for more information.
386
498
  */
387
499
  commit?: string;
388
500
  }
@@ -423,12 +535,13 @@ export interface PluginConfigTypeAndroidQueries {
423
535
  * Specifies an intent filter signature. Your app can discover other apps that have matching `<intent-filter>` elements.
424
536
  * These intents have restrictions compared to typical intent filter signatures.
425
537
  *
426
- * @see [Android documentation](https://developer.android.com/training/package-visibility/declaring#intent-filter-signature) for details
538
+ * @see [Android documentation](https://developer.android.com/training/package-visibility/declaring#intent-filter-signature) for more information.
427
539
  */
428
540
  intent?: PluginConfigTypeAndroidQueriesIntent[];
429
541
  /**
430
542
  * Specifies one or more content provider authorities. Your app can discover other apps whose content providers use the specified authorities.
431
- * There are some restrictions on the options that you can include in this `<provider>` element, compared to a typical `<provider>` manifest element. You may only specify the `android:authorities` attribute.
543
+ * There are some restrictions on the options that you can include in this `<provider>` element, compared to a typical `<provider>` manifest element.
544
+ * You may only specify the `android:authorities` attribute.
432
545
  */
433
546
  provider?: string[];
434
547
  }
@@ -439,7 +552,9 @@ export interface PluginConfigTypeAndroidQueries {
439
552
  */
440
553
  export interface PluginConfigTypeAndroidQueriesIntent {
441
554
  /**
442
- * A string naming the action to perform. Usually one of the platform-defined values, such as `ACTION_SEND` or `ACTION_VIEW`.
555
+ * A string naming the action to perform. Usually one of the platform-defined values, such as `SEND` or `VIEW`.
556
+ *
557
+ * @see [Android documentation](https://developer.android.com/guide/topics/manifest/action-element) for more information.
443
558
  */
444
559
  action?: string;
445
560
  /**
@@ -485,7 +600,7 @@ const schema: JSONSchemaType<PluginConfigType> = {
485
600
  buildToolsVersion: { type: 'string', nullable: true },
486
601
  kotlinVersion: { type: 'string', nullable: true },
487
602
 
488
- enableProguardInReleaseBuilds: { type: 'boolean', nullable: true },
603
+ enableMinifyInReleaseBuilds: { type: 'boolean', nullable: true },
489
604
  enableShrinkResourcesInReleaseBuilds: { type: 'boolean', nullable: true },
490
605
  enablePngCrunchInReleaseBuilds: { type: 'boolean', nullable: true },
491
606
  extraProguardRules: { type: 'string', nullable: true },
@@ -565,6 +680,8 @@ const schema: JSONSchemaType<PluginConfigType> = {
565
680
 
566
681
  useLegacyPackaging: { type: 'boolean', nullable: true },
567
682
 
683
+ useDayNightTheme: { type: 'boolean', nullable: true },
684
+
568
685
  manifestQueries: {
569
686
  type: 'object',
570
687
  properties: {
@@ -593,6 +710,16 @@ const schema: JSONSchemaType<PluginConfigType> = {
593
710
  },
594
711
  nullable: true,
595
712
  },
713
+ enableBundleCompression: { type: 'boolean', nullable: true },
714
+ buildFromSource: { type: 'boolean', nullable: true },
715
+ buildReactNativeFromSource: { type: 'boolean', nullable: true },
716
+ buildArchs: { type: 'array', items: { type: 'string' }, nullable: true },
717
+ exclusiveMavenMirror: { type: 'string', nullable: true },
718
+ reactNativeReleaseLevel: {
719
+ type: 'string',
720
+ enum: ['stable', 'canary', 'experimental'],
721
+ nullable: true,
722
+ },
596
723
  },
597
724
  nullable: true,
598
725
  },
@@ -629,6 +756,13 @@ const schema: JSONSchemaType<PluginConfigType> = {
629
756
  },
630
757
  nullable: true,
631
758
  },
759
+ buildReactNativeFromSource: { type: 'boolean', nullable: true },
760
+ buildFromSource: { type: 'boolean', nullable: true },
761
+ reactNativeReleaseLevel: {
762
+ type: 'string',
763
+ enum: ['stable', 'canary', 'experimental'],
764
+ nullable: true,
765
+ },
632
766
  },
633
767
  nullable: true,
634
768
  },
@@ -695,6 +829,13 @@ function maybeThrowInvalidVersions(config: PluginConfigType) {
695
829
  */
696
830
  export function validateConfig(config: any): PluginConfigType {
697
831
  const validate = new Ajv({ allowUnionTypes: true }).compile(schema);
832
+ // handle deprecated enableProguardInReleaseBuilds
833
+ if (
834
+ config.android?.enableProguardInReleaseBuilds !== undefined &&
835
+ config.android?.enableMinifyInReleaseBuilds === undefined
836
+ ) {
837
+ config.android.enableMinifyInReleaseBuilds = config.android.enableProguardInReleaseBuilds;
838
+ }
698
839
  if (!validate(config)) {
699
840
  throw new Error('Invalid expo-build-properties config: ' + JSON.stringify(validate.errors));
700
841
  }
@@ -703,10 +844,10 @@ export function validateConfig(config: any): PluginConfigType {
703
844
 
704
845
  if (
705
846
  config.android?.enableShrinkResourcesInReleaseBuilds === true &&
706
- config.android?.enableProguardInReleaseBuilds !== true
847
+ config.android?.enableMinifyInReleaseBuilds !== true
707
848
  ) {
708
849
  throw new Error(
709
- '`android.enableShrinkResourcesInReleaseBuilds` requires `android.enableProguardInReleaseBuilds` to be enabled.'
850
+ '`android.enableShrinkResourcesInReleaseBuilds` requires `android.enableMinifyInReleaseBuilds` to be enabled.'
710
851
  );
711
852
  }
712
853
 
@@ -2,12 +2,14 @@ import { ConfigPlugin } from 'expo/config-plugins';
2
2
 
3
3
  import {
4
4
  withAndroidBuildProperties,
5
+ withAndroidCleartextTraffic,
6
+ withAndroidDayNightTheme,
5
7
  withAndroidProguardRules,
6
8
  withAndroidPurgeProguardRulesOnce,
7
- withAndroidCleartextTraffic,
8
9
  withAndroidQueries,
10
+ withAndroidSettingsGradle,
9
11
  } from './android';
10
- import { withIosBuildProperties, withIosDeploymentTarget } from './ios';
12
+ import { withIosBuildProperties, withIosDeploymentTarget, withIosInfoPlist } from './ios';
11
13
  import { PluginConfigType, validateConfig } from './pluginConfig';
12
14
 
13
15
  /**
@@ -22,6 +24,7 @@ export const withBuildProperties: ConfigPlugin<PluginConfigType> = (config, prop
22
24
 
23
25
  config = withAndroidProguardRules(config, pluginConfig);
24
26
  config = withAndroidCleartextTraffic(config, pluginConfig);
27
+ config = withAndroidSettingsGradle(config, pluginConfig);
25
28
  config = withAndroidQueries(config, pluginConfig);
26
29
  // Assuming `withBuildProperties` could be called multiple times from different config-plugins,
27
30
  // the `withAndroidProguardRules` always appends new rules by default.
@@ -30,9 +33,11 @@ export const withBuildProperties: ConfigPlugin<PluginConfigType> = (config, prop
30
33
  //
31
34
  // plugins order matter: the later one would run first
32
35
  config = withAndroidPurgeProguardRulesOnce(config);
36
+ config = withAndroidDayNightTheme(config, pluginConfig);
33
37
 
34
38
  config = withIosBuildProperties(config, pluginConfig);
35
39
  config = withIosDeploymentTarget(config, pluginConfig);
40
+ config = withIosInfoPlist(config, pluginConfig);
36
41
 
37
42
  return config;
38
43
  };