Repository navigation
Description
Capacitor Version
Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 8.6.0
@capacitor/core: 8.6.0
@capacitor/android: 8.6.0
@capacitor/ios: 8.6.0
Installed Dependencies:
@capacitor/core: 8.6.0
@capacitor/cli: 8.6.0
@capacitor/android: 8.6.0
@capacitor/ios: 8.6.0
[success] iOS looking great! 👌
[success] Android looking great! 👌
Other API Details
npm --version output: 11.19.0
node --version output: v24.21.0Platforms Affected
- iOS
- Android
- Web
Current Behavior
With the experimental SPM packageOptions introduced in #8471, setting symlink: true for a plugin makes npx cap sync ios create a symlink under ios/App/CapApp-SPM/symlinks/. The symlink target is an absolute path to the plugin in node_modules:
$ readlink ios/App/CapApp-SPM/symlinks/CapacitorFirebaseMessaging
/Users/<me>/<path-to-project>/node_modules/@capacitor-firebase/messagingBecause the absolute path is specific to one machine, the project is no longer portable:
SwiftPM package resolution then fails because the symlink points to a path that doesn't exist.
Expected Behavior
The symlink target should be relative to the symlink's own directory, e.g.:
$ readlink ios/App/CapApp-SPM/symlinks/CapacitorFirebaseMessaging
../../../../node_modules/@capacitor-firebase/messagingThis would work on any machine and with any checkout location, as long as node_modules is installed.
Project Reproduction
- Create a Capacitor 8.4+ app using SPM for iOS.
npm install @capacitor-firebase/messaging- Add to
capacitor.config.json:{ "experimental": { "ios": { "spm": { "packageOptions": { "@capacitor-firebase/messaging": { "symlink": true } } } } } } npx cap sync iosfind ios -type l -lname '/*'lists the symlink, andreadlinkshows an absolute target.
Additional Information
Suggested fix: compute the target relative to the link's directory before creating the link, e.g.
if (symlink) {
- await ensureSymlink(plugin.rootPath, resolve(config.ios.nativeProjectDirAbs, 'CapApp-SPM', symlinkFolder));
+ const linkPath = resolve(config.ios.nativeProjectDirAbs, 'CapApp-SPM', symlinkFolder);
+ await ensureSymlink(relative(dirname(linkPath), plugin.rootPath), linkPath);
}Note on implementation: if the link is created with fs-extra's ensureSymlink (directly or via @ionic/utils-fs), passing a relative srcPath used to fail on re-runs when the symlink already existed. That was fixed in fs-extra 11.3.4 (jprichardson/node-fs-extra#1038, jprichardson/node-fs-extra#1064). So switching to a relative target should be paired with requiring fs-extra >= 11.3.4, otherwise subsequent cap sync runs could fail.
Current workaround:
- gitignoring
ios/App/CapApp-SPM/symlinks/and relying oncap syncto recreate the links
Activity