Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Safari app extensions

Building Safari app extensions

A short talk about building Safari extensions using the new SDK from Safari 10.0 - as extensions included in a Mac app, written in Xcode using native code

Kuba Suder

March 23, 2017
Tweet

More Decks by Kuba Suder

Other Decks in Programming

Transcript

  1. (Old) Safari Extensions Pros: • you can use web technologies

    (HTML/JS) • no ObjC/Swi> knowledge required • easy to port from Chrome/Firefox
  2. (Old) Safari Extensions Cons: • you have to use web

    technologies ! • no way to make " # • no analy5cs? $ • the review process is an absolute nightmare %
  3. Safari App Extensions Pros: • built in Xcode/Swi1 ❤ (or

    ObjC if you have to :) • can be distributed via Mac App Store • updated together with the app • normal app review process " • can be paid ##
  4. Safari App Extensions Cons: • no way to reuse code/skills

    from other browsers • needs to be contained in an app
  5. Building an extension • Main object: SFSafariExtensionHandler • handle toolbar

    bu3on callbacks • handle context menu callbacks • handle messages from the JavaScript side • whatever else you need running in the background
  6. Injec&ng scripts • SFSafariContentScript key • can be applied only

    to selected sites/pages • runs in the opened website's environment • safari.extension - communicate with Safari and your app • can access assets from the app bundle
  7. Communica)ng with the script JS: safari.self.addEventListener('message', function() { … });

    safari.extension.dispatchMessage('newItemsLoaded'); App: func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String: Any]!) { page.dispatchMessageToScript(withName: "reload", userInfo: nil) }
  8. Adding a toolbar bu.on • SFSafariToolbarItem key & class •

    icon as a template image • PDF (!), 19×19, simple black outline • 10.1: can be changed at runDme • can be enabled/disabled • can have a badge
  9. Responding to bu.on clicks Op#on 1: no UI • get

    a call toolbarItemClicked(in:) Op#on 2: popover • na$ve Cocoa view + SFSafariExtensionViewController • scales automa$cally, must use AutoLayout • might behave in weird ways (layers, transparency, anima$ons)
  10. Context menu items • SFSafariContextMenu key • contextMenuItemSelected(withCommand:in:userInfo:) • valida>on

    - can be shown or hidden depending on the context • you can add mul>ple items
  11. Content blocking • Safari extension can manage the content blocker

    (Safari 10.1) SFContentBlockerManager.getStateOfContentBlocker( withIdentifier: "eu.mackuba.BannerHunterMac.SafariExtension", completionHandler: { state, error in … } ) SFContentBlockerManager.reloadContentBlocker(withIdentifier: "…") { … }
  12. Site access permissions • declare access level: None / Some

    / All • access needed to read URL :( <key>SFSafariWebsiteAccess</key> <dict> <key>Level</key> <string>Some</string> <key>Allowed Domains</key> <array> <string>*.facebook.com</string> </array> </dict>
  13. Communica)ng with the app • enable App Groups • project

    capabili3es • NOT on developer.apple.com (unlike iOS apps)
  14. Communica)ng with the app • shared data folder let appGroupId

    = "KL585M628D.eu.mackuba.BannerHunter" let fileManager = FileManager.defaultManager() let container = fileManager.containerURL( forSecurityApplicationGroupIdentifier: appGroupId ) • located in: ~/Library/Group Containers
  15. Communica)ng with the app • shared user defaults container let

    defaults = UserDefaults(suiteName: appGroupId) • no support for "defaults write …" ! • edit .plist file in the Group Container • killall cfprefsd • plz file a radar ;)
  16. Communica)ng with the app (10.1) SFSafariApplication.dispatchMessage( withName: "startSync", toExtensionWithIdentifier: "eu.mackuba.BannerHunterMac.Extension",

    userInfo: ["userId": 567] ) func messageReceivedFromContainingApp( withName messageName: String, userInfo: [String : Any]? = nil) { startSync() }
  17. Pro %ps • Develop → Allow Unsigned Extensions • console.log-

    and NSLog-based debugging ! • disable app sandbox during development • use a framework to share code • extension is disabled by default aDer installaEon • for non-MAS apps, app needs to be started once