@bravemobile/react-native-code-push 10.0.0-beta.4 → 10.0.0

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/CodePush.js CHANGED
@@ -253,11 +253,11 @@ async function tryReportStatus(statusReport, retryOnAppResume) {
253
253
  const label = statusReport.package.label;
254
254
  if (statusReport.status === "DeploymentSucceeded") {
255
255
  log(`Reporting CodePush update success (${label})`);
256
- sharedCodePushOptions?.onUpdateSuccess(label);
256
+ sharedCodePushOptions?.onUpdateSuccess?.(label);
257
257
  } else {
258
258
  log(`Reporting CodePush update rollback (${label})`);
259
259
  await NativeCodePush.setLatestRollbackInfo(statusReport.package.packageHash);
260
- sharedCodePushOptions?.onUpdateRollback(label);
260
+ sharedCodePushOptions?.onUpdateRollback?.(label);
261
261
  }
262
262
  }
263
263
 
@@ -564,7 +564,7 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg
564
564
  }
565
565
  } catch (error) {
566
566
  syncStatusChangeCallback(CodePush.SyncStatus.UNKNOWN_ERROR);
567
- sharedCodePushOptions?.onSyncError(remotePackageLabel ?? 'unknown', error);
567
+ sharedCodePushOptions?.onSyncError?.(remotePackageLabel ?? 'unknown', error);
568
568
  log(error.message);
569
569
  throw error;
570
570
  }
package/README.md CHANGED
@@ -1,14 +1,10 @@
1
1
  # @bravemobile/react-native-code-push
2
2
 
3
- **Seamless transition from AppCenter to a fully self-hosted CodePush.**
4
-
5
-
6
- This package was created to continue using React Native CodePush without AppCenter.
7
-
8
- It allows self-hosting of CodePush deployments while retaining essential operational features.
9
-
10
-
3
+ ### Seamless Transition from AppCenter to a Fully Self-Hosted CodePush
11
4
 
5
+ - **No API Server Needed** – Use static hosting solutions (e.g., AWS S3) without maintaining additional API servers.
6
+ - **Familiar API** – Built on `microsoft/react-native-code-push`, ensuring compatibility and stability.
7
+ - **Flexible Deployment** – Implement your own release workflow, giving you complete control over the deployment process.
12
8
 
13
9
  ### 🚀 New Architecture support
14
10
 
@@ -173,7 +169,31 @@ Add the following line to the end of the file.
173
169
  }
174
170
  ```
175
171
 
176
- ### 4. "CodePush-ify" Your App
172
+ ### 4. Expo Setup
173
+ For Expo projects, you can use the automated config plugin instead of manual setup.
174
+
175
+ **Add plugin to your Expo configuration:**
176
+ ```js
177
+ // app.config.js
178
+ export default {
179
+ expo: {
180
+ plugins: ["@bravemobile/react-native-code-push"],
181
+ },
182
+ };
183
+ ```
184
+
185
+ **Run prebuild to apply changes:**
186
+ ```bash
187
+ npx expo prebuild
188
+ ```
189
+
190
+ > [!NOTE]
191
+ > The plugin automatically handles all native iOS and Android code modifications. No manual editing of AppDelegate, MainApplication, or gradle files is required.
192
+
193
+ **Requirements**
194
+ Expo SDK: 50.0.0 or higher
195
+
196
+ ### 5. "CodePush-ify" Your App
177
197
 
178
198
  The root component of your app should be wrapped with a higher-order component.
179
199
 
@@ -217,7 +237,7 @@ export default CodePush({
217
237
  > The URL for fetching the release history should point to the resource location generated by the CLI tool.
218
238
 
219
239
 
220
- #### 4-1. Telemetry Callbacks
240
+ #### 5-1. Telemetry Callbacks
221
241
 
222
242
  Please refer to the [CodePushOptions](https://github.com/Soomgo-Mobile/react-native-code-push/blob/f0d26f7614af41c6dd4daecd9f7146e2383b2b0d/typings/react-native-code-push.d.ts#L76-L95) type for more details.
223
243
  - **onUpdateSuccess:** Triggered when the update bundle is executed successfully.
@@ -227,7 +247,7 @@ Please refer to the [CodePushOptions](https://github.com/Soomgo-Mobile/react-nat
227
247
  - **onSyncError:** Triggered when an unknown error occurs during the update process. (`CodePush.SyncStatus.UNKNOWN_ERROR` status)
228
248
 
229
249
 
230
- ### 5. Configure the CLI Tool
250
+ ### 6. Configure the CLI Tool
231
251
 
232
252
  > [!TIP]
233
253
  > For a more detailed and practical example, refer to the `CodePushDemoApp` in `example` directory. ([link](https://github.com/Soomgo-Mobile/react-native-code-push/tree/master/Examples/CodePushDemoApp))
@@ -342,7 +362,7 @@ Create a new release history for a specific binary app version.
342
362
  **Example:**
343
363
  - Create a new release history for the binary app version `1.0.0`.
344
364
 
345
- ```
365
+ ```bash
346
366
  npx code-push create-history --binary-version 1.0.0 --platform ios --identifier staging
347
367
  ```
