Unreal Engine - Codesigning and Distribution

Hi everyone! I have what I think is going to be a problem with a very simple solution, but I've reached the limits of my knowledge with this sort of thing. I'm an exhibit/experiential designer trying to build interactive 3D environments with Unreal Engine. Besides being more technically literate than most designers, I don't have very much development knowledge at all.

I've packaged my .app through UE and it's running great. The part that I can't seem to wrap my head around is code-signing and notarizing. I believe I've gone through the process correctly but I still get the Gatekeeper dialog box rejecting my app as from an "unidentified developer" when I run it on a different Mac or download it onto my development Mac and try to run it.

I'm using a "Developer ID Application" certificate installed to Keychain, and ran codesign with that certificate as shown below on every single binary and .dylib file in the package:

Code Block
codesign --deep -f -v -s "Developer ID Application: My Name (IDCODE)" --entitlements "/entitlements.xml" --options runtime --all-architectures --timestamp "each-individual-file"

I have then compressed the app into a DMG image and uploaded it for notarization like so:

Code Block
xcrun altool --notarize-app -primary-bundle-id "com.thebundleID" --file "thearchive.dmg" --username "myappleid" --password "password"

After many attempts I did eventually get this to return with a success. I then ran
Code Block
xcrun stapler staple "thearchive.dmg"

as well as tried to extract the app from the dmg and ran
Code Block
xcrun stapler staple "theapp.app"

and despite
Code Block
spctl -vvv --asses --type exec "theapp.app"

coming up "accepted" with a "Notarized Developer ID" matching my own, when I transfer the app to another computer it won't open easily, with the same "unidentified developer" message as if I hadn't signed the code at all.

Has anyone here gone through this process and found a way to make it work? Have I missed something? I'm happy to share a download link for you to try launching as well.

Thanks!
Answered by DTS Engineer in 616305022

Besides that I'm not really sure what to make of this log, that file location in /Users/build

Yeah, that’s not good. It suggests that somewhere in your product there’s an rpath entry that points to /Users/build, probably left over from the build environment that originally built this code.

I recommend that you:
  1. Find all the code in your product:

  2. Check the imported libraries to make sure they make sense.

  3. Check the rpath declarations to make sure they make sense.

  4. Fix anything that you’s obviously broken.

  5. If that brokenness is coming from a third-party vendor, report the problem to that vendor.

I’ll describe each step in turn [1].



To quickly find all the code in your product:

Code Block
% find /path/to/you.app -type f -print 0 | xargs -0 file | grep "Mach-O"




To list the libraries imported by the code:

Code Block
% otool -L /path/to/your/code




To list the rpath entries for the code:

Code Block
% otool -l /path/to/your/code | grep -B 1 -A 2 LC_RPATH




To fix things, use install_name_tool. See its man page for details.

IMPORTANT Changing code in this way will break the seal on its code signature, so if you make changes you will have to re-sign that code and anything that depends on that code.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

[1] It’s a sad indictment of my life that I can list these off by heart )-:
First up, don’t use --deep. See --deep Considered Harmful for an explanation as to why. Rather, you should sign each code item separately, from the inside out. See Signing a Mac Product For Distribution.

Second, your app is passing the notarisation step but, alas, that does not guarantee that you’ll pass Gatekeeper. Gatekeeper errors can be quite tricky to track down. I’ve posted some hints on this thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thanks for those suggestions, eskimo. I went through and re-signed everything in the package without the --deep option, but I'm getting the same results as before. I did find a line in the console about xprotect when I tried running the app:

Code Block
File /Applications/SMC Museum Gallery.app/Contents/MacOS/../UE4/Engine/Binaries/ThirdParty/PhysX3/Mac/libPhysX3.dylib failed on rPathCmd /Users/build/Build/++UE4/Sync/Engine/Binaries/ThirdParty/PhysX3/Mac/libPhysX3Common.dylib


libPhysX3.dylib and libPhysX3Common.dylib are both in the package and signed. Besides that I'm not really sure what to make of this log, that file location in /Users/build... doesn't exist as far as I can tell. Do you have any other suggestions, or some insight on how I can interpret that? Absolutely everything seems to be working until I try to launch this app.
Accepted Answer

Besides that I'm not really sure what to make of this log, that file location in /Users/build

Yeah, that’s not good. It suggests that somewhere in your product there’s an rpath entry that points to /Users/build, probably left over from the build environment that originally built this code.

I recommend that you:
  1. Find all the code in your product:

  2. Check the imported libraries to make sure they make sense.

  3. Check the rpath declarations to make sure they make sense.

  4. Fix anything that you’s obviously broken.

  5. If that brokenness is coming from a third-party vendor, report the problem to that vendor.

I’ll describe each step in turn [1].



To quickly find all the code in your product:

Code Block
% find /path/to/you.app -type f -print 0 | xargs -0 file | grep "Mach-O"




To list the libraries imported by the code:

Code Block
% otool -L /path/to/your/code




To list the rpath entries for the code:

