fix(ios-vpn): Packet-Tunnel-.appex in eigene dst-13-Embed-Phase zwingen
Bug: die RebreakPacketTunnelExtension.appex wurde nach ReBreak.app/Extensions/ statt PlugIns/ embedded → Install-Crash AppexBundleMissingEXAppExtensionAttributesDict (klassische NSExtension im ExtensionKit-Ordner). Ursache (verifiziert gegen node_modules/xcode + E2E-Lauf der Plugin-Kette): withXcodeProject-Mods laufen LIFO — withPacketTunnelTarget zuerst, withExtensionTarget (NEURLFilter) danach. proj.addTarget() bettet die .appex über buildPhaseObject() ein, das projektweit die erste PBXCopyFilesBuildPhase mit Section-Comment "Copy Files" matcht. Der NEURLFilter-Umbau ändert nur phase.name/dstSubfolderSpec, nicht den Section-Comment → die PacketTunnel-.appex landet in der dst-16-Phase des NEURLFilter-Targets. Fix in withPacketTunnelTarget: die .appex aus allen Copy-Files-Phasen herausziehen, exklusiv in die eigene dst-13-Phase legen UND deren Section-Comment auf "Embed App Extensions" umbenennen — damit der nachfolgende NEURLFilter-addTarget-Lookup die Phase nicht mehr matcht. NEURLFilter-Code unangetastet (dessen Umbau matcht per .appex-Dateiname). Verifiziert: frisches Projekt, vorhandenes URLFilter-Target, Idempotenz. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
0d28682749
commit
adeaf4eb75
@ -243,11 +243,15 @@ function withExtensionTarget(config) {
|
||||
//
|
||||
// KLASSISCHE App-Extension — anders als das NEURLFilter-Target:
|
||||
// - normaler `app_extension`-Produkttyp,
|
||||
// - normale „Embed App Extensions"-Phase (dstSubfolderSpec 13, PlugIns/),
|
||||
// - „Embed App Extensions"-Phase mit dstSubfolderSpec 13 (PlugIns/),
|
||||
// - KEIN ExtensionKit-Sonderweg (kein dstSubfolderSpec 16, kein
|
||||
// EXAppExtensionAttributes). Der `addTarget`-Default ist hier schon korrekt
|
||||
// — wir biegen die Embed-Phase NICHT um.
|
||||
// EXAppExtensionAttributes).
|
||||
// - Deployment-Target = Main-App (iOS 16), KEIN 26.0-Gate.
|
||||
//
|
||||
// ACHTUNG: `addTarget` legt zwar eine korrekte dst-13-Phase an, embedded die
|
||||
// .appex aber wegen einer Eigenheit der `xcode`-Lib in die NEURLFilter-dst-16-
|
||||
// Phase (siehe ausführliche Begründung am Embed-Phase-Fix unten). Darum MUSS
|
||||
// die .appex hier explizit in die eigene dst-13-Phase umgehängt werden.
|
||||
|
||||
function withPacketTunnelTarget(config) {
|
||||
return withXcodeProject(config, async (cfg) => {
|
||||
@ -326,13 +330,101 @@ function withPacketTunnelTarget(config) {
|
||||
}
|
||||
});
|
||||
|
||||
// ── Embed-Phase: BEWUSST NICHT umbiegen ──
|
||||
// proj.addTarget() hat bereits eine „Copy Files"-PBXCopyFilesBuildPhase
|
||||
// (dstSubfolderSpec 13 = PlugIns/) im Haupt-Target angelegt, die unsere
|
||||
// .appex einbettet. Für eine KLASSISCHE PluginKit-App-Extension (unser
|
||||
// NEPacketTunnelProvider hat ein NSExtension-Dict in der Info.plist) ist
|
||||
// genau das korrekt — wir lassen die Phase, wie addTarget sie anlegt.
|
||||
// KEIN dstSubfolderSpec-16-Umbau wie beim NEURLFilter-Target.
|
||||
// ── Embed-Phase korrigieren — die .appex MUSS allein in dst 13 (PlugIns/) ──
|
||||
//
|
||||
// BUG (verifiziert gegen node_modules/xcode/lib/pbxProject.js + einen
|
||||
// End-to-End-Lauf der echten Plugin-Kette):
|
||||
//
|
||||
// 1. `withXcodeProject`-Mods laufen LIFO — `withPacketTunnelTarget` ist
|
||||
// zuletzt registriert und läuft daher ZUERST, `withExtensionTarget`
|
||||
// (NEURLFilter) DANACH.
|
||||
// 2. `proj.addTarget('app_extension')` ruft intern (via `addProductFile`)
|
||||
// `addToPbxCopyfilesBuildPhase`, BEVOR die neue dst-13-Copy-Files-Phase
|
||||
// existiert. `buildPhaseObject` findet im neuen Target keine eigene
|
||||
// Phase und fällt auf die ERSTE PBXCopyFilesBuildPhase zurück, deren
|
||||
// SECTION-COMMENT exakt „Copy Files" ist — projektweit.
|
||||
// 3. Ergebnis ohne Fix: die NEURLFilter-`addTarget` (läuft als zweites)
|
||||
// biegt seine Phase per `phase.name`/`dstSubfolderSpec` auf dst 16 um,
|
||||
// lässt den SECTION-COMMENT aber auf „Copy Files". Beim PacketTunnel-
|
||||
// `addTarget` matcht `buildPhaseObject` diesen Comment und pusht die
|
||||
// PacketTunnel-.appex in dieselbe dst-16-Phase. → .appex landet in
|
||||
// `ReBreak.app/Extensions/` statt `PlugIns/` → Install-Crash
|
||||
// `AppexBundleMissingEXAppExtensionAttributesDict` (klassische
|
||||
// NSExtension im ExtensionKit-Ordner).
|
||||
//
|
||||
// Fix (zwei Teile, beide nötig):
|
||||
// (a) Die PacketTunnel-.appex aus JEDER Copy-Files-Phase herausziehen und
|
||||
// exklusiv in die eigene, von `addTarget` angelegte dst-13-Phase legen.
|
||||
// (b) Den SECTION-COMMENT dieser dst-13-Phase von „Copy Files" auf
|
||||
// „Embed App Extensions" umbenennen. SONST matcht der NACH uns laufende
|
||||
// `withExtensionTarget`-`addTarget`-Aufruf via `buildPhaseObject(
|
||||
// 'Copy Files')` unsere PacketTunnel-Phase und der dortige dst-16-Umbau
|
||||
// zieht die PacketTunnel-.appex erneut mit. Comment-Rename entkoppelt
|
||||
// beide Phasen sauber (NEURLFilters eigener Umbau matcht per
|
||||
// .appex-Dateiname, nicht per Comment — bleibt also korrekt).
|
||||
const ptCopyFilesPhases = proj.hash.project.objects.PBXCopyFilesBuildPhase || {};
|
||||
const ptPhaseKeys = Object.keys(ptCopyFilesPhases).filter(
|
||||
(k) => typeof ptCopyFilesPhases[k] === 'object' && !/_comment$/.test(k),
|
||||
);
|
||||
|
||||
// (a) Den PacketTunnel-.appex-BuildFile-Eintrag finden und aus ALLEN
|
||||
// Copy-Files-Phasen entfernen.
|
||||
let ptAppexBuildFile = null;
|
||||
ptPhaseKeys.forEach((key) => {
|
||||
const phase = ptCopyFilesPhases[key];
|
||||
const kept = [];
|
||||
(phase.files || []).forEach((f) => {
|
||||
if (
|
||||
typeof f?.comment === 'string' &&
|
||||
f.comment.includes(`${PT_TARGET_NAME}.appex`)
|
||||
) {
|
||||
ptAppexBuildFile = f;
|
||||
} else {
|
||||
kept.push(f);
|
||||
}
|
||||
});
|
||||
phase.files = kept;
|
||||
});
|
||||
if (!ptAppexBuildFile) {
|
||||
throw new Error(
|
||||
'[with-rebreak-protection-ios] PacketTunnel-.appex-BuildFile nicht gefunden',
|
||||
);
|
||||
}
|
||||
|
||||
// (b) Die von addTarget frisch angelegte (jetzt leere) dst-13-Phase finden,
|
||||
// die .appex exklusiv dort einhängen UND den Section-Comment umbenennen.
|
||||
// dst 13 = PlugIns/ = der korrekte Ort für eine klassische NSExtension-
|
||||
// PluginKit-Extension.
|
||||
const ptDst13Key = ptPhaseKeys.find(
|
||||
(k) =>
|
||||
ptCopyFilesPhases[k].dstSubfolderSpec === 13 &&
|
||||
(ptCopyFilesPhases[k].files || []).length === 0,
|
||||
);
|
||||
if (!ptDst13Key) {
|
||||
throw new Error(
|
||||
'[with-rebreak-protection-ios] keine leere dst-13-Copy-Files-Phase für die PacketTunnel-.appex gefunden',
|
||||
);
|
||||
}
|
||||
ptCopyFilesPhases[ptDst13Key].name = '"Embed App Extensions"';
|
||||
ptCopyFilesPhases[ptDst13Key].files = [ptAppexBuildFile];
|
||||
// Section-Comment-Key umbenennen — entkoppelt die Phase vom
|
||||
// `buildPhaseObject('Copy Files')`-Lookup des NEURLFilter-Targets.
|
||||
const ptDst13CommentKey = `${ptDst13Key}_comment`;
|
||||
if (ptCopyFilesPhases[ptDst13CommentKey] === 'Copy Files') {
|
||||
ptCopyFilesPhases[ptDst13CommentKey] = 'Embed App Extensions';
|
||||
}
|
||||
// Auch den Build-Phase-Verweis im Target auf den neuen Comment ziehen,
|
||||
// damit pbxproj-Serialisierung + Xcode-Anzeige konsistent bleiben.
|
||||
const ptNativeTargets = proj.hash.project.objects.PBXNativeTarget || {};
|
||||
Object.keys(ptNativeTargets).forEach((tk) => {
|
||||
const nt = ptNativeTargets[tk];
|
||||
if (typeof nt !== 'object' || !Array.isArray(nt.buildPhases)) return;
|
||||
nt.buildPhases.forEach((bp) => {
|
||||
if (bp.value === ptDst13Key && bp.comment === 'Copy Files') {
|
||||
bp.comment = 'Embed App Extensions';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ── Target-Dependency: Haupt-App baut die Extension vorher ──
|
||||
const mainTargetUuid = proj.getFirstTarget().uuid;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user