348
368
 
@@ -354,7 +374,7 @@ Display the release history for a specific binary app version.
354
374
  **Example:**
355
375
  - Show the release history for the binary app version `1.0.0`.
356
376
 
357
- ```
377
+ ```bash
358
378
  npx code-push show-history --binary-version 1.0.0 --platform ios --identifier staging
359
379
  ```
360
380
 
@@ -366,16 +386,20 @@ Release a CodePush update for a specific binary app version.
366
386
  **Example:**
367
387
  - Release a CodePush update `1.0.1` targeting the binary app version `1.0.0`.
368
388
 
369
- ```
370
- npx code-push release --target-binary-version 1.0.0 --app-version 1.0.1 \
389
+ ```bash
390
+ npx code-push release --binary-version 1.0.0 --app-version 1.0.1 \
371
391
  --platform ios --identifier staging --entry-file index.js \
372
392
  --mandatory true
393
+
394
+ # Expo project
395
+ npx code-push release --framework expo --binary-version 1.0.0 --app-version 1.0.1 --platform ios
373
396
  ```
374
- - `--target-binary-version`: The version of the binary app that the CodePush update is targeting.
397
+ - `--framework`(`-f`) : Framework type (expo)
398
+ - `--binary-version`: The version of the binary app that the CodePush update is targeting.
375
399
  - `--app-version`: The version of the CodePush update itself.
376
400
 
377
401
  > [!IMPORTANT]
378
- > `--app-version` should be greater than `--target-binary-version` (SemVer comparison).
402
+ > `--app-version` should be greater than `--binary-version` (SemVer comparison).
379
403
 
380
404
 
381
405
  #### `update-history`
@@ -387,8 +411,8 @@ Update the release history for a specific CodePush update.
387
411
  **Example:**
388
412
  - Rollback the CodePush update `1.0.1` (targeting the binary app version `1.0.0`).
389
413
 
390
- ```
391
- npx code-push update-history --target-binary-version 1.0.0 --app-version 1.0.1 \
414
+ ```bash
415
+ npx code-push update-history --binary-version 1.0.0 --app-version 1.0.1 \
392
416
  --platform ios --identifier staging \
393
417
  --enable false
394
418
  ```
@@ -398,10 +422,17 @@ npx code-push update-history --target-binary-version 1.0.0 --app-version 1.0.1 \
398
422
  Create a CodePush bundle file.
399
423
 
400
424
  **Example:**
401
- ```
425
+ ```bash
402
426
  npx code-push bundle --platform android --entry-file index.js
427
+
428
+ # Expo project
429
+ npx code-push bundle --framework expo --platform android --entry-file index.js
403
430
  ```
431
+ - `--framework`(`-f`): Framework type (expo)
404
432
 
