#!/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/');