You can make a difference in the Apple Support Community!

When you sign up with your Apple Account, you can provide valuable feedback to other community members by upvoting helpful replies and User Tips.

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

How to deploy an app from a DMG so that it does not need dragging to the Applications folder

Prior to Catalina our code-signed & notarized, downloadable (not from Apple store) macOS 64-bit app, distributed in a DMG with supporting folders of data, ran from Finder (by double-clicking) with no problems (all files extracted from the DMG and copied onto the file system). On Catalina and above, the app needs to be dragged to the Applications folder and copied back to the location on the file system it was extracted to in order to run properly, otherwise the app window opens but nothing is displayed and it fails to run further than a blank app window.


Without having been dragged to and copied back from the Applications folder, if the app is invoked from the command-line (not using open but typing the path to the executable in Contents/MacOS) it will run perfectly well to.


I have tried any number of entitlement combinations to try to make this work correctly on macOS 10.15+, all to no avail. It may be worth noting that, this is not a native app, but a cross-platform Python application bundled using PyInstaller (4.10), however, as it works pre 10.15, I'm not sure whether this is entirely relevant.


Has anyone come across a similar issue (native or not) and found a way to circumvent this behaviour, or is it an expected part of the security model post 10.15?

Posted on May 13, 2022 9:13 AM

Reply

Similar questions

9 replies

May 16, 2022 2:05 AM in response to etresoft

@etresoft, many thanks for your reply. I probably should have provided a little more information before I submitted this last Friday, but didn't want to cloud the picture incase it was recognised behaviour from this initial description.


It is definitely not app structure as I have built simple apps both from XCode & manually to follow the basic app Apple structure and they match that generated by PyInstaller. Furthermore it would seem to be something to do with behaviour related to the Quarantine (com.apple.quarantine) flag, as setting it using a tool like xatrred (to simulate download conditions) creates the same behaviour described in my original post, but for the simpler apps I just mentioned behaviour is normal.


For further background information:

  • The behaviour I described started on Catalina (but it's the same for Big Sur & Monterey) and has only surfaced as 64-bit versions of apps were built - previously we were upgrading from a 32-bit framework, which shall remain nameless, that the HTML5 standard saw the demise of ;)
  • The app is an educational app used in the same way by teachers regardless of platform & was historically distributed in a ZIP file (the supporting folders have data injected into them at download and the app saves data to a co-located folder for later upload to a secure site) - hence the reason it is currently distributed in DMG, rather than PKG.


So for 1) & 2) in your kind reply, I can clarify that this has already been done, there is nothing unique about the app structure and side-loading to a machine, other than that which the app was built on, shows no problems. Simulating the quarantine flag and/or downloading it in Safari introduces the issue. As far as 4) goes, PyInstaller creates a stand-alone static Python application that doesn't rely on anything on the system (e.g. under /usr/lib).


The console app does generate a heck of a lot of information about what the system is doing under the hood, (even when I run it for a short duration as the app fires up), that is hard to decipher and I did dig around in that, but couldn't see anything obvious (although that may be due to my own naivety).

May 13, 2022 5:43 PM in response to par-focal

I've seen many problems with these cross-platform app builders. I haven't heard of having to copy files back and forth like that. I'm not sure what that's about.


Anyway, the structure of an app isn't that complicated. Even if you are using some kind of script-runner tool. The changes needed to support that kind of operation are actually quite minor. But in most cases, when people have problems, the structure of their app is just wildly out of the ordinary. Yet because it worked on some old operating system, they often balk at actually building a recognizable app bundle. Catalina isn't even the current OS version. It is effectively 3 major versions old.


There are a number of things that can go wrong. Plus, I'm not sure what you mean about "supporting folders of data". That is not unusual, but distributing it in a DMG isn't right. This should probably be a PKG file instead. I recommend the following:

1) Copy the unsigned, unnotarized, and unquaranted app bundle to a factory-fresh VM. See if it works there. If not, you've got a lot of work ahead of you. Review errors in the Console tool when you try to launch the app.

2) Review the structure of said app. Compare it to any other app. Are you doing something unique? If you do things unlike anyone else, then you are literally on your own.

