I'm developing a Safari Web Extension for Mac using Xcode, and I'm encountering a frustrating issue that I can't seem to resolve.
The Problem:
When I archive and export my app and install it, the extension works flawlessly in Safari—no errors, and all resources load correctly. However, when I run the app directly from Xcode (for development and debugging), Safari shows the following error in the extension preferences:
Sometimes it also shows:
Additionally, the extension doesn't appear in Safari's Extensions list when running from Xcode, even though the app launches.
This used to work and then it just stopped working randomly when I exported a copy of the app by archiving and opened that app to test it. After that I was not able to get it to work by running from Xcode.
What I've Tried So Far:
popup.html
and all other resource files are included in the extension target and are present in the Copy Bundle Resources phase.Contents/Resources/
.manifest.json
**:**
popup.html
and other resources are correct./Applications
, ~/Applications
, and ~/Library/Safari/Extensions/
./Applications
**:**
/Applications
.Additional Observations:
popup.html
are found when inspecting the built app and extension; the files are present and paths are correct.Questions:
Environment:
Any insights or suggestions would be greatly appreciated!
Adding this as a workaround until Apple fixes this issue.
Rather than relying on the Copy Bundle Resources build phase I just manually copied the necessary files by modifying an existing custom shell script which was getting called before Copy Bundle Resources.
I'll include the entire script here so other people can use it as a starting point and modify it as needed but I can't guarantee that it'll work without modifications.
Add this shell script into your Resources folder and name it whatever you want.
Ex: CopyFiles.sh
#!/bin/bash
set -e # Exit if any command fails
# Function to copy additional resources from source to destination directory since Xcode build phase fails to copy them
copy_additional_resources() {
local src_dir="$1"
local dest_dir="$2"
echo "Copying additional resources from ${src_dir} to ${dest_dir}"
# Copy directories (recursive)
echo "Copying directories..."
cp -R "${src_dir}/_locales" "${dest_dir}/"
cp -R "${src_dir}/images" "${dest_dir}/"
# Copy individual files
echo "Copying files..."
cp "${src_dir}/manifest.json" "${dest_dir}/"
cp "${src_dir}/popup.css" "${dest_dir}/"
cp "${src_dir}/popup.html" "${dest_dir}/"
# Add additional files/dirs if needed
# List contents to verify
echo "Contents of destination directory after copying:"
ls -la "${dest_dir}/"
}
echo "Environment variable SRCROOT is set to '${SRCROOT}'"
SRC_RESOURCES="${SRCROOT}/{ENTER_YOUR_EXTENSION_TARGET_DIR_HERE}/Resources"
echo "SRC_RESOURCES is set to '${SRC_RESOURCES}'"
echo "Environment variable CONTENTS_FOLDER_PATH is set to '${CONTENTS_FOLDER_PATH}'"
# Determine if this is a Mac build by checking if CONTENTS_FOLDER_PATH contains "Contents"
IS_MAC_BUILD=false
if [[ "${CONTENTS_FOLDER_PATH}" == *"Contents"* ]]; then
IS_MAC_BUILD=true
DEST_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources"
else
DEST_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
fi
if [ "${CONFIGURATION}" = "DEBUG" ]; then
echo "Running Debug build: Copying original JS files."
# For debug builds, handle directory creation based on platform
if [ "$IS_MAC_BUILD" = true ]; then
echo "Creating Resources directory for Mac build at ${DEST_DIR}."
mkdir -p "${DEST_DIR}"
fi
echo "Copying original JS files to destination directory."
cp "${SRC_RESOURCES}/content.js" "${DEST_DIR}/content.js"
cp "${SRC_RESOURCES}/background.js" "${DEST_DIR}/background.js"
cp "${SRC_RESOURCES}/popup.js" "${DEST_DIR}/popup.js"
# List copied files
echo "Verifying copied JS files in destination directory:"
ls -la "${DEST_DIR}/"
# Ensure JS files are not executable in debug builds as well
echo "Removing execute permissions from JS files."
chmod -x "${DEST_DIR}/content.js"
chmod -x "${DEST_DIR}/background.js"
chmod -x "${DEST_DIR}/popup.js"
# Manually additional files and directories
copy_additional_resources "${SRC_RESOURCES}" "${DEST_DIR}"
fi
echo "JS files processing completed successfully."
Then add a new Build Phase (Run Script phase)
Make sure you add the proper input files and output files as seen in the screenshot:
Obviously, change the string "Protego Extension" to the name of your extension target's directory
I left the Copy Bundle Resources build phase at the end of the list since everything was working as expected.
The primary purpose of my script is to minify my js scripts so I tried to remove the minification logic. Feel free to refactor the script as needed.