@callstack/react-native-brownfield 3.9.0 → 3.11.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/CHANGELOG.md +24 -0
- package/ReactBrownfield.podspec +23 -3
- package/ios/BrownfieldDevLoadingViewBridge.h +11 -0
- package/ios/BrownfieldDevLoadingViewBridge.m +12 -0
- package/ios/{ExpoHostRuntime.swift → Expo/ExpoHostRuntime.swift} +65 -23
- package/ios/ReactNativeBrownfield.swift +14 -0
- package/ios/ReactNativeBrownfield.xcodeproj/project.pbxproj +74 -24
- package/ios/{ReactNativeHostRuntime.swift → Vanilla/ReactNativeHostRuntime.swift} +40 -12
- package/ios/swiftpm/Package.swift +27 -0
- package/ios/swiftpm/Sources/BrownfieldBundleSupport/BrownfieldBundleURLResolver.swift +28 -0
- package/ios/swiftpm/Tests/BrownfieldBundleSupportTests/BrownfieldBundleURLResolverTests.swift +156 -0
- package/lib/commonjs/expo-config-plugin/ios/withBrownfieldIos.js +1 -1
- package/lib/commonjs/expo-config-plugin/ios/withBrownfieldIos.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/ios/withFmtFix.js +12 -0
- package/lib/commonjs/expo-config-plugin/ios/withFmtFix.js.map +1 -0
- package/lib/commonjs/expo-config-plugin/ios/withIosFrameworkFiles.js +1 -1
- package/lib/commonjs/expo-config-plugin/ios/withIosFrameworkFiles.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js +6 -1
- package/lib/commonjs/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/logging.js +1 -1
- package/lib/commonjs/expo-config-plugin/logging.js.map +1 -1
- package/lib/commonjs/expo-config-plugin/template/ios/FrameworkInterface.swift +4 -1
- package/lib/module/expo-config-plugin/ios/withBrownfieldIos.js +1 -1
- package/lib/module/expo-config-plugin/ios/withBrownfieldIos.js.map +1 -1
- package/lib/module/expo-config-plugin/ios/withFmtFix.js +12 -0
- package/lib/module/expo-config-plugin/ios/withFmtFix.js.map +1 -0
- package/lib/module/expo-config-plugin/ios/withIosFrameworkFiles.js +1 -1
- package/lib/module/expo-config-plugin/ios/withIosFrameworkFiles.js.map +1 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js +6 -1
- package/lib/module/expo-config-plugin/ios/xcodeHelpers.js.map +1 -1
- package/lib/module/expo-config-plugin/logging.js +1 -1
- package/lib/module/expo-config-plugin/logging.js.map +1 -1
- package/lib/module/expo-config-plugin/template/ios/FrameworkInterface.swift +4 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/withBrownfieldIos.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/withFmtFix.d.ts +5 -0
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/withFmtFix.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/withIosFrameworkFiles.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts +14 -0
- package/lib/typescript/commonjs/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/expo-config-plugin/logging.d.ts +1 -0
- package/lib/typescript/commonjs/src/expo-config-plugin/logging.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/ios/withBrownfieldIos.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/ios/withFmtFix.d.ts +5 -0
- package/lib/typescript/module/src/expo-config-plugin/ios/withFmtFix.d.ts.map +1 -0
- package/lib/typescript/module/src/expo-config-plugin/ios/withIosFrameworkFiles.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts +14 -0
- package/lib/typescript/module/src/expo-config-plugin/ios/xcodeHelpers.d.ts.map +1 -1
- package/lib/typescript/module/src/expo-config-plugin/logging.d.ts +1 -0
- package/lib/typescript/module/src/expo-config-plugin/logging.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/expo-config-plugin/ios/withBrownfieldIos.ts +14 -2
- package/src/expo-config-plugin/ios/withFmtFix.ts +72 -0
- package/src/expo-config-plugin/ios/withIosFrameworkFiles.ts +10 -10
- package/src/expo-config-plugin/ios/xcodeHelpers.ts +134 -14
- package/src/expo-config-plugin/logging.ts +4 -0
- package/src/expo-config-plugin/template/ios/FrameworkInterface.swift +4 -1
- /package/ios/{ReactNativeView.swift → Views/ReactNativeView.swift} +0 -0
- /package/ios/{ReactNativeViewController.swift → Views/ReactNativeViewController.swift} +0 -0
- /package/ios/{BrownfieldBundlePathResolver.swift → swiftpm/Sources/BrownfieldBundleSupport/BrownfieldBundlePathResolver.swift} +0 -0
|
@@ -401,7 +401,7 @@ export function ensureTargetHasFileReferenceInResourcesBuildPhase(
|
|
|
401
401
|
* @param options The user configuration
|
|
402
402
|
* @returns Build settings object
|
|
403
403
|
*/
|
|
404
|
-
function getFrameworkBuildSettings(
|
|
404
|
+
export function getFrameworkBuildSettings(
|
|
405
405
|
{
|
|
406
406
|
configuration,
|
|
407
407
|
}: {
|
|
@@ -424,11 +424,16 @@ function getFrameworkBuildSettings(
|
|
|
424
424
|
USER_SCRIPT_SANDBOXING: 'NO',
|
|
425
425
|
SKIP_INSTALL: 'NO',
|
|
426
426
|
ENABLE_MODULE_VERIFIER: 'NO',
|
|
427
|
+
INSTALL_PATH: '"$(LOCAL_LIBRARY_DIR)/Frameworks"',
|
|
427
428
|
|
|
428
429
|
// basic settings
|
|
429
430
|
PRODUCT_BUNDLE_IDENTIFIER: `"${bundleIdentifier}"`,
|
|
430
431
|
IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
|
|
431
432
|
|
|
433
|
+
// Ensure the BrownfieldLib (or equivalent name) is installed at the correct path
|
|
434
|
+
DYLIB_INSTALL_NAME_BASE: '"@rpath"',
|
|
435
|
+
LD_DYLIB_INSTALL_NAME: '"@rpath/$(EXECUTABLE_PATH)"',
|
|
436
|
+
|
|
432
437
|
// Swift settings - use modern Swift version (5.0+) to avoid legacy Swift 3.x migration prompts
|
|
433
438
|
SWIFT_VERSION: '5.0',
|
|
434
439
|
TARGETED_DEVICE_FAMILY: `"1,2"`,
|
|
@@ -442,6 +447,62 @@ function getFrameworkBuildSettings(
|
|
|
442
447
|
};
|
|
443
448
|
}
|
|
444
449
|
|
|
450
|
+
export function rewriteBundleReactNativePhaseScriptForFrameworkTarget(
|
|
451
|
+
shellScript: string
|
|
452
|
+
): string {
|
|
453
|
+
const debugBundlingOverride = `# Brownfield framework packaging must embed JS in Debug builds.
|
|
454
|
+
if [[ "$CONFIGURATION" = *Debug* ]]; then
|
|
455
|
+
unset SKIP_BUNDLING
|
|
456
|
+
export FORCE_BUNDLING=1
|
|
457
|
+
fi
|
|
458
|
+
`;
|
|
459
|
+
const debugSkipBundlingBlock =
|
|
460
|
+
/if \[\[ "\$CONFIGURATION" = \*Debug\* \]\]; then\s+export SKIP_BUNDLING=1\s+fi\s*/m;
|
|
461
|
+
|
|
462
|
+
if (debugSkipBundlingBlock.test(shellScript)) {
|
|
463
|
+
return shellScript.replace(
|
|
464
|
+
debugSkipBundlingBlock,
|
|
465
|
+
`${debugBundlingOverride}\n`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (shellScript.includes('export FORCE_BUNDLING=1')) {
|
|
470
|
+
return shellScript;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return `${debugBundlingOverride}\n${shellScript}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function decodePbxString(value: string | undefined): string {
|
|
477
|
+
if (!value) {
|
|
478
|
+
return '';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
482
|
+
try {
|
|
483
|
+
return JSON.parse(value) as string;
|
|
484
|
+
} catch {
|
|
485
|
+
return value.slice(1, -1).replace(/\\"/g, '"');
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return value;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function encodePbxString(value: string): string {
|
|
493
|
+
return JSON.stringify(value);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function hasBuildPhaseComment(
|
|
497
|
+
phase: { comment?: string },
|
|
498
|
+
expectedComment: string
|
|
499
|
+
): boolean {
|
|
500
|
+
return (
|
|
501
|
+
phase.comment === expectedComment ||
|
|
502
|
+
phase.comment === `"${expectedComment}"`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
445
506
|
/**
|
|
446
507
|
* Finds the "Bundle React Native code and images" build phase from the main app target
|
|
447
508
|
* and adds it to the framework target's build phases
|
|
@@ -465,40 +526,85 @@ export function copyBundleReactNativePhase(
|
|
|
465
526
|
|
|
466
527
|
// find the phase by name
|
|
467
528
|
let existingPhaseUuid: string | null = null;
|
|
529
|
+
let existingPhase: Record<string, any> | null = null;
|
|
468
530
|
for (const key of Object.keys(shellScriptPhases)) {
|
|
469
531
|
if (key.endsWith('_comment')) continue;
|
|
470
532
|
const phase = shellScriptPhases[key];
|
|
471
533
|
if (phase.name === `"${buildPhaseName}"` || phase.name === buildPhaseName) {
|
|
472
534
|
existingPhaseUuid = key;
|
|
535
|
+
existingPhase = phase;
|
|
473
536
|
break;
|
|
474
537
|
}
|
|
475
538
|
}
|
|
476
539
|
|
|
477
|
-
if (!existingPhaseUuid) {
|
|
540
|
+
if (!existingPhaseUuid || !existingPhase) {
|
|
478
541
|
throw new SourceModificationError(
|
|
479
542
|
`Could not find "${buildPhaseName}" build phase, skipping`
|
|
480
543
|
);
|
|
481
544
|
}
|
|
482
545
|
|
|
483
|
-
// add the phase reference to the framework target's buildPhases array
|
|
484
546
|
const nativeTargets = project.hash.project.objects.PBXNativeTarget;
|
|
485
547
|
if (nativeTargets && nativeTargets[targetUuid]) {
|
|
486
548
|
const target = nativeTargets[targetUuid];
|
|
487
549
|
if (target.buildPhases) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
550
|
+
const targetPhaseIndex = target.buildPhases.findIndex(
|
|
551
|
+
(phase: { comment?: string }) =>
|
|
552
|
+
hasBuildPhaseComment(phase, buildPhaseName)
|
|
553
|
+
);
|
|
554
|
+
const frameworkShellPath =
|
|
555
|
+
decodePbxString(existingPhase.shellPath) || '/bin/sh';
|
|
556
|
+
const frameworkShellScript =
|
|
557
|
+
rewriteBundleReactNativePhaseScriptForFrameworkTarget(
|
|
558
|
+
decodePbxString(existingPhase.shellScript)
|
|
496
559
|
);
|
|
497
560
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
561
|
+
if (targetPhaseIndex !== -1) {
|
|
562
|
+
const currentPhaseUuid = target.buildPhases[targetPhaseIndex].value;
|
|
563
|
+
const currentPhase = shellScriptPhases[currentPhaseUuid];
|
|
564
|
+
|
|
565
|
+
if (currentPhase && currentPhaseUuid !== existingPhaseUuid) {
|
|
566
|
+
currentPhase.inputPaths = existingPhase.inputPaths ?? [];
|
|
567
|
+
currentPhase.outputPaths = existingPhase.outputPaths ?? [];
|
|
568
|
+
currentPhase.shellPath = encodePbxString(frameworkShellPath);
|
|
569
|
+
currentPhase.shellScript = encodePbxString(frameworkShellScript);
|
|
570
|
+
|
|
571
|
+
if (existingPhase.showEnvVarsInLog !== undefined) {
|
|
572
|
+
currentPhase.showEnvVarsInLog = existingPhase.showEnvVarsInLog;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
Logger.logDebug(
|
|
576
|
+
`Updated framework-specific "${buildPhaseName}" build phase on target ${target.name}`
|
|
577
|
+
);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (currentPhaseUuid === existingPhaseUuid) {
|
|
582
|
+
target.buildPhases.splice(targetPhaseIndex, 1);
|
|
583
|
+
} else {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
501
586
|
}
|
|
587
|
+
|
|
588
|
+
const addedPhase = project.addBuildPhase(
|
|
589
|
+
[],
|
|
590
|
+
'PBXShellScriptBuildPhase',
|
|
591
|
+
buildPhaseName,
|
|
592
|
+
targetUuid,
|
|
593
|
+
{
|
|
594
|
+
inputPaths: existingPhase.inputPaths ?? [],
|
|
595
|
+
outputPaths: existingPhase.outputPaths ?? [],
|
|
596
|
+
shellPath: frameworkShellPath,
|
|
597
|
+
shellScript: frameworkShellScript,
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
if (existingPhase.showEnvVarsInLog !== undefined) {
|
|
602
|
+
addedPhase.buildPhase.showEnvVarsInLog = existingPhase.showEnvVarsInLog;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
Logger.logDebug(
|
|
606
|
+
`Added framework-specific "${buildPhaseName}" build phase to target ${target.name}`
|
|
607
|
+
);
|
|
502
608
|
}
|
|
503
609
|
}
|
|
504
610
|
}
|
|
@@ -561,6 +667,10 @@ function resolveAppTargetName(
|
|
|
561
667
|
return null;
|
|
562
668
|
}
|
|
563
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Adds the "Patch ExpoModulesProvider" shell script phase to the framework target.
|
|
672
|
+
* Safe to call on every prebuild: skips creation when the phase is already present.
|
|
673
|
+
*/
|
|
564
674
|
export function addExpoPre55ShellPatchScriptPhase(
|
|
565
675
|
modRequest: ModProps<XcodeProject>,
|
|
566
676
|
project: XcodeProject,
|
|
@@ -582,6 +692,16 @@ export function addExpoPre55ShellPatchScriptPhase(
|
|
|
582
692
|
);
|
|
583
693
|
}
|
|
584
694
|
|
|
695
|
+
const existingBuildPhases =
|
|
696
|
+
project.pbxNativeTargetSection()[frameworkTargetUUID]?.buildPhases ?? [];
|
|
697
|
+
if (
|
|
698
|
+
existingBuildPhases.some((phase: { comment?: string }) =>
|
|
699
|
+
hasBuildPhaseComment(phase, 'Patch ExpoModulesProvider')
|
|
700
|
+
)
|
|
701
|
+
) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
|
|
585
705
|
project.addBuildPhase(
|
|
586
706
|
[
|
|
587
707
|
// no associated files
|
|
@@ -2,7 +2,10 @@ import Foundation
|
|
|
2
2
|
import ReactBrownfield
|
|
3
3
|
|
|
4
4
|
// Initializes a Bundle instance that points at the framework target.
|
|
5
|
-
public let ReactNativeBundle =
|
|
5
|
+
public let ReactNativeBundle =
|
|
6
|
+
Bundle(identifier: "{{BUNDLE_IDENTIFIER}}")
|
|
7
|
+
?? Bundle.allFrameworks.first { $0.bundleIdentifier == "{{BUNDLE_IDENTIFIER}}" }
|
|
8
|
+
?? Bundle(for: InternalClassForBundle.self)
|
|
6
9
|
|
|
7
10
|
class InternalClassForBundle {}
|
|
8
11
|
|
|
File without changes
|
|
File without changes
|