Go-flutter: MacOS Code Signing

Created on 2 Jul 2019  路  15Comments  路  Source: go-flutter-desktop/go-flutter

Hello,

I am trying to get my app code signed, but Apple now requires all apps to be notarized. I am getting the following error back from Apple:

The executable does not have the hardened runtime enabled.

This is referring to the main executable created by hover build. I have tried adding the hardening to the Xcode project, but Im assuming hover build does not use the xcode project to build it.. How do I add the hardened runtime capability when using hover?

MacOS hover

Most helpful comment

I have been able to successfully sign, notarize and distribute the app with a DMG installer. My findings:

Step 1: build with either hover or manual

hover build -t "lib/main.dart" I dont use the main_desktop.dart

Step 2: create .app package:

/MyApp.app
    /Contents
         Info.plist
         /MacOS
         /Resources

Step 3: move the build output to the MacOS folder in the app package

Move the following files to the .app directory under the MacOS folder

/assets
/flutter_assets
FlutterEmbedder.framework
icudtl.dat
myapp_binary

Step 4: modify Info.plist, add icons and/or installer background to /Resources

It is very important to have the following fields in the Info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleExecutable</key>
        <string>*YOUR EXECUTABLE (myapp_binary)*</string>
        <key>CFBundleIconFile</key>
        <string>icon.icns</string>
        <key>CFBundleIdentifier</key>
        <string>*YOUR BUNDLE*</string>
        <key>NSHighResolutionCapable</key>
        <true/>
        <key>LSUIElement</key>
        <true/>
</dict>
</plist>

Step 5: Sign the app package

First sign the app bundle:
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep MyApp.app

Sign the executable with the runtime options (This is now required for MacOS 10.14+)
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep --options runtime MyApp.app/Contents/MacOS/MyAppBinary

Sign the FlutterEmbedder Framework separately
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep MyApp.app/Contents/MacOS/FlutterEmbedder.framework/Versions/A/

Step 6: Notarize the package with Apple

You will need an application specific password for the following steps

https://support.apple.com/en-ca/HT204397

How to generate an app-specific password
Sign in to your Apple ID account page.
In the Security section, click Generate Password below App-Specific Passwords.
Follow the steps on your screen.
After you generate your app-specific password, enter or paste it into the password field of the app as you would normally.

Compress the .app directory into zip, then:

xcrun altool --notarize-app --primary-bundle-id "YOUR BUNDLE ID" --username "YOUR DEVELOPER EMAIL" --password "YOUR APP SPECIFIC PASSWORD" --file MyApp.zip

Once the zip is uploaded, you will get a REQUEST-ID back, use it to check the status

Check status: xcrun altool --notarization-info <REQUEST-ID> -u "YOUR DEVELOPER EMAIL" -p "YOUR APP SPECIFIC PASSWORD"

If there is an error, you will see it in the output of the check status ^ command. There will be a link to a log file which will contain the errors to fix.

If approved, staple the app: xcrun stapler staple MyApp.app/

Step 7: create DMG

I used the create-dmg tool: brew install create-dmg

Then run with command:

create-dmg --volname "MyApp Installer" \
--volicon MyApp.app/Contents/Resources/icon.icns \
--background MyApp.app/Contents/Resources/installer-bg.png \
--window-size 800 400 \
--icon-size 100 \
--icon "MyApp.app" 200 200 \
--app-drop-link 600 185 \
"MyApp-1.0.dmg" "MyApp.app/"

All Done

Do not sign the DMG, the MacOS gatekeeper will detect the signed app in the image. If you sign the dmg, you will need to notarize it too, and there are many bug reports with notarizing image files.

All 15 comments

The documentation from Apple:

Hardened runtime is available in the Capabilities pane of Xcode 10 or later, but you can enable the feature manually using earlier versions of Xcode, as long as you鈥檙e on macOS 10.13.6 or later. To do this, add the following flag to the OTHER_CODE_SIGN_FLAGS build setting:

--options=runtime

Is there a way to provide this build settings when creating the cmd binary?

I think I found how to do it, the codesign utility lets you add the option:

codesign -s "<COMMON_NAME>" -fv --options runtime App.app/Contents/MacOS/<EXECUTABLE>

I'm sorry, but I cannot help you on this one. Please report your finding here, as it might help others.

This sounds like something we may want to do for the release build of an app? Or should it also be done for debug builds?
Related issue #156

I have very little experience with MacOS, help is welcome and much appreciated @alexelisenko

I have been able to successfully sign, notarize and distribute the app with a DMG installer. My findings:

Step 1: build with either hover or manual

hover build -t "lib/main.dart" I dont use the main_desktop.dart

Step 2: create .app package:

/MyApp.app
    /Contents
         Info.plist
         /MacOS
         /Resources

Step 3: move the build output to the MacOS folder in the app package

Move the following files to the .app directory under the MacOS folder

/assets
/flutter_assets
FlutterEmbedder.framework
icudtl.dat
myapp_binary

