Разработка расширения для браузера Safari (Safari Extension)
Safari Extension — технически самое сложное браузерное расширение из всех. Apple требует нативной Mac/iOS-оболочки, подписи через Apple Developer Program и одобрения App Store. Зато это единственный способ легально расширить Safari — особенно на iOS, где Safari остаётся безальтернативным браузером для любого WebKit-движка.
Архитектурные варианты
Safari Web Extension (современный, с Safari 14+) — основан на WebExtensions API, аналогичном Chrome/Firefox. Требует обёртки в виде нативного Mac/iOS-приложения. Это основной рекомендуемый формат с 2020 года.
Safari App Extension (устаревший) — нативный Swift/ObjC код с нативными точками расширения. Больше возможностей (доступ к нативным API), но значительно сложнее.
Content Blocker — упрощённый формат только для блокировки контента по JSON-правилам. Не требует JavaScript, работает на iOS. Используется для рекламных блокировщиков.
Структура проекта
Safari Web Extension — это Xcode-проект, где расширение является расширением таргета приложения:
MyApp.xcodeproj
├── MyApp/ # Основное приложение-оболочка
│ ├── AppDelegate.swift
│ └── ContentView.swift # Минимальный UI (инструкция по активации)
└── MyApp Extension/ # Само расширение
├── manifest.json
├── background.js
├── content.js
├── popup.html
└── Resources/
└── icons/
Конвертация Chrome Extension в Safari
Apple предоставляет инструмент safari-web-extension-converter:
# Установить Xcode (обязательно) и xcrun
xcrun safari-web-extension-converter \
./my-chrome-extension \
--project-location ./safari-project \
--app-name "My Extension" \
--bundle-identifier com.example.my-extension \
--swift
Конвертер создаёт Xcode-проект с нативной оболочкой и копирует все файлы расширения. После этого нужно:
- Исправить несовместимые API (список ниже)
- Настроить иконки приложения (требуется набор из 10+ размеров)
- Подписать через Apple Developer аккаунт
Manifest V2 vs V3 в Safari
| Версия | Safari | Статус |
|---|---|---|
| MV2 | Safari 14–17 | Работает, устаревает |
| MV3 | Safari 15.4+ | Рекомендован |
Safari 15.4 добавил поддержку MV3. Для максимальной совместимости с iOS 15+ используем MV3.
Несовместимые API и обходы
// chrome.* НЕ работает в Safari — используем browser.* или полифил
// webextension-polyfill решает большинство проблем
import browser from 'webextension-polyfill';
// НЕ работает в Safari:
// chrome.scripting.executeScript (MV3) — частично с Safari 16
// chrome.declarativeNetRequest — с Safari 15.4
// chrome.sidePanel — только Chrome
// Работает в Safari:
// browser.storage.local / sync
// browser.tabs
// browser.runtime.sendMessage
// browser.webNavigation
// browser.cookies (с разрешением)
Особенности Safari:
-
browser.storage.syncработает через iCloud — синхронизируется между Mac и iPhone/iPad -
Content Security Policy в Safari строже — некоторые
eval-зависимые библиотеки не работают - Background Service Worker — Safari иногда завершает SW агрессивно, нужно переинициализировать состояние
iOS-расширения
Safari на iOS поддерживает расширения начиная с iOS 15. Это открывает уникальный рынок, недоступный для Chrome/Firefox расширений:
// SafariExtensionViewController.swift — нативный код для iOS-части
import SafariServices
class SafariExtensionViewController: SFSafariExtensionViewController {
static let shared = SafariExtensionViewController()
// Вызывается при открытии popup в Safari на iOS
override func viewDidLoad() {
super.viewDidLoad()
// Встроенный WebView с popup.html загружается автоматически
}
}
// JavaScript → Native Bridge
// Из content script можно вызвать нативный код через:
browser.runtime.sendNativeMessage('com.example.app', { type: 'DO_NATIVE_THING' });
Подпись и публикация
# Сборка для тестирования (development signing)
xcodebuild -scheme "MyApp" -configuration Debug \
-destination "platform=macOS" build
# Архив для App Store
xcodebuild -scheme "MyApp" -configuration Release \
-archivePath build/MyApp.xcarchive archive
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportPath build/export \
-exportOptionsPlist ExportOptions.plist
Требования для публикации:
- Apple Developer Program ($99/год)
- Подпись Mac App + Safari Extension entitlements
- App Review (~1–3 дня для обновлений, до 7 дней для новых)
- Минимальная функциональность основного приложения — App Store не принимает «пустые» оболочки
Тестирование на устройствах
# Mac: включить режим разработчика
# Safari → Настройки → Дополнения → Показать меню «Разработка»
# Разработка → Разрешить неподписанные расширения
# iOS: Настройки → Safari → Расширения (появляется после установки приложения)
Структура манифеста для Safari MV3
{
"manifest_version": 3,
"name": "My Safari Extension",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"content_scripts": [{
"matches": ["https://*.example.com/*"],
"js": ["content.js"],
"run_at": "document_idle"
}],
"action": {
"default_popup": "popup.html",
"default_icon": "icons/toolbar-icon.svg"
},
"permissions": ["storage", "activeTab"],
"browser_specific_settings": {
"safari": {
"strict_min_version": "15.4"
}
}
}
Типичные проблемы и решения
Проблема: Service Worker завершается слишком быстро.
Решение: Не хранить состояние в памяти SW, использовать chrome.storage.session (Safari 16.4+) или переинициализировать при каждом старте.
Проблема: fetch в Content Script блокируется CORS.
Решение: Перенаправить запрос через Background (browser.runtime.sendMessage), так как Background обходит CORS ограничения страницы.
Проблема: Расширение не появляется на iOS. Решение: Приложение должно быть установлено и запущено хотя бы один раз. Расширение включается вручную в Settings → Safari → Extensions.
Сроки
Конвертация готового Chrome-расширения в Safari с исправлением несовместимостей и публикацией на Mac App Store — 5–8 рабочих дней. Разработка кроссплатформенного расширения (Mac + iOS) с нуля, включая нативные оболочки, тестирование и App Review — 15–25 дней. Основное время — Xcode setup, Apple Developer bureaucracy и App Review ожидание.







