react-native-3rddigital-appupdate 1.0.19 → 1.0.20
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/package.json +1 -1
- package/scripts/bundle.js +164 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-3rddigital-appupdate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "A React Native library for seamless over-the-air (OTA) updates with version checks, automatic bundle download, and customizable user prompts for iOS and Android.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
package/scripts/bundle.js
CHANGED
|
@@ -169,6 +169,54 @@ function findFirstXcodeProj(dir) {
|
|
|
169
169
|
return null;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
function findFirstXcworkspace(dir) {
|
|
173
|
+
const files = fs.readdirSync(dir);
|
|
174
|
+
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
const fullPath = path.join(dir, file);
|
|
177
|
+
const stat = fs.statSync(fullPath);
|
|
178
|
+
|
|
179
|
+
if (stat.isDirectory()) {
|
|
180
|
+
if (file.endsWith('.xcworkspace') && file !== 'Pods.xcworkspace') {
|
|
181
|
+
return fullPath;
|
|
182
|
+
}
|
|
183
|
+
const nested = findFirstXcworkspace(fullPath);
|
|
184
|
+
if (nested) return nested;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function quoteShellArg(value) {
|
|
192
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function runAndCapture(command, cwd = process.cwd()) {
|
|
196
|
+
try {
|
|
197
|
+
return execSync(command, {
|
|
198
|
+
cwd,
|
|
199
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
200
|
+
})
|
|
201
|
+
.toString()
|
|
202
|
+
.trim();
|
|
203
|
+
} catch (_error) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function extractJsonObject(text) {
|
|
209
|
+
if (!text) return null;
|
|
210
|
+
|
|
211
|
+
const start = text.indexOf('{');
|
|
212
|
+
const end = text.lastIndexOf('}');
|
|
213
|
+
if (start === -1 || end === -1 || end <= start) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return text.slice(start, end + 1);
|
|
218
|
+
}
|
|
219
|
+
|
|
172
220
|
function extractBracedBlock(content, startIndex) {
|
|
173
221
|
const openIndex = content.indexOf('{', startIndex);
|
|
174
222
|
if (openIndex === -1) return null;
|
|
@@ -472,19 +520,134 @@ function getIosProjectFiles() {
|
|
|
472
520
|
return null;
|
|
473
521
|
}
|
|
474
522
|
|
|
523
|
+
const xcworkspacePath = findFirstXcworkspace(iosDir);
|
|
524
|
+
|
|
475
525
|
const pbxprojPath = path.join(xcodeProjPath, 'project.pbxproj');
|
|
476
526
|
if (!fs.existsSync(pbxprojPath)) {
|
|
477
527
|
console.warn('⚠️ project.pbxproj not found.');
|
|
478
528
|
return null;
|
|
479
529
|
}
|
|
480
530
|
|
|
481
|
-
return { iosDir, xcodeProjPath, pbxprojPath };
|
|
531
|
+
return { iosDir, xcodeProjPath, xcworkspacePath, pbxprojPath };
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function getIosBuildContainerArgs(projectFiles) {
|
|
535
|
+
if (projectFiles.xcworkspacePath) {
|
|
536
|
+
return `-workspace ${quoteShellArg(projectFiles.xcworkspacePath)}`;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return `-project ${quoteShellArg(projectFiles.xcodeProjPath)}`;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function parseXcodebuildSettings(output) {
|
|
543
|
+
const settings = {};
|
|
544
|
+
|
|
545
|
+
for (const line of output.split('\n')) {
|
|
546
|
+
const match = line.match(/^\s*([A-Za-z0-9_]+)\s*=\s*(.+)$/);
|
|
547
|
+
if (!match) continue;
|
|
548
|
+
settings[match[1]] = cleanPbxString(match[2]);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return settings;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function isResolvedBuildSetting(value) {
|
|
555
|
+
if (!value) return false;
|
|
556
|
+
|
|
557
|
+
return !/[()$]/.test(value);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function getIosSchemeMetadataFromXcodebuild(projectFiles) {
|
|
561
|
+
const projectRoot = getProjectRoot();
|
|
562
|
+
const buildContainerArgs = getIosBuildContainerArgs(projectFiles);
|
|
563
|
+
const listOutput = runAndCapture(
|
|
564
|
+
`xcodebuild -list -json ${buildContainerArgs}`,
|
|
565
|
+
projectRoot
|
|
566
|
+
);
|
|
567
|
+
|
|
568
|
+
if (!listOutput) return null;
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
const jsonOutput = extractJsonObject(listOutput);
|
|
572
|
+
if (!jsonOutput) return null;
|
|
573
|
+
|
|
574
|
+
const parsed = JSON.parse(jsonOutput);
|
|
575
|
+
const schemes =
|
|
576
|
+
parsed.project?.schemes ??
|
|
577
|
+
parsed.workspace?.schemes ??
|
|
578
|
+
parsed.project?.targets ??
|
|
579
|
+
[];
|
|
580
|
+
|
|
581
|
+
const uniqueSchemes = [...new Set(schemes)].filter(Boolean);
|
|
582
|
+
if (!uniqueSchemes.length) return null;
|
|
583
|
+
|
|
584
|
+
const entries = uniqueSchemes
|
|
585
|
+
.map((schemeName) => {
|
|
586
|
+
const buildConfigurations = ['Release', 'Profile', 'Debug'];
|
|
587
|
+
const buildSettingsOutput = buildConfigurations
|
|
588
|
+
.map((configuration) => ({
|
|
589
|
+
configuration,
|
|
590
|
+
output: runAndCapture(
|
|
591
|
+
`xcodebuild -showBuildSettings ${buildContainerArgs} -scheme ${quoteShellArg(
|
|
592
|
+
schemeName
|
|
593
|
+
)} -configuration ${quoteShellArg(configuration)}`,
|
|
594
|
+
projectRoot
|
|
595
|
+
),
|
|
596
|
+
}))
|
|
597
|
+
.find((item) => item.output)?.output;
|
|
598
|
+
|
|
599
|
+
if (!buildSettingsOutput) return null;
|
|
600
|
+
|
|
601
|
+
const settings = parseXcodebuildSettings(buildSettingsOutput);
|
|
602
|
+
const appId = isResolvedBuildSetting(settings.PRODUCT_BUNDLE_IDENTIFIER)
|
|
603
|
+
? settings.PRODUCT_BUNDLE_IDENTIFIER
|
|
604
|
+
: null;
|
|
605
|
+
const version = isResolvedBuildSetting(settings.MARKETING_VERSION)
|
|
606
|
+
? settings.MARKETING_VERSION
|
|
607
|
+
: null;
|
|
608
|
+
const targetName =
|
|
609
|
+
settings.TARGET_NAME || settings.PRODUCT_NAME || schemeName;
|
|
610
|
+
|
|
611
|
+
return {
|
|
612
|
+
name: schemeName,
|
|
613
|
+
targetName,
|
|
614
|
+
label: schemeName,
|
|
615
|
+
appId,
|
|
616
|
+
version,
|
|
617
|
+
productName: settings.PRODUCT_NAME || targetName,
|
|
618
|
+
buildConfiguration: settings.CONFIGURATION || 'Release',
|
|
619
|
+
};
|
|
620
|
+
})
|
|
621
|
+
.filter(Boolean);
|
|
622
|
+
|
|
623
|
+
if (!entries.length) return null;
|
|
624
|
+
|
|
625
|
+
const dedupedEntries = entries.filter(
|
|
626
|
+
(entry, index, allEntries) =>
|
|
627
|
+
allEntries.findIndex(
|
|
628
|
+
(candidate) =>
|
|
629
|
+
candidate.name === entry.name && candidate.appId === entry.appId
|
|
630
|
+
) === index
|
|
631
|
+
);
|
|
632
|
+
|
|
633
|
+
return {
|
|
634
|
+
defaultConfig: dedupedEntries[0] ?? null,
|
|
635
|
+
targets: dedupedEntries,
|
|
636
|
+
};
|
|
637
|
+
} catch (_error) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
482
640
|
}
|
|
483
641
|
|
|
484
642
|
function getIosTargetMetadata() {
|
|
485
643
|
const projectFiles = getIosProjectFiles();
|
|
486
644
|
if (!projectFiles) return null;
|
|
487
645
|
|
|
646
|
+
const xcodebuildMetadata = getIosSchemeMetadataFromXcodebuild(projectFiles);
|
|
647
|
+
if (xcodebuildMetadata?.targets?.length) {
|
|
648
|
+
return xcodebuildMetadata;
|
|
649
|
+
}
|
|
650
|
+
|
|
488
651
|
const pbxprojContent = fs.readFileSync(projectFiles.pbxprojPath, 'utf8');
|
|
489
652
|
const configObjects = parsePbxprojObjectsByIsa(
|
|
490
653
|
pbxprojContent,
|