405
433
  By default, the bundle file is created in the `/build/bundleOutput` directory.
406
434
 
435
+ > [!NOTE]
436
+ > For Expo projects, the CLI uses `expo export:embed` command for bundling instead of React Native's bundle command.
437
+
407
438
  (The file name represents a hash value of the bundle content.)
@@ -20,6 +20,22 @@
20
20
  -keepclassmembers class com.facebook.react.ReactInstanceManager {
21
21
  private final ** mBundleLoader;
22
22
  }
23
+ -keepclassmembers class com.facebook.react.ReactDelegate {
24
+ private ** mReactHost; # bridgeless
25
+ public void reload(...); # RN 0.74 and above
26
+ }
27
+ # RN 0.74 and above
28
+ -keepclassmembers class com.facebook.react.ReactActivity {
29
+ public ** getReactDelegate(...);
30
+ }
31
+ # bridgeless
32
+ -keepclassmembers class com.facebook.react.defaults.DefaultReactHostDelegate {
33
+ private ** jsBundleLoader;
34
+ }
35
+ # bridgeless
36
+ -keepclassmembers class com.facebook.react.runtime.ReactHostImpl {
37
+ private final ** mReactHostDelegate;
38
+ }
23
39
 
24
40
  # Can't find referenced class org.bouncycastle.**
25
41
  -dontwarn com.nimbusds.jose.**
package/app.plugin.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./expo/plugin/withCodePush");
@@ -1,12 +1,14 @@
1
1
  const fs = require('fs');
2
2
  const { prepareToBundleJS } = require('../../functions/prepareToBundleJS');
3
3
  const { runReactNativeBundleCommand } = require('../../functions/runReactNativeBundleCommand');
4
+ const { runExpoBundleCommand } = require('../../functions/runExpoBundleCommand');
4
5
  const { getReactTempDir } = require('../../functions/getReactTempDir');
5
6
  const { runHermesEmitBinaryCommand } = require('../../functions/runHermesEmitBinaryCommand');
6
7
  const { makeCodePushBundle } = require('../../functions/makeCodePushBundle');
