9

I'm trying to embed a Finder Sync extension written in Swift in my app written with Electron. How can I manage to make them work together and communicate with each other? I have read the Apple documentation but it only explains how to add a target to a native application. I also noticed that I can manually inject the .appex compiled file (produced by XCode) in the application Plugins folder using electron builder. How can I develop and test the extension in XCode and embed it correctly in a custom Electron app? Any suggestion?

Thank you very much for any suggestion

Marco Moschettini
  • 1,555
  • 2
  • 16
  • 26
  • 1
    Have you tried simply copying and pasting your appex to the Plugins folder of your Electron app? As long as your extension is configured according to the documentation, it should launch alongside your main app (it may need to be signed to automatically launch). For testing, make sure your extension is visible and enabled in System Preferences -> Extensions. Then attach your debugger to your Finder Sync process in XCode. – dejuknow Aug 18 '17 at 19:27
  • Yes! This method works fine if the `.plist` files are written accordingly as the extension starts correctly. The only question remaining is how to let the main application communicate with the extension if the documentation specifies that the only allowed method is to extend the `FIFinderSync` class in ObjectiveC/Swift. How can I raise a JS event inside an `.appex` extension? – Marco Moschettini Aug 19 '17 at 14:53
  • You will need to use some form of interprocess communication. I'm not familiar with the Electron API, but you should be able to use sockets to handle IPC: https://nodejs.org/api/net.html#net_class_net_socket – dejuknow Aug 21 '17 at 17:58
  • btw, if you're planning to implement context menus/badges for Windows Explorer as well as Finder, check out our cross-platform project Liferay Nativity: https://github.com/liferay/liferay-nativity. Linux support is limited and I haven't worked on it much lately, but it'll give you an example of using ports for IPC. – dejuknow Aug 21 '17 at 18:07
  • @dejuknow your project sounds interesting. I think I will explore it a little bit. Can you provide an example on how to bridge your Liferay Nativity Finder Sync plugin to a node.js project? Thank you – Marco Moschettini Aug 24 '17 at 15:58
  • We don't have node.js examples, but Java and C# are available. They communicate w/ the Finder/Explorer/Nautilus plugins via sockets. Take a look at the source if you want to build a similar node.js example. – dejuknow Aug 24 '17 at 19:36
  • Thank you for the suggestion! I will give it a try! – Marco Moschettini Aug 24 '17 at 19:59
  • @dejuknow - copying the appex into Plugins folder in my Electron app does nothing for me - I'm missing something, but what? – Tom Andraszek Feb 23 '18 at 04:24
  • @dejuknow - PlugIns not Plugins, and the package.json must have "extraFiles": ["PlugIns/"] in the "mac" section. – Tom Andraszek Feb 23 '18 at 06:02
  • @TomAndraszek Do you see your Electron app in System Preferences -> Extensions -> Finder? Make sure it's checked. You should see a message in the console like "-[FinderSync init] launched from YourElectronApp/.../YourFinderSync.appex" – dejuknow Feb 23 '18 at 22:00

2 Answers2

5

Create PlugIns folder in your Electron root folder.

Copy the .appex file into PlugIns folder.

If you are using electron-builder, modify the package.json file - add: "extraFiles": ["PlugIns/"] in the "mac" section.

Build. The Contents of your app package will contain the PlugIns folder and your appex file inside, and the appex will get loaded into your app's process.

Tom Andraszek
  • 1,793
  • 1
  • 23
  • 30
  • You are right. I've managed to implement this months ago. Maybe I will post a full answer too on how I did it so far. – Marco Moschettini Feb 26 '18 at 11:29
  • 1
    Basically you're inputs are right. At run time the only way I found to make the extension communicate with the Electron app has been implementing an IPC over the loopback interface using Socket.io. Practically, I implemented the sync extension in Swift, built it in an appex file and followed the steps you have mentioned in your answer to package it in Electron. Now I'm controlling it's behavior via Socket.io. It may be a workaround but, for now, it is working quite good. If you have found better solutions I am all ears! :) – Marco Moschettini Feb 26 '18 at 11:36
  • @MarcoMoschettini do mind sharing how you did it so far? (: – Larry Mickie Jul 14 '21 at 01:48
  • @MarcoMoschettini any chance you can share the way you do it? – HKIT May 15 '23 at 12:14
0

How to embed a mac app extension in an Electron app?

I would compile it as an independent binary and include it in some dir to be executed from the electron app using child_process.execFile

You can use arguments when executing the binary with execFile, here is an example (using promise)

const util = require('util');
const execFile = util.promisify(require('child_process').execFile);
async function FinderSyncExtPlugin(ARGUMENTS) {
  const { stdout } = await execFile('YourBinary', ARGUMENTS);
  console.log(stdout);
}
FinderSyncExtPlugin(['argument1','argument2','...']);

You could then use the stdout to know the status/result of the requested operation.

EMX
  • 6,066
  • 1
  • 25
  • 32
  • 2
    It's not possible to compile the finder extension as an independent binary as it is automatically generated by Xcode alongisde the Swift/ObjC project using a different target. Your method would still work fine with a normal Command Line MacOS application but is not applicable to my specific situation... – Marco Moschettini Aug 19 '17 at 14:58