3) Repeat all of the above after attempting to notarize the app and downloading it with Safari.

4) Carefully review your use of dynamic libraries. I have seem some similar apps try to dynamically load system dylibs from /usr/lib. Those don't exist anymore.


Good luck!

May 16, 2022 9:48 AM in response to par-focal

par-focal wrote:

It is definitely not app structure as I have built simple apps both from XCode & manually to follow the basic app Apple structure and they match that generated by PyInstaller.

Sorry, but I have to mention it. I've seen many examples of apps that won't notarize that also just happen to be completely unique structures. I don't know for sure that the structure of the bundle has anything to do with it. It is just that someone who decides to do something unique for no reason other than to make their life more difficult has probably also made lots of other poor decisions. It's good that you haven't gone down that road.

Furthermore it would seem to be something to do with behaviour related to the Quarantine (com.apple.quarantine) flag, as setting it using a tool like xatrred• (to simulate download conditions) creates the same behaviour described in my original post, but for the simpler apps I just mentioned behaviour is normal.

The quarantine flag is what triggers the whole mechanism. I wouldn't recommend using any 3rd party hacks like that. Downloading from Safari is simple enough to do.

The behaviour I described started on Catalina (but it's the same for Big Sur & Monterey) and has only surfaced as 64-bit versions of apps were built - previously we were upgrading from a 32-bit framework, which shall remain nameless, that the HTML5 standard saw the demise of ;)

It is normal for major updates to break things that were done incorrectly. Sometimes even minor updates will do that. This doesn't mean that there is anything wrong with the update. Don't sit on your hands for a year or three waiting for a fix. No such fix will ever be forthcoming. This is your problem to solve. Unfortunately, if you were still building 32-bit code in 2019, you may have missed some developments during the previous 12 years.

• The app is an educational app used in the same way by teachers regardless of platform & was historically distributed in a ZIP file (the supporting folders have data injected into them at download and the app saves data to a co-located folder for later upload to a secure site) - hence the reason it is currently distributed in DMG, rather than PKG.

Are you saying the app is generated on-the-fly, when it is downloaded? Don't do that. Host the data on a server somewhere and have them download it on first run. You could make it more difficult for yourself and download during installation of the PKG file.

So for 1) & 2) in your kind reply, I can clarify that this has already been done, there is nothing unique about the app structure and side-loading to a machine, other than that which the app was built on, shows no problems. Simulating the quarantine flag and/or downloading it in Safari introduces the issue.

That still leaves 3) and 4).

PyInstaller creates a stand-alone static Python application that doesn't rely on anything on the system (e.g. under /usr/lib).

A significant portion of all the reported problems with notarization come from PyInstaller users. A significant portion of those problems are directly due to trying to do something directly with files in /usr/lib.


Here's the problem. When you use a tool like PyInstaller, you really aren't saving yourself any time, effort, or money. You could have developed a great native app that would work with no problems. Maybe you could port that app to iOS for 10 X the market. Or just target iOS right from the start and get a Mac version for free. But instead, you have to become an expert in PyInstaller and in macOS dynamic libraries just to get your app to run.

May 16, 2022 9:51 AM in response to par-focal

(For example, when replying to PyInstaller users who have problems with notarization, I often run into the 5000 character limit here in the forums. Even trying to give you the bare minimum of basic information on how do debug these problems usually requires multiple posts.)

The console app does generate a heck of a lot of information about what the system is doing under the hood, (even when I run it for a short duration as the app fires up), that is hard to decipher and I did dig around in that, but couldn't see anything obvious (although that may be due to my own naivety).

Normally I avoid mentioning it. I have seen numerous cases where the never-ending stream of log messages literally drives people insane. But you can set filters on your app to see errors that are specific to it. Sometimes the important messages will be system messages though. What you have to do is just be really quick about. Turn on streaming, then immediately try to launch your app. As soon as it fails, turn off streaming and review the logs. If you can do all of that in 10 seconds or so, then you should only have about 2000 log messages to review.


