Розробка розширення Safari
Розширення Safari — технічно найскладніше браузерне розширення з усіх. 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.* або polyfill
// 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 → Preferences → Extensions → Show "Develop" menu
# Develop → Allow unsigned extensions
# iOS: Settings → Safari → Extensions (з'являється після установки програми)
Структура маніфеста для 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 бюрократія та очікування App Review.







