5

I want to create a Safari Extension Companion, but the option to create a Safari extension doesn't appear.

What is the right way to create an extension?

enter image description here

makerofthings7
  • 60,103
  • 53
  • 215
  • 448

2 Answers2

7

To create a Safari app extension, you add a new target to an existing project in Xcode. — mentioned in the documentation.

  1. Launch Xcode and open an existing project containing an OS X application, or create a new one.

  2. Create a new target by choosing File > New > Target.

  3. In the New Target sheet, look in the sidebar on the left and select OS X Application Extension.

  4. From the list of templates on the right, select Safari Extension and click Next.

enter image description here

  1. Enter a Product Name for your extension, such as “My Extension.”

  2. Make sure that your application project is selected in the Project menu, and that your OS X application target is selected in the Embed in Application menu.

  3. Click Finish.

  4. When Xcode asks you if you want to activate a new scheme for your new extension, click the Cancel button.


Xcode adds a new group into your project, which contains several new files, including an Info.plist file, a variety of supporting source files, an Interface Builder file, a JavaScript file, and a toolbar image PDF.

* There might be a few more steps, although I'm pretty sure you can handle it...

Add a Safari App Extension Target in Xcode

l'L'l
  • 44,951
  • 10
  • 95
  • 146
  • That creates a **Safari App Extension**, which is very different from the **Safari Extension Companion** referenced by the OP! An extension companion is the native-code counterpart to an extension that is written using JavaScript, just like all other modern browsers (Chrome especially, but also Firefox, Edge, and Opera) all use; the companion lets the extension do things that require native code, much like how NativeMessaging in Chrome and the others work. Safari App Extensions require re-writing your extension in native code, and are totally incompatible with all other browsers. – CBHacking May 17 '17 at 21:54
  • @CBHacking: Where are you getting that information? The Apple documentation states "Safari app extensions are written using a combination of JavaScript, CSS, and native code written in Objective-C or Swift" — https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/SafariAppExtension_PG/index.html#//apple_ref/doc/uid/TP40017319-CH15-SW1. In the current version of Xcode (8.3.2), there's no option for "Safari Extension Companion"; the older documentation suggests "As of Safari 10.0 on macOS 10.11.5, Safari extensions are created as app extensions in Xcode.". – l'L'l May 18 '17 at 03:12
  • Safari 10 supports both the JS-based extensions used on other WebKit-derived browsers (and Edge, for good measure) that were also used in older Safari versions, and the new native-code extensions (which use JS for content scripts injected into pages, but do not have a background/global JS page the way WebKit-based extensions do). Yes, if you want to write companions compatible with existing extensions (such as ones ported from other browsers), you need to use Xcode 7.x; this does not appear to be documented, because Apple documentation sucks. – CBHacking May 18 '17 at 07:39
  • The native-code "Safari App Extensions" have a different API than "Safari Extension Companions", requiring quite a lot more code than the Companions. This is because the Safari App Extensions are a full browser extension encompassing all the background/global functionality (which must be in native code instead of JS), in addition to the possible interop-with-other-apps stuff that was previously done in a Companion, while Companions are *just* the native interop stuff and are not themselves browser extensions. They also have a different extension type in their plists. – CBHacking May 18 '17 at 07:47
  • @CBHacking : So are you basically confirming Xcode doesn't support creating Safari Extension Companions in version 8.x? – l'L'l May 18 '17 at 19:16
  • @l'L'l Well, it doesn't offer it as a project type anymore. I suspect you could actually get them to compile, but you'd have to use Xcode 7 to create the project, or edit the configuration manually. – CBHacking May 18 '17 at 21:19
  • @l'L'l so have you succeed in this. have you made an app which communicates with the safari extension. – Vikram Sinha Jul 13 '17 at 11:28
  • @vikramsingh: Yes, I have successfully done this without issue. – l'L'l Jul 14 '17 at 05:52
  • @I'L'I thanks for the replay. can you provide me some sample code or any article, references anything because my companion is not working and continuously invalidating by safari. – Vikram Sinha Jul 14 '17 at 05:59
  • @vikramsingh: [There's a simple example project from Apple](https://developer.apple.com/library/content/samplecode/Animalify/Introduction/Intro.html#//apple_ref/doc/uid/TP40017383-Intro-DontLinkElementID_2), which I know works. Be sure to look at the `README.md`, because it has important instructions about allowing unsigned extensions to work in Safari. After you build the app, run it then open Safari > Preferences > Extensions and it should show up in there. If you go to a webpage (like google) and search for Bear you will notice it replaces the word with an emoji. – l'L'l Jul 14 '17 at 06:07
  • @vikramsingh: Also if you want it permanent or be allowed to run without invalidating each time you open Safari then you'll need to sign it with an official Apple Developer Certificate. – l'L'l Jul 14 '17 at 06:13
  • @I'L'I I have implemented this and succeed but the problem with this approach is I need to do all global & js side code in native obj-c. I can't buy this so I am willing to use already made safari extension. Safari extension companion can do communication between native app and safari extension so I want to know how to do that. Have you tried Safari extension companion? – Vikram Sinha Jul 14 '17 at 06:16
2

The easiest way is to just install Xcode 7 side-by-side with Xcode 8 - this works fine - and load your project in 7. Create the extension companion target, but don't do anything with it yet. Close Xcode 7 and open Xcode 8 to the same project/workspace, and you'll see the companion. If you use Swift you'll need to modernize the language (Xcode 7 uses Swift 2, Xcode 8 uses Swift 3); the IDE will suggest some of the changes directly when you try to compile but others you may need to change by hand.

Alternatively / more awkwardly, you can create a new target (such as a Safari Extension) in Xcode 8, and then delete the extraneous files (such as JavaScript for content injection) and edit/replace the plist in the extension to the plist of an extension companion. The key property is <string>com.apple.Safari.extension-companion</string> for the NSExtensionPointIdentifier; also make sure that the NSExtensionPrincipalClass implements the extension companion protocol (both of these keys are under NSExtension).

Please be aware that I've had mixed results with this approach. Sometimes it works, sometimes Safari pretends it can't see the extension companion at all, sometimes the extension can't see the companion until you re-load it and then it can... If you can see the extension companion, it should work (but note the warning here about if the companion crashes) and I haven't found any logging that helps troubleshoot these issues. Attempting to debug the extension companion using Xcode 8 doesn't work for me either.

I really wish Apple didn't insist so hard on "thinking different" and just supported Native Messaging like every single other modern browser.

CBHacking
  • 1,984
  • 16
  • 20
  • I am also looking for the same approach as you suggested but my companion is not establishing the connection with safari and this extension always getting invalidated by safari. Will you guide me to the right direction – Vikram Sinha Jul 13 '17 at 11:27
  • @vikramsingh Unfortunately, I'm having the same problem getting the browser (or at least the extension) to see the companion. A few things I've found to *sometimes* work: 1) Wait a while. Apparently the OS sometimes doesn't see app extensions immediately? 2) Try debugging the companion, against either its containing app or against Safari; sometimes this seems to help Safari see it. 3) Try reloading the extension, possibly from Extension Builder (if relevant) or from the Refresh button on on the global page inspector; I've had the companion mysteriously appear after doing that. – CBHacking Jul 13 '17 at 17:38
  • That's not fair. Apart from assuming Apple's decisions purely made just to be different, the idea that consensus is always the truth is dangerous. – Adrian Bartholomew Mar 03 '19 at 09:10