I was now able to successfully notarize our app and it still runs just fine.
Here is what I am doing:
Our App:
- we do not care for app store, so we do not use sandbox
- of course our nwjs Helper is renamed
- we do not use any ready-made node packages for building, bundling or other stuff. we have our own sets of bash and node scripts to fit our needs
- we distribute via pkg not dmg
Steps to successfully notarize our app:
1. build and bundle the nwjs app to an executable .app "file"
2. codesign:
a) adding flag for hardened runtime
b) adding entitlements needed by nwjs/chromium/node
c) apply to ALL binary files
basic codesign command we use for all files:
codesign --verbose --force --deep --strict --options runtime --timestamp --sign [IDENTITY] --entitlements neededToRun.entitlements [FILE]
our entiltements file contains the following entitlements:
- com.apple.security.automation.apple-events
- com.apple.security.cs.allow-dyld-environment-variables
- com.apple.security.cs.allow-jit
- com.apple.security.cs.allow-unsigned-executable-memory
- com.apple.security.cs.disable-executable-page-protection
- com.apple.security.cs.disable-library-validation
note: an .entitlement file ist just a plist, see:
we give all binaries the same .entitlements file, we do not use com.apple.security.inherit as it dir not work for us.
VERSION_DIR: e.g. /Contents/Version/73.0.3683.103/ or what ever the number is
These are the binary files we sign (in order of signing):
- VERSION_DIR/nwjs Framework.framework/Helpers/crashpad_handler
- VERSION_DIR/nwjs Framework.framework/libnode.dylib
- VERSION_DIR/nwjs Framework.framework/libffmpeg.dylib
- VERSION_DIR/nwjs Framework.framework/Versions/A/Libraries/libEGL.dylib
- VERSION_DIR/nwjs Framework.framework/Versions/A/Libraries/libswiftshader_libEGL.dylib
- VERSION_DIR/nwjs Framework.framework/Versions/A/Libraries/libGLESv2.dylib
- VERSION_DIR/nwjs Framework.framework/Versions/A/Libraries/libswiftshader_libGLESv2.dylib
- VERSION_DIR/nwjs Framework.framework/Versions/A/XPCServices/AlertNotificationService.xpc/Contents/MacOS/AlertNotificationService
- VERSION_DIR/nwjs Framework.framework/Versions/A/Helpers/crashpad_handler
- VERSION_DIR/nwjs Framework.framework/Versions/A/nwjs Framework
- VERSION_DIR/nwjs Helper.app (this is the renmaed helper however it is called)
-
nwjs.app (this is you app, however it is called)
Note that you also might need to do this for all binary node modules!
3. use pkgbuild and productbuild to create a macOS installer. This needs also to be signed with an Installer Certificate!
4. notarize:
a) zip the installer
b) send it to apples notarization service
c) poll every minuted for the status of notarization
- on reject we check the logs apple sends us
- on success we staple the installer
step 3 and 4 are pretty straight forward and apple
as for step 4:
according to apple you only need to notarize the most outer container. In our case the pkg -- but a dmg would also be possible. They scan the whole container for all its elements!
as for step 2:
do not think that --deep does a nested signing! it does not, or at least not for all subdirectories. You have to individually sign all the binaries, otherwise apple will reject your app!
Read these before you start implementing notarization: