rebreak-monorepo/apps/rebreak-native/scripts/fix-embed-extension.js

141 lines
5.0 KiB
JavaScript

#!/usr/bin/env node
/**
* One-shot Fix: fügt die fehlende "Embed App Extensions" Build-Phase ins
* existierende Xcode-Projekt ein, ohne den ganzen Prebuild zu wiederholen.
*
* Wird auch in `with-rebreak-protection-ios.js` als Logik referenziert,
* damit zukünftige Prebuilds das richtig hinkriegen.
*
* Usage: node scripts/fix-embed-extension.js
*/
const fs = require('fs');
const path = require('path');
const xcode = require('xcode');
const PROJECT_ROOT = path.resolve(__dirname, '..');
const PBXPROJ = path.join(PROJECT_ROOT, 'ios', 'Rebreak.xcodeproj', 'project.pbxproj');
const TARGET_NAME = 'RebreakURLFilter';
if (!fs.existsSync(PBXPROJ)) {
console.error('❌ pbxproj not found at:', PBXPROJ);
process.exit(1);
}
const project = xcode.project(PBXPROJ);
project.parseSync();
// 1) Find Main + Extension targets
const mainTarget = project.getFirstTarget();
if (!mainTarget) {
console.error('❌ no main target found');
process.exit(1);
}
const mainTargetUuid = mainTarget.uuid;
const extTargetUuid = project.findTargetKey(TARGET_NAME);
if (!extTargetUuid) {
console.error(`❌ Extension target "${TARGET_NAME}" not found`);
process.exit(1);
}
console.log(`✓ Main target: ${mainTarget.firstTarget.name} (${mainTargetUuid})`);
console.log(`✓ Extension target: ${TARGET_NAME} (${extTargetUuid})`);
// 2) Check existing Embed phase
const buildPhases = project.hash.project.objects.PBXNativeTarget[mainTargetUuid].buildPhases || [];
const copyFilesPhases = project.hash.project.objects.PBXCopyFilesBuildPhase || {};
let hasEmbedPhase = false;
for (const key of Object.keys(copyFilesPhases)) {
const phase = copyFilesPhases[key];
if (typeof phase !== 'object') continue;
if (!buildPhases.some((bp) => bp.value === key)) continue;
// dstSubfolderSpec kann String '13' oder Number 13 sein — beide checken
if (phase.dstSubfolderSpec === 13 || phase.dstSubfolderSpec === '13') {
hasEmbedPhase = true;
console.log(`✓ Embed phase already exists: ${key}`);
break;
}
}
if (hasEmbedPhase) {
console.log('✓ Already has Embed App Extensions phase');
} else {
console.log('→ Adding Embed App Extensions phase to main target...');
const newPhase = project.addBuildPhase(
[`${TARGET_NAME}.appex`],
'PBXCopyFilesBuildPhase',
'Embed App Extensions',
mainTargetUuid,
'app_extension',
);
const phaseObj = project.hash.project.objects.PBXCopyFilesBuildPhase[newPhase.uuid];
if (phaseObj && phaseObj.dstSubfolderSpec !== 13 && phaseObj.dstSubfolderSpec !== '13') {
phaseObj.dstSubfolderSpec = 13;
phaseObj.dstPath = '';
}
}
// Target-Dependency: Main → Extension (zwingt Build-Order)
console.log('→ Ensuring target dependency (Main → Extension)...');
const mainObj = project.hash.project.objects.PBXNativeTarget[mainTargetUuid];
const existingDeps = mainObj.dependencies || [];
const dependencyTargets = project.hash.project.objects.PBXTargetDependency || {};
const hasDepToExt = existingDeps.some((dep) => {
const depObj = dependencyTargets[dep.value];
return depObj && depObj.target === extTargetUuid;
});
if (!hasDepToExt) {
project.addTargetDependency(mainTargetUuid, [extTargetUuid]);
console.log('✓ Target dependency added');
} else {
console.log('✓ Target dependency already exists');
}
// Save & exit (von hier — die ursprüngliche save-Logik unten wurde durch dieses Block ersetzt)
fs.writeFileSync(PBXPROJ, project.writeSync());
console.log('✅ Saved pbxproj');
console.log('Now: in Xcode → Cmd+Shift+K (clean) → Cmd+B (build)');
process.exit(0);
// 3) Add Embed phase
console.log('→ Adding Embed App Extensions phase to main target...');
const newPhase = project.addBuildPhase(
[`${TARGET_NAME}.appex`],
'PBXCopyFilesBuildPhase',
'Embed App Extensions',
mainTargetUuid,
'app_extension',
);
console.log(`✓ New phase UUID: ${newPhase.uuid}`);
// 4) Verify dstSubfolderSpec was set correctly
const phaseObj = project.hash.project.objects.PBXCopyFilesBuildPhase[newPhase.uuid];
if (phaseObj && phaseObj.dstSubfolderSpec !== 13 && phaseObj.dstSubfolderSpec !== '13') {
console.log(
`⚠️ dstSubfolderSpec was ${phaseObj.dstSubfolderSpec}, forcing to 13`,
);
phaseObj.dstSubfolderSpec = 13;
phaseObj.dstPath = '';
}
// 5) Add target dependency: Main → Extension
// Sorgt dafür dass Xcode die Extension VOR der Main-App baut.
console.log('→ Adding target dependency: Main → Extension...');
try {
project.addTargetDependency(mainTargetUuid, [extTargetUuid]);
console.log('✓ Target dependency added');
} catch (e) {
console.log('⚠️ Target dependency might already exist:', e.message);
}
// 6) Add Extension's appex to the main app's Frameworks/PBXFileReference linkage
// so Xcode knows where to find it during embedding.
// (xcode npm package's addBuildPhase handles file references automatically
// if the .appex was registered via addTarget — sollte schon da sein.)
// 7) Save
fs.writeFileSync(PBXPROJ, project.writeSync());
console.log('✅ Saved pbxproj');
console.log('');
console.log('Now rebuild in Xcode (Cmd+B). The .appex should be embedded into Rebreak.app/PlugIns/');