Code Block
% otool -l /path/to/your/code | grep -B 1 -A 2 LC_RPATH




To fix things, use install_name_tool. See its man page for details.

IMPORTANT Changing code in this way will break the seal on its code signature, so if you make changes you will have to re-sign that code and anything that depends on that code.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

[1] It’s a sad indictment of my life that I can list these off by heart )-:
That was it!

All of the .dylib libraries (third-party plugins to the engine) had an rpath to that /Users/build folder that didn't exist. I changed them to their containing directory (.) since they were referencing each other and that seems to have fixed it all - app opens right up even on a different Mac.

Thanks so much for your help!
I am having exactly the same issue as smcaruso. And I followed your instructions eskimo. But I am still having the issue where the app runs perfectly before codesigning it, but breaks after codesigning it. (The app icon shows up in the Dock for 1-2 seconds and then goes away). Below are all the steps I took during the whole process:
  1. Checked all the libraries imported by the code, here is the output (tried doing pastebin but was not allowed to)

Don't see any issues here, please let me know if you see any
Code Block
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 902.1.0)
@rpath/libPhysX3.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libPhysX3Cooking.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libPhysX3Common.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libPxFoundation.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libPxPvdSDK.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libAPEX_Clothing.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libAPEX_Legacy.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libApexFramework.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libNvCloth.dylib (compatibility version 0.0.0, current version 0.0.0, weak)
@rpath/libopenvr_api.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
@rpath/libogg.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
@rpath/libvorbis.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 23.0.0)
/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 162.0.0)
/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 59306.140.5)
/System/Library/Frameworks/AVFoundation.framework/Versions/A/AVFoundation (compatibility version 1.0.0, current version 2.0.0)
/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo (compatibility version 1.2.0, current version 1.5.0)
/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox (compatibility version 1.0.0, current version 1000.0.0)
/System/Library/Frameworks/MediaToolbox.framework/Versions/A/MediaToolbox (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.11.0)
/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 212.8.0, weak)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1281.100.1)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1894.60.100)
/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork (compatibility version 1.0.0, current version 0.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1677.104.0)
/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1355.22.0)
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1069.24.0)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1677.104.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)


2. Checked rpath entries: (Here is the output)

Code Block
Load command 48
cmd LC_RPATH
cmdsize 32
path @loader_path/ (offset 12)
--
--
Load command 49
cmd LC_RPATH
cmdsize 32
path @executable_path/ (offset 12)
--
--
Load command 50
cmd LC_RPATH
cmdsize 72
path @loader_path/../UE4/Engine/Binaries/ThirdParty/PhysX3/Mac (offset 12)
--
--
Load command 51
cmd LC_RPATH
cmdsize 88
path @loader_path/../UE4/Engine/Binaries/ThirdParty/OpenVR/OpenVRv1_5_17/osx32 (offset 12)
--
--
Load command 52
cmd LC_RPATH
cmdsize 72
path @loader_path/../UE4/Engine/Binaries/ThirdParty/Ogg/Mac (offset 12)
--
--
Load command 53
cmd LC_RPATH
cmdsize 72
path @loader_path/../UE4/Engine/Binaries/ThirdParty/Vorbis/Mac (offset 12)


3. I tried 2 different things after this and both of them did not work:

(i)Added library paths relative to @executablepath, so there are rpaths with @executablepath for all the dynamic libraries
in addition to them having rpaths with @loaderpath.
e.g. it will have both @loader
path/../UE4/Engine/Binaries/ThirdParty/Ogg/Mac and @executablepath/../UE4/Engine/Binaries/ThirdParty/Ogg/Mac when we will list the rpaths
Same issue occurred as mentioned before after I did the codesigning.

(ii)Replaced @loader
path rpaths related to dynamic libraries with @executable_path rpaths. Same issue occured as
mentioned before after I did the codesigning.

So, I am assuming I am doing something wrong related to the rpaths.

4. Also posting all the codesigning commands I am using, maybe there is something wrong with them.
Code Block
codesign -f -v -s "Developer ID Application: CompanyName (Company ID)" --entitlements entitlements.plist --options=runtime --timestamp Path/to/App.app/Contents/MacOS/AppName
find Path/to/App.app/Contents/ | grep .dylib | xargs codesign -f -v -s "Developer ID Application: CompanyName (Company ID)" --entitlements entitlements.plist --options=runtime --timestamp
codesign -f -v -s "Developer ID Application: CompanyName (Company ID)" --entitlements entitlements.plist --options=runtime --timestamp Path/to/App.app/

Slightly off topic, but this thread helped me get my application signed and notarized.

There is an issue when codesigning x86_64 Unreal5 applications on Apple Silicon. (Monterey 12.5.1). Signing the dylibs works, but signing the .app causes it to crash on launch. Same signed (and notarized) app runs fine on Intel.

The solution is to enable the experimental Universal build in Unreal settings. The unreal dylibs are universal to begin with, and the universal build signed and ran without issue.

Unreal Engine - Codesigning and Distribution
 
 
Q