7
8
  const { ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../constant');
8
9
 
9
10
  /**
11
+ * @param framework {string|undefined} 'expo'
10
12
  * @param platform {string} 'ios' | 'android'
11
13
  * @param outputRootPath {string}
12
14
  * @param entryFile {string}
@@ -15,6 +17,7 @@ const { ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../constant');
15
17
  * @return {Promise<string>} CodePush bundle file name (equals to packageHash)
16
18
  */
17
19
  async function bundleCodePush(
20
+ framework,
18
21
  platform = 'ios',
19
22
  outputRootPath = ROOT_OUTPUT_DIR,
20
23
  entryFile = ENTRY_FILE,
@@ -32,13 +35,24 @@ async function bundleCodePush(
32
35
 
33
36
  prepareToBundleJS({ deleteDirs: [outputRootPath, getReactTempDir()], makeDir: OUTPUT_CONTENT_PATH });
34
37
 
35
- runReactNativeBundleCommand(
36
- _jsBundleName,
37
- OUTPUT_CONTENT_PATH,
38
- platform,
39
- SOURCEMAP_OUTPUT,
40
- entryFile,
41
- );
38
+ if (framework === 'expo') {
39
+ runExpoBundleCommand(
40
+ _jsBundleName,
41
+ OUTPUT_CONTENT_PATH,
42
+ platform,
43
+ SOURCEMAP_OUTPUT,
44
+ entryFile,
45
+ );
46
+ } else {
47
+ runReactNativeBundleCommand(
48
+ _jsBundleName,
49
+ OUTPUT_CONTENT_PATH,
50
+ platform,
51
+ SOURCEMAP_OUTPUT,
52
+ entryFile,
53
+ );
54
+ }
55
+
42
56
  console.log('log: JS bundling complete');
43
57
 
44
58
  await runHermesEmitBinaryCommand(
@@ -4,6 +4,7 @@ const { OUTPUT_BUNDLE_DIR, ROOT_OUTPUT_DIR, ENTRY_FILE } = require('../../consta
4
4
 
5
5
  program.command('bundle')
6
6
  .description('Creates a CodePush bundle file (assumes Hermes is enabled).')
7
+ .addOption(new Option('-f, --framework <type>', 'framework type (expo)').choices(['expo']))
7
8
  .addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
8
9
  .option('-o, --output-path <string>', 'path to output root directory', ROOT_OUTPUT_DIR)
9
10
  .option('-e, --entry-file <string>', 'path to JS/TS entry file', ENTRY_FILE)
@@ -11,6 +12,7 @@ program.command('bundle')
11
12
  .option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
12
13
  /**
13
14
  * @param {Object} options
15
+ * @param {string} options.framework
14
16
  * @param {string} options.platform
15
17
  * @param {string} options.outputPath
16
18
  * @param {string} options.entryFile
@@ -20,6 +22,7 @@ program.command('bundle')
20
22
  */
21
23
  .action((options) => {
22
24
  bundleCodePush(
25
+ options.framework,
23
26
  options.platform,
24
27
  options.outputPath,
25
28
  options.entryFile,
@@ -7,6 +7,7 @@ program.command('release')
7
7
  .description('Deploys a new CodePush update for a target binary app.\nAfter creating the CodePush bundle, it uploads the file and updates the ReleaseHistory information.\n`bundleUploader`, `getReleaseHistory`, and `setReleaseHistory` functions should be implemented in the config file.')
8
8
  .requiredOption('-b, --binary-version <string>', '(Required) The target binary version')
9
9
  .requiredOption('-v, --app-version <string>', '(Required) The app version to be released. It must be greater than the binary version.')
10
+ .addOption(new Option('-f, --framework <type>', 'framework type (expo)').choices(['expo']))
10
11
  .addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
11
12
  .option('-i, --identifier <string>', 'reserved characters to distinguish the release.')
12
13
  .option('-c, --config <path>', 'set config file name (JS/TS)', CONFIG_FILE_NAME)
@@ -22,6 +23,7 @@ program.command('release')
22
23
  * @param {Object} options
23
24
  * @param {string} options.binaryVersion
24
25
  * @param {string} options.appVersion
26
+ * @param {string} options.framework
25
27
  * @param {string} options.platform
26
28
  * @param {string} options.identifier
27
29
  * @param {string} options.config
@@ -44,6 +46,7 @@ program.command('release')
44
46
  config.setReleaseHistory,
45
47
  options.binaryVersion,
46
48
  options.appVersion,
49
+ options.framework,
47
50
  options.platform,
48
51
  options.identifier,
49
52
  options.outputPath,
@@ -25,6 +25,7 @@ const { addToReleaseHistory } = require("./addToReleaseHistory");
25
25
  * ): Promise<void>}
26
26
  * @param binaryVersion {string}
27
27
  * @param appVersion {string}
28
+ * @param framework {string|undefined} 'expo'
28
29
  * @param platform {"ios" | "android"}
29
30
  * @param identifier {string?}
30
31
  * @param outputPath {string}
@@ -43,6 +44,7 @@ async function release(
43
44
  setReleaseHistory,
44
45
  binaryVersion,
45
46
  appVersion,
47
+ framework,
46
48
  platform,
47
49
  identifier,
48
50
  outputPath,
@@ -56,7 +58,7 @@ async function release(
56
58
  ) {
57
59
  const bundleFileName = skipBundle
58
60
  ? readBundleFileNameFrom(bundleDirectory)
59
- : await bundleCodePush(platform, outputPath, entryFile, jsBundleName, bundleDirectory);
61
+ : await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory);
60
62
  const bundleFilePath = `${bundleDirectory}/${bundleFileName}`;
61
63
 
62
64
  const downloadUrl = await (async () => {
@@ -0,0 +1,53 @@
1
+ const path = require('path');
2
+ const shell = require('shelljs');
3
+
4
+ /**
5
+ * Run `expo bundle` CLI command
6
+ *
7
+ * @param bundleName {string} JS bundle file name
8
+ * @param entryFile {string} App code entry file name (default: index.ts)
9
+ * @param outputPath {string} Path to output JS bundle file and assets
10
+ * @param platform {string} Platform (ios | android)
11
+ * @param sourcemapOutput {string} Path to output sourcemap file (Warning: if sourcemapOutput points to the outputPath, the sourcemap will be included in the CodePush bundle and increase the deployment size)
12
+ * @return {void}
13
+ */
14
+ function runExpoBundleCommand(
15
+ bundleName,
16
+ outputPath,
17
+ platform,
18
+ sourcemapOutput,
19
+ entryFile,
20
+ ) {
21
+ /**
22
+ * @return {string}
23
+ */
24
+ function getCliPath() {
25
+ return path.join('node_modules', '.bin', 'expo');
26
+ }
27
+
28
+ /**
29
+ * @type {string[]}
30
+ */
31
+ const expoBundleArgs = [
32
+ 'export:embed',
33
+ '--assets-dest',
34
+ outputPath,
35
+ '--bundle-output',
36
+ path.join(outputPath, bundleName),
37
+ '--dev',
38
+ 'false',
39
+ '--entry-file',
40
+ entryFile,
41
+ '--platform',
42
+ platform,
43
+ '--sourcemap-output',
44
+ sourcemapOutput,
45
+ '--reset-cache',
46
+ ];
47
+
48
+ console.log('Running "expo export:embed" command:\n');
49
+
50
+ shell.exec(`${getCliPath()} ${expoBundleArgs.join(' ')}`);
51
+ }
52
+
53
+ module.exports = { runExpoBundleCommand };
@@ -0,0 +1,15 @@
1
+ const { createRunOncePlugin } = require('expo/config-plugins');
2
+ const { withAndroidBuildScriptDependency, withAndroidMainApplicationDependency } = require('./withCodePushAndroid');
3
+ const { withIosBridgingHeader, withIosAppDelegateDependency } = require('./withCodePushIos');
4
+ const pkg = require('../../package.json');
5
+
6
+ const withCodePush = (config) => {
7
+ config = withAndroidBuildScriptDependency(config);
8
+ config = withAndroidMainApplicationDependency(config);
9
+ config = withIosBridgingHeader(config);
10
+ config = withIosAppDelegateDependency(config);
11
+
12
+ return config;
13
+ };
14
+
15
+ module.exports = createRunOncePlugin(withCodePush, pkg.name, pkg.version);
@@ -0,0 +1,72 @@
1
+ const { withAppBuildGradle, withMainApplication, WarningAggregator } = require('expo/config-plugins');
2
+
3
+ function androidApplyImplementation(appBuildGradle) {
4
+ const codePushImplementation = `apply from: "../../node_modules/@bravemobile/react-native-code-push/android/codepush.gradle"`;
5
+
6
+ if (!appBuildGradle.includes(codePushImplementation)) {
7
+ return `${appBuildGradle.trimEnd()}\n${codePushImplementation}\n`;
8
+ }
9
+
10
+ return appBuildGradle;
11
+ }
12
+
13
+ function androidMainApplicationApplyImplementation(
14
+ mainApplication,
15
+ find,
16
+ add,
17
+ reverse = false,
18
+ ) {
19
+ if (mainApplication.includes(add)) {
20
+ return mainApplication;
21
+ }
22
+
23
+ if (mainApplication.includes(find)) {
24
+ return mainApplication.replace(find, reverse ? `${add}\n${find}` : `${find}\n${add}`);
25
+ }
26
+
27
+ WarningAggregator.addWarningAndroid(
28
+ 'withCodePushAndroid',
29
+ `
30
+ Failed to detect "${find.replace(/\n/g, '').trim()}" in the MainApplication.kt.
31
+ Please add "${add.replace(/\n/g, '').trim()}" to the MainApplication.kt.
32
+ Supported format: Expo SDK default template.
33
+
34
+ Android manual setup: https://github.com/Soomgo-Mobile/react-native-code-push#3-android-setup
35
+ `,
36
+ );
37
+
38
+ return mainApplication;
39
+ }
40
+
41
+ const withAndroidBuildScriptDependency = (config) => {
42
+ return withAppBuildGradle(config, (action) => {
43
+ action.modResults.contents = androidApplyImplementation(
44
+ action.modResults.contents,
45
+ );
46
+
47
+ return action;
48
+ });
49
+ };
50
+
51
+ const withAndroidMainApplicationDependency = (config) => {
52
+ return withMainApplication(config, (action) => {
53
+ action.modResults.contents = androidMainApplicationApplyImplementation(
54
+ action.modResults.contents,
55
+ 'class MainApplication : Application(), ReactApplication {',
56
+ 'import com.microsoft.codepush.react.CodePush\n',
57
+ true,
58
+ );
59
+
60
+ action.modResults.contents = androidMainApplicationApplyImplementation(
61
+ action.modResults.contents,
62
+ 'object : DefaultReactNativeHost(this) {',
63
+ ' override fun getJSBundleFile(): String = CodePush.getJSBundleFile()\n',
64
+ );
65
+ return action;
66
+ });
67
+ };
68
+
69
+ module.exports = {
70
+ withAndroidBuildScriptDependency,
71
+ withAndroidMainApplicationDependency,
72
+ };
@@ -0,0 +1,143 @@
1
+ const { withAppDelegate, withXcodeProject, WarningAggregator } = require('expo/config-plugins');
2
+ const { getAppDelegate } = require('@expo/config-plugins/build/ios/Paths');
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ function iosApplyImplementation(
7
+ appDelegate,
8
+ find,
9
+ add,
10
+ replace,
11
+ ) {
12
+ if (appDelegate.includes(add)) {
13
+ return appDelegate;
14
+ }
15
+
16
+ if (appDelegate.includes(find)) {
17
+ return appDelegate.replace(find, replace ? add : `${find}\n${add}`);
18
+ }
19
+
20
+ WarningAggregator.addWarningIOS(
21
+ 'withCodePushIos',
22
+ `
23
+ Failed to detect "${find.replace(/\n/g, '').trim()}" in the AppDelegate.(m|swift).
24
+ Please ${replace ? 'replace' : 'add'} "${add.replace(/\n/g, '').trim()}" to the AppDelegate.(m|swift).
25
+ Supported format: Expo SDK default template.
26
+
27
+ iOS manual setup: https://github.com/Soomgo-Mobile/react-native-code-push#2-ios-setup
28
+ `,
29
+ );
30
+
31
+ return appDelegate;
32
+ }
33
+
34
+ function getBridgingHeaderFileFromXcode(project) {
35
+ const buildConfigs = project.pbxXCBuildConfigurationSection();
36
+
37
+ for (const key in buildConfigs) {
38
+ const config = buildConfigs[key];
39
+ if (
40
+ typeof config === 'object' &&
41
+ config.buildSettings &&
42
+ config.buildSettings['SWIFT_OBJC_BRIDGING_HEADER']
43
+ ) {
44
+ const bridgingHeaderFile = config.buildSettings[
45
+ 'SWIFT_OBJC_BRIDGING_HEADER'
46
+ ].replace(/"/g, '');
47
+
48
+ return bridgingHeaderFile;
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+
54
+ const withIosAppDelegateDependency = (config) => {
55
+ return withAppDelegate(config, (action) => {
56
+ const language = action.modResults.language;
57
+
58
+ if (['objc', 'objcpp'].includes(language)) {
59
+ action.modResults.contents = iosApplyImplementation(
60
+ action.modResults.contents,
61
+ `#import "AppDelegate.h"`,
62
+ `#import <CodePush/CodePush.h>`,
63
+ );
64
+ action.modResults.contents = iosApplyImplementation(
65
+ action.modResults.contents,
66
+ `return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];`,
67
+ `return [CodePush bundleURL];`,
68
+ true,
69
+ );
70
+
71
+ return action;
72
+ }
73
+
74
+ if (language === 'swift') {
75
+ action.modResults.contents = iosApplyImplementation(
76
+ action.modResults.contents,
77
+ `return Bundle.main.url(forResource: "main", withExtension: "jsbundle")`,
78
+ `return CodePush.bundleURL()`,
79
+ true,
80
+ );
81
+
82
+ return action;
83
+ }
84
+
85
+ WarningAggregator.addWarningIOS(
86
+ 'withIosAppDelegate',
87
+ `${language} AppDelegate file is not supported yet.`,
88
+ );
89
+
90
+ return action;
91
+ });
92
+ };
93
+
94
+ const withIosBridgingHeader = (config) => {
95
+ return withXcodeProject(config, (action) => {
96
+ const projectRoot = action.modRequest.projectRoot;
97
+ const appDelegate = getAppDelegate(projectRoot);
98
+
99
+ if (appDelegate.language === 'swift') {
100
+ const bridgingHeaderFile = getBridgingHeaderFileFromXcode(
101
+ action.modResults,
102
+ );
103
+
104
+ const bridgingHeaderPath = path.join(
105
+ action.modRequest.platformProjectRoot,
106
+ bridgingHeaderFile,
107
+ );
108
+
109
+ if (fs.existsSync(bridgingHeaderPath)) {
110
+ let content = fs.readFileSync(bridgingHeaderPath, 'utf8');
111
+ const codePushImport = '#import <CodePush/CodePush.h>';
112
+
113
+ if (!content.includes(codePushImport)) {
114
+ content += `${codePushImport}\n`;
115
+ fs.writeFileSync(bridgingHeaderPath, content);
116
+ }
117
+
118
+ return action;
119
+ }
120
+
121
+ WarningAggregator.addWarningIOS(
122
+ 'withIosBridgingHeader',
123
+ `
124
+ Failed to detect ${bridgingHeaderPath} file.
125
+ Please add CodePush integration manually:
126
+ #import <CodePush/CodePush.h>
127
+
128
+ Supported format: Expo SDK default template.
129
+ iOS manual setup: https://github.com/Soomgo-Mobile/react-native-code-push#2-edit-appdelegate-code
130
+ `
131
+ );
132
+
133
+ return action;
134
+ }
135
+
136
+ return action;
137
+ });
138
+ };
139
+
140
+ module.exports = {
141
+ withIosAppDelegateDependency,
142
+ withIosBridgingHeader,
143
+ };
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "@bravemobile/react-native-code-push",
3
- "version": "10.0.0-beta.4",
3
+ "version": "10.0.0",
4
4
  "description": "React Native plugin for the CodePush service",
5
5
  "main": "CodePush.js",
6
6
  "typings": "typings/react-native-code-push.d.ts",
7
7
  "homepage": "https://microsoft.github.io/code-push",
8
8
  "keywords": [
9
9
  "react-native",
10
+ "expo",
10
11
  "code",
11
- "push"
12
+ "push",
13
+ "code-push",
14
+ "react-native-code-push",
15
+ "expo-code-push"
12
16
  ],
13
17
  "author": "Soomgo Mobile Team (originally Microsoft Corporation)",
14
18
  "license": "MIT",
@@ -48,8 +52,14 @@
48
52
  "yazl": "^3.3.1"
49
53
  },
50
54
  "peerDependencies": {
55
+ "expo": ">=50.0.0",
51
56
  "react-native": "*"
52
57
  },
58
+ "peerDependenciesMeta": {
59
+ "expo": {
60
+ "optional": true
61
+ }
62
+ },
53
63
  "devDependencies": {
54
64
  "@babel/core": "^7.26.0",
55
65
  "@babel/preset-env": "^7.26.0",