When I said "Carefully review your use of dynamic libraries", this is what I mean. Yes, it is very difficult. I wasn't exaggerating when I said you have to become an expert in use and abuse of dynamic libraries. This is almost always the source of the problem. There might be some quick-n-easy fix with entitlements, but you will have to identify the source of the problem first. In addition to reviewing the log files, look at the dynamic libraries themselves. Use "otool -L" on your app any any 3rd party dynamic libraries or processes loaded by your app. Then use "otool -L" on each of those. Maybe there is an invalid @rpath somewhere deep inside.


PS: Don't forget, WWDC is in 3 weeks. You'll have to do all of this over again with a beta version of macOS then. But if you haven't solved it by then, maybe consider signing up for a help session with an Apple engineer who could do all of the above for you in about 10 minutes.

May 17, 2022 11:00 AM in response to etresoft

Thanks @etresoft, your time and advice here is really appreciated :)


The app does natoarize and isn't being generated on the fly, it's statically generated, code-signed & notarized, then bundled into a DMG in which additional folders are injected at download with user specific configuration.


A little more background as to why PyInstaller is being used: The macOS app is just one of 90+ apps generated for 3 platforms from the same Python & Javascript code-base of 500, 000+ lines of code, Apple versions of the apps represent <5% of the users & it is not intended for smaller mobile devices, so a native version is not possible resource-wise right now, but the difficulties of getting it to work may make those responsible for user experience have to think hard about additional resource going forward or withdrawing macOS support :(

May 17, 2022 11:06 AM in response to etresoft

I now understand what you mean about /usr/lib dependencies, I see dependencies upon:


/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 164.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 54.0.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1770.255.0)
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1122.11.0)


So, I will dig a little further into those and see if they could be causing the problem :)

May 17, 2022 11:24 AM in response to par-focal

par-focal wrote:

The app does natoarize

OK. I guess I'm confused. You mentioned Catalina, entitlements, and PyInstaller, so I assumed this was a notarization problem.

isn't being generated on the fly, it's statically generated, code-signed & notarized, then bundled into a DMG in which additional folders are injected at download with user specific configuration.

Can you clarify, really specifically, what you mean by "additional folders are injected at download"? I still think this is a notarization problem for these reasons:

1) People who have notarization problems always claim that their apps are notarized. I've learned by this that they mean they ran the command-line notary tool and it didn't dump an error. That does not mean the app is notarized. The app's not notarized until it runs properly after download.

2) The thing that gets notarized is the outermost container. In the case of a DMG, you notarize the DMG, not the app. Same for an installer package. The installer package gets notarized. All of the executable code inside the DMG and/or installer packages must be properly signed, using a secure timestamp and hardened runtime, possibly with entitlements to poke holes in security in various places so that whatever crazy thing PyInstaller does will work.

3) A notarization failure may very well exhibit itself using in the manner that you describe. Most of notarization is designed for a stand-alone, native app that the user double-clicks to run. But if you are using some kind of cross-platform tool, what is being run may be some command-line tool that does something funky.


So yes, I still think this is a notarization problem. Plus, when you answered my 4-part question above, that definitively identified this as a notarization problem.

4) That brings me back to the "injection" of new files into the DMG. I still don't know what that means. I still think there are better ways to accomplish this. But you didn't say anything about notarizing the DMG afterwards, so I assume that is where your notarization is failing. You said this "injection" happens "at download". However, you must notarize before download. So I guess that ends that.


Apple versions of the apps represent <5% of the users

You might want to review cause and effect on this point. 😄

it is not intended for smaller mobile devices, so a native version is not possible resource-wise right now, but the difficulties of getting it to work may make those responsible for user experience have to think hard about additional resource going forward or withdrawing macOS support :(

No worries. I'm a developer myself, so your exit from, or avoidance of, a given market means more opportunity for other developers. 😄

May 17, 2022 11:27 AM in response to par-focal

par-focal wrote:

So, I will dig a little further into those and see if they could be causing the problem :)

No. Those are fine. This is only a problem with the Python side tries to manually open a dylib in /usr/lib and fails because no such file exists. Any app that is properly linked to system libraries will load those libraries from the system cache.


The problem sounds like your injection at download, resulting in an un-notarized DMG.

How to deploy an app from a DMG so that it does not need dragging to the Applications folder

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.