Prepare plugins for distribution on macOS (notarization, code signing etc)

Hi,
I’m currently trying to build an installer for my plugins (AU, VST3 and Standalone) in order to send them to my beta tester and then sell them. Since I’m on macOS I need to sign the binaries, otherwise they won’t work on other Macs. I’m using JUCE with Cmake (no Xcode, no Projucer), and I’m on the latest macOS release (12.6).
I’m following this guide: HOWTO macOS notarization (plugins, app, pkg installers) - DSP and Plug-in Development Forum - KVR Audio , along with the one in the JUCE website: JUCE: Tutorial: Package your app or plugin for distribution .

I want to make an installer, and in the guide it says that I only need to sign it in order to have all the plugins signed:

Notarization is indeed needed for plugins, but if you are distributing through a PKG or DMG (which contains a PKG), you can just notarize the PKG or the DMG, and everything inside will be notarized.

So basically I’m following this part of the guide:

I’ve created an Apple Developer Account, and I’ve downloaded a certificate (“Developer ID Installer: myname mysurname”). I downloaded from here: Apple PKI - Apple some other certificates in order to have mine working, and now in the keychain app I see my certificate like this:

(it’s Italian, it says that my certificate is valid, with a green tick).

I need a signed installer as stated in the guide:

Submit the signed PKG to Apple servers:

So I added my Certificate to White Packages:

As you can see it says that it is VALID. If I try to build the installer I get this error:

What I’m supposed to do? My certificate is valid everywhere, even White Packages says that, how can I fix this problem? All this notarization and certificate madness is driving me insane. Thank you!

Notarization and signing are two different things.

If I recall correctly:

  • the plugin must be signed with a “Developer ID Application”
  • the installer must be signed with a “Developer ID Installer”
  • Whatever you intend the user to download (could be a .pkg, a .dmg or a .zip) must be notarized

But I’m not sure if that’s the problem here, as the error message sounds like it just doesn’t accept your installer certificate? I’ve never used Whitebox, so never encountered that particular message. Did you sign the binaries with an Application certificate?

1 Like

This is correct (as are the following bullet points).

Another potential issue (that I’m not sure how you fix with Packages1) is that you might need to “force” the signing of the plugin with the Developer ID Application Certificate, as it may have been “ad hoc” signed when built.

Are your certificates added to the “login” Key Chain? If not this might be the cause of the error in Packages.

1 : my advice is to forget Packages, it’s just a needless dependency, instead spend a few hours looking at the Surge VST repo to figure out how to make your installer manually with a script.

Some more info:

  • I’ve downloaded both a Developer ID Application and a Developer ID Installer certificate, both are in my Keychain App and both are valid
  • in my CMakeLists file I’ve added (with my real team ID of course):
if (APPLE)
    set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
    set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application")
    set(CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "**************")
endif()

Do I need to do something else to sign my plugins?

@asimilon regarding the “login” Key Chain, my certificates are in that keychain, I can see them in the KayChain app.

Btw, thank you both!

with the “codesign” command line utility I’ve found that I’m not signing my code, so the cmake commands that I’ve posted above are not correct. Anyone knows what is the correct way to sign a plugin compiled with CMake?

There should be an official JUCE tutorial on these topics!!

You can add the codesign command as an additional step to the plugin target(s). Roughly like this:

get_target_property( bundle_path MyPlugin_AU JUCE_PLUGIN_ARTEFACT_FILE )
add_custom_command( TARGET MyPlugin_AU POST_BUILD
    COMMENT "Signing MyPlugin_AU"
    COMMAND codesign -f -s ${DEVELOPER_ID_APPLICATION} --timestamp ${bundle_path}
    )
1 Like

Ok, in the meantime I was trying to do something like that, thank you. I have a couple of questions:

  • what is bundle_path? in the second step is treated like a variable but not in the first one.

  • “MyPlugin_AU” is the name of the plugin followed by “_AU” and automatically it signs the .component file? So if I would like to do the same for the VST3 I should use “MyPlugin_VST3”?

  • I’ve noticed that I need to add the entitlements file generated in the JuceLibraryCode folder, otherwise the standalone app does not asks for the microphone permission and therefore it does not work (no audio input)

Btw thank you again!

The first line gets the path to the .component file from the target and saves it into the bundle_path variable. CMake can be confusing at times. :wink:

When you do a juce_add_plugin( MyPlugin … ) it builds a couple of sub-targets according to the formats you’ve enabled. So it’s similar for _VST3, _AAX etc.

You can also do something like this to loop through all the sub-targets:

get_target_property(active_targets MyPlugin JUCE_ACTIVE_PLUGIN_TARGETS)
foreach( sub_target IN LISTS active_targets )
    get_target_property( bundle_path ${sub_target} JUCE_PLUGIN_ARTEFACT_FILE )
    add_custom_command( TARGET ${sub_target} POST_BUILD
        COMMENT "Signing ${sub_target}"
        COMMAND codesign -f -s ${DEVELOPER_ID_APPLICATION} --timestamp ${bundle_path}
        )
endforeach()

Unfortunately the Standalone target used to not have the JUCE_PLUGIN_ARTEFACT_FILE property, but I think that’s fixed now, at least in the develop branch.

1 Like

Thank you man! This is extremely helpful!

I highly suggest to use xcrun notarytool instead of xcrun altool for notarization.

4 Likes

Update:

The correct command (for example for AU) is this one:

    get_target_property( bundle_path ${PLUGIN_NAME}_AU JUCE_PLUGIN_ARTEFACT_FILE )
    add_custom_command( TARGET ${PLUGIN_NAME}_AU POST_BUILD VERBATIM COMMAND codesign -f "-s Developer ID Application: Alessandro Proverbio (**********)" ${bundle_path} )

By doing this the codesign command is correctly recognized by cmake, but then ends with an error, that says “no identity found”. This is very strange, because if I run the same command from a terminal window, it works perfectly. How is that possible? The same command run alone in the shell works, while run inside cmake it doesn’t.

I remember some similar problem. If I remember correctly I could fix it by escaping the braces “\( … \)”.

You put the -s inside the quotes, that last line should look like:

    add_custom_command(TARGET ${PLUGIN_NAME}_AU POST_BUILD VERBATIM COMMAND codesign -f -s "Developer ID Application: Alessandro Proverbio (**********)" ${bundle_path} )

Just to re-emphasize, altool is deprecated and will stop working by fall next year. Luckily notarytool is a much nicer experience. I blogged about code signing/notarization recently, maybe it can be helpful.

1 Like

You have to put the -s inside the quotes, otherwise it does not work, the command is not recognized. There are different examples online that shows the same (very strange) syntax.

Btw, I ended up writing my own script that do everything, from compiling to signing to building and notarizing the installer (with notary tool which is way better than altool)

That’s quite strange! Glad you got it working. Going the CMake route looked pretty rough…

1 Like