Step 4: modify Info.plist, add icons and/or installer background to /Resources

It is very important to have the following fields in the Info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleExecutable</key>
        <string>*YOUR EXECUTABLE (myapp_binary)*</string>
        <key>CFBundleIconFile</key>
        <string>icon.icns</string>
        <key>CFBundleIdentifier</key>
        <string>*YOUR BUNDLE*</string>
        <key>NSHighResolutionCapable</key>
        <true/>
        <key>LSUIElement</key>
        <true/>
</dict>
</plist>

Step 5: Sign the app package

First sign the app bundle:
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep MyApp.app

Sign the executable with the runtime options (This is now required for MacOS 10.14+)
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep --options runtime MyApp.app/Contents/MacOS/MyAppBinary

Sign the FlutterEmbedder Framework separately
codesign -s "YOUR DEVELOPER ID COMMON NAME" -fv --deep MyApp.app/Contents/MacOS/FlutterEmbedder.framework/Versions/A/

Step 6: Notarize the package with Apple

You will need an application specific password for the following steps

https://support.apple.com/en-ca/HT204397

How to generate an app-specific password
Sign in to your Apple ID account page.
In the Security section, click Generate Password below App-Specific Passwords.
Follow the steps on your screen.
After you generate your app-specific password, enter or paste it into the password field of the app as you would normally.

Compress the .app directory into zip, then:

xcrun altool --notarize-app --primary-bundle-id "YOUR BUNDLE ID" --username "YOUR DEVELOPER EMAIL" --password "YOUR APP SPECIFIC PASSWORD" --file MyApp.zip

Once the zip is uploaded, you will get a REQUEST-ID back, use it to check the status

Check status: xcrun altool --notarization-info <REQUEST-ID> -u "YOUR DEVELOPER EMAIL" -p "YOUR APP SPECIFIC PASSWORD"

If there is an error, you will see it in the output of the check status ^ command. There will be a link to a log file which will contain the errors to fix.

If approved, staple the app: xcrun stapler staple MyApp.app/

Step 7: create DMG

I used the create-dmg tool: brew install create-dmg

Then run with command:

create-dmg --volname "MyApp Installer" \
--volicon MyApp.app/Contents/Resources/icon.icns \
--background MyApp.app/Contents/Resources/installer-bg.png \
--window-size 800 400 \
--icon-size 100 \
--icon "MyApp.app" 200 200 \
--app-drop-link 600 185 \
"MyApp-1.0.dmg" "MyApp.app/"

All Done

Do not sign the DMG, the MacOS gatekeeper will detect the signed app in the image. If you sign the dmg, you will need to notarize it too, and there are many bug reports with notarizing image files.

This sounds like something we may want to do for the release build of an app? Or should it also be done for debug builds?

It's is more related to packaging (hover dist maybe?)
related to #99

Indeed this will be useful for packaging. Thanks @alexelisenko !

@Drakirus @GeertJohan I have found that using the --options runtime, which is required by Apple for the app to be notarized, caused a Dart crash. I have files bug reports.

Also, is there any updates on how MacOS 10.15+ will be handled? It is my understanding that OpenGL is no longer supported.

Hopefully you can get the --options runtime bug to be fixed :crossed_fingers:.
About OpenGL not been supported on MacOS, we did talk about it in #40.
tl;dr: It might be a non-issue if Metal gets ported into go-gl/glfw.

@Drakirus I have found the issue with enabling hardened runtime.

You need to also add entitlements for allowing JIT, since AOT with Dart in the flutterembedder is not supported yet, which is why it crashes.

I will post the exact entitlement file and codesign command that is working for me.

Moved to #207.

@alexelisenko what is related to code signing can be reported in this issue.

@Drakirus I have found the issue with enabling hardened runtime.

You need to also add entitlements for allowing JIT, since AOT with Dart in the flutterembedder is not supported yet, which is why it crashes.

I will post the exact entitlement file and codesign command that is working for me.

Hi, have you figured out the entitlement file that is working for you? I met the same issue:(

@wud147 Yes, You need to codesign with the entitlement file:

codesign -s "Developer ID Application: <APPLE DEVELOPER IDENTITY>" -fv --entitlements entitlements.xml --deep --options runtime MyAPP.app

The entitlement file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>com.apple.security.cs.allow-jit</key>
        <true/>
        <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
        <true/>
        <key>com.apple.security.cs.disable-library-validation</key>
        <true/>
        <key>com.apple.security.cs.disable-executable-page-protection</key>
        <true/>
    </dict>
</plist>

Once codesigned and notarized, did you notice any issue launching the app?
I have a go-glfw app that refuses to launch the first time after clicking "Open" in the Gatekeeper dialog.
I'd like to know if this also happen with go-flutter.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  路  6Comments

pchampio picture pchampio  路  3Comments

ohsory1324 picture ohsory1324  路  4Comments

MathiasDeWeerdt picture MathiasDeWeerdt  路  4Comments

pchampio picture pchampio  路  6Comments