{ "version": "https://jsonfeed.org/version/1.1", "user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format. To add this feed to your reader, copy the following URL -- https://www.noodlesoft.com/blog/feed/json -- and add it your reader.", "home_page_url": "https://www.noodlesoft.com/blog", "feed_url": "https://www.noodlesoft.com/blog/feed/json", "language": "en-US", "title": "Noodlings", "description": "On Mac OS X programming", "items": [ { "id": "https://www.noodlesoft.com/blog/?p=588", "url": "https://www.noodlesoft.com/blog/2022/10/20/the-bundle-blame-game/", "title": "The Bundle Blame Game", "content_html": "\n
macOS Catalina introduced extra privacy protections where the user can control what apps can or cannot do. Key to this is providing the user with a correct identification of the app in question.
\n\n\n\nFor many apps, this is straightforward. If the \u201cFoo\u201d executable, which is located in \u2026Foo.app/Contents/MacOS
, does something that requires permission, the system knows to present Foo.app as the responsible bundle. For many apps, though, it\u2019s slightly less straightforward. There may be multiple executables in the app bundle. Nonetheless, it shouldn\u2019t be much of a problem figuring out the responsible app bundle but for some reason, a consistent solution has eluded Apple.
One of the main permissions that Hazel may require is Full Disk Access. If you go to that section in System Preferences/Settings, you\u2019ll see a list of apps. You think adding and enabling your app there is all that is needed; that it should handle permissions for that app and all its subsidiary executables in its bundle. Here\u2019s how it normally looks for Hazel.
\n\n\n\n\n\n\n\nBut sometimes things go awry. All of sudden, the system requires separate permissions for the other executables in your bundle. Users will find the app not working properly and they won\u2019t think to look at the permissions again as they thought they already given the proper permissions. Another trip to the privacy settings may show it listing the helper executables there.
\n\n\n\n\n\n\n\nNow, what the hell is that godforsaken app name? Well, it\u2019s the team id followed by the bundle id. Unfortunately, Apple requires the crazy naming scheme for apps that are login items bundled in the main app. Is this something the user really needs to be exposed to? Minimally, Apple should observe the display name specified by the bundle but in the ultimately, this should not appear there at all.
\n\n\n\nThe user should not have to understand the different running components internal to an app. This is a level of \u201ctransparency\u201d that muddles the issue and adds nothing of value. Does the user really need to know that \u201cFoo Helper\u201d exists and want to really control that separately from the main app? I know for a fact that the vast majority of Hazel users have no idea how the different executables in Hazel work and interact with each other. I would not expet them to be able to judge whether it\u2019s a good idea to give permissions to one, but not the other.
\n\n\n\nAt the other end of the spectrum, other parts of the system sometimes fail to list an app at all. For instance, Hazel sends notifications via a commandline program in one of the standard locations within the bundle. With Monterey, while Hazel was properly being recognized as the responsible app in the Notification settings, it would be absent in the list of app you choose for the Focus feature. This was remedied in a Monterey point release with Hazel properly listed in both places there.
\n\n\n\n\n\n\n\n\n\n\n\nUnfortunately, Ventura broke it again and now it\u2019s absent from both locations .
\n\n\n\n\n\n\n\nThis all seems to indicate that each team working on these different bits are re-inventing the same wheel over and over and doing it incorrectly in different ways. You\u2019d think it would be in their best interest of have someone write the canonical algorithm for this and use it across all these subsystems.
\n\n\n\nUnfortunately, for me, this has resulted in various DTS incidents and bug reports in recent years. As of this writing, it\u2019s still a problem in Ventura (last checked on the release candidate). Apple, please get this sorted. FB11462910 (which also mentions several other related FBs) for those working at Fruit Company.
There is an unrelated major issue which I am hoping has been worked around in the current Hazel beta. If you are interested in testing, please see the forum article here (forum login required).
\n\n\n\nFor the moment, if Hazel is an important part of your work, I suggest holding off on upgrading to Ventura. I’ll keep you posted on the status of these bugs via Twitter.
\n ", "content_text": "macOS Catalina introduced extra privacy protections where the user can control what apps can or cannot do. Key to this is providing the user with a correct identification of the app in question.\n\n\n\nFor many apps, this is straightforward. If the \u201cFoo\u201d executable, which is located in \u2026Foo.app/Contents/MacOS, does something that requires permission, the system knows to present Foo.app as the responsible bundle. For many apps, though, it\u2019s slightly less straightforward. There may be multiple executables in the app bundle. Nonetheless, it shouldn\u2019t be much of a problem figuring out the responsible app bundle but for some reason, a consistent solution has eluded Apple.\n\n\n\nOne of the main permissions that Hazel may require is Full Disk Access. If you go to that section in System Preferences/Settings, you\u2019ll see a list of apps. You think adding and enabling your app there is all that is needed; that it should handle permissions for that app and all its subsidiary executables in its bundle. Here\u2019s how it normally looks for Hazel.\n\n\n\n\n\n\n\nBut sometimes things go awry. All of sudden, the system requires separate permissions for the other executables in your bundle. Users will find the app not working properly and they won\u2019t think to look at the permissions again as they thought they already given the proper permissions. Another trip to the privacy settings may show it listing the helper executables there.\n\n\n\n\n\n\n\nNow, what the hell is that godforsaken app name? Well, it\u2019s the team id followed by the bundle id. Unfortunately, Apple requires the crazy naming scheme for apps that are login items bundled in the main app. Is this something the user really needs to be exposed to? Minimally, Apple should observe the display name specified by the bundle but in the ultimately, this should not appear there at all.\n\n\n\nThe user should not have to understand the different running components internal to an app. This is a level of \u201ctransparency\u201d that muddles the issue and adds nothing of value. Does the user really need to know that \u201cFoo Helper\u201d exists and want to really control that separately from the main app? I know for a fact that the vast majority of Hazel users have no idea how the different executables in Hazel work and interact with each other. I would not expet them to be able to judge whether it\u2019s a good idea to give permissions to one, but not the other.\n\n\n\nAt the other end of the spectrum, other parts of the system sometimes fail to list an app at all. For instance, Hazel sends notifications via a commandline program in one of the standard locations within the bundle. With Monterey, while Hazel was properly being recognized as the responsible app in the Notification settings, it would be absent in the list of app you choose for the Focus feature. This was remedied in a Monterey point release with Hazel properly listed in both places there.\n\n\n\n\n\n\n\n\n\n\n\nUnfortunately, Ventura broke it again and now it\u2019s absent from both locations .\n\n\n\n\n\n\n\nThis all seems to indicate that each team working on these different bits are re-inventing the same wheel over and over and doing it incorrectly in different ways. You\u2019d think it would be in their best interest of have someone write the canonical algorithm for this and use it across all these subsystems.\n\n\n\nUnfortunately, for me, this has resulted in various DTS incidents and bug reports in recent years. As of this writing, it\u2019s still a problem in Ventura (last checked on the release candidate). Apple, please get this sorted. FB11462910 (which also mentions several other related FBs) for those working at Fruit Company.\n\n\n\nThere is an unrelated major issue which I am hoping has been worked around in the current Hazel beta. If you are interested in testing, please see the forum article here (forum login required).\n\n\n\nFor the moment, if Hazel is an important part of your work, I suggest holding off on upgrading to Ventura. I’ll keep you posted on the status of these bugs via Twitter.", "date_published": "2022-10-20T12:28:33-04:00", "date_modified": "2022-10-20T12:28:33-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } }, { "id": "https://www.noodlesoft.com/blog/?p=581", "url": "https://www.noodlesoft.com/blog/2022/09/06/hazels-15th-16th-anniversary/", "title": "Hazel\u2019s 15th 16th Anniversary", "content_html": "\nIt\u2019s been 16 years ago today since Hazel\u2019s first release. Why celebrate the 16th anniversary? Because I thought it was actually 15 years but got the dates wrong. So, to mark the 16th anniversary (or a belated 15th, if you prefer), Hazel is 30% off. That applies to all license types (single, family, and upgrade). Just go to the store. Sale ends at 3am EDT.
\n\n\n\nChances are if you are reading this, then you already own a copy so share the news with friends and family. Just don\u2019t tell Zach in Accounting. He knows what he did.
\n\n\n\nWhile odd bits have changed since the 10th anniversary, things remain mostly the same. After all these years, still not in the App Store. No plans to shift to a subscription model. I’ve resisted many of the “innovations” in software sales and distribution in recent years. I could probably write another post why but in short, I haven’t found any need to change something that works.
\n\n\n\nCan’t say whether I’ll still be here doing this for Hazel’s 20th anniversary but I hope you’ll forgive me if I forget again and end up being a year or two late.
\n ", "content_text": "It\u2019s been 16 years ago today since Hazel\u2019s first release. Why celebrate the 16th anniversary? Because I thought it was actually 15 years but got the dates wrong. So, to mark the 16th anniversary (or a belated 15th, if you prefer), Hazel is 30% off. That applies to all license types (single, family, and upgrade). Just go to the store. Sale ends at 3am EDT.\n\n\n\nChances are if you are reading this, then you already own a copy so share the news with friends and family. Just don\u2019t tell Zach in Accounting. He knows what he did.\n\n\n\nWhile odd bits have changed since the 10th anniversary, things remain mostly the same. After all these years, still not in the App Store. No plans to shift to a subscription model. I’ve resisted many of the “innovations” in software sales and distribution in recent years. I could probably write another post why but in short, I haven’t found any need to change something that works.\n\n\n\nCan’t say whether I’ll still be here doing this for Hazel’s 20th anniversary but I hope you’ll forgive me if I forget again and end up being a year or two late.", "date_published": "2022-09-06T09:05:42-04:00", "date_modified": "2022-09-06T12:06:09-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" }, "tags": [ "Business", "Hazel", "Noodlesoft" ] }, { "id": "https://www.noodlesoft.com/blog/?p=575", "url": "https://www.noodlesoft.com/blog/2021/01/25/codesigning-notarization-woes/", "title": "Codesigning & Notarization Woes", "content_html": "\nAs mentioned in my last post, I had various issues with codesigning and notarization during Hazel 5\u2019s launch. Now before I get into it, remember during all this that Hazel is codesigned and notarized with no warnings or errors. In my release build process, I do a codesign \u2014verify
as well as spctl
to make sure everything is hunky-dory before submitting to Apple for notarization.
The biggest problem at launch was some users getting an \u201cUnidentified developer\u201d alert when opening the dmg. I had various users send in logs, but it was only when someone found a log message pertaining to the rpath for one of the binaries in the bundle that I was able to identify the problem. Strangely enough, that person didn\u2019t receive the \u201cUnidentified developer\u201d error alert.
\n\n\n\nTurns out, I had mistakenly added a binary to the top level bundle (it was originally in a framework). The binary had an rpath which escaped the framework bundle as it depended on a sibling framework. This worked fine when the binary was in the framework bundle but when it was at the top level of the main app bundle, it escaped the app bundle itself. Not sure how the binary got added to the Copy Files phase there but it was an easy fix to remove.
\n\n\n\nAnother issue was that the installer wasn\u2019t triggering for some people. For the installer to trigger, Hazel needs to detect that it is running from a disk image. Further investigation turned up that Hazel was being translocated. If you don\u2019t know what translocation is, I suggest reading this article:\u00a0https://lapcatsoftware.com/articles/app-translocation.html
\n\n\n\nWhen translocated, the binary is no longer on the disk image, instead it is copied to a temp location on disk. Hazel is unaware of this and as a result, doesn\u2019t run the installer. Why was Hazel being translocated? I\u2019m still not sure. It\u2019s my understanding that if an app and its containing dmg is signed and notarized, it shouldn\u2019t be translocated. As a workaround, I ended up using the private SecTranslocate.h
APIs to detect the translocation and compensate appropriately.
Possibly related to the above, there was also an issue with the embedded helper app not running. Logs from users showed that the quarantine flag was still set on the helper and that was preventing it from being run. When the user copies an app, like say from a disk image to /Applications, the quarantine flag should be cleared for the app and everything inside but for some reason it was not clearing it for the embedded binaries. Note that unlike when a user launches an app from Finder where they will be asked to run the app, a login item helper will fail to launch without any prompt. As a short term workaround, on first run, I had Hazel recursively remove its quarantine flag before it attempted to run the helper.
\n\n\n\nEven with the workarounds, something didn\u2019t sit right with me. I suspected there was something wrong with my bundle that was causing these issues. I ended up filing a DTS incident to get some feedback from Apple. The DTS engineer was able to reproduce the issue on a VM and dig up a log message indicating that it could not clear the quarantine flag on the Autoupdate helper app in the Sparkle framework. For those that don\u2019t know, Sparkle is a very commonly used framework for apps to update themselves. The Autoupdate helper runs when your app is terminated so that it can install and run the new version.
\n\n\n\nThis all lead to an investigation into where should Autoupdate, or executable binaries in general, be put in a framework. Now, I had looked into this once before . Sparkle originally put Autoupdate in Resources which is incorrect and can cause subtle issues. The solution I came up with back then was to put any executables alongside the framework binary, which would be in Versions/A with a symbolic link at the top level of the framework bundle. This seemed to work at the time. It got through codesigning and notarization checks without issue and ran fine after that.
\n\n\n\nBut it seems that the problem is more subtle than that as whatever code that clears quarantine flags on embedded bundles didn\u2019t like that. I was pointed to this article which suggests I put the program in Contents/Helpers. Despite the insistence that this was the way to do it, it flat out did not work. An important thing to note is that framework bundles do not have a Contents directory. Putting a Contents directory, either in Versions/A or at the top level will make codesign
barf, complaining about an invalid bundle format. My guess is that when codesign sees a Contents directory, it considers the bundle to be another (non-framework) type of bundle. After wasting a good bit of time on this, I went with what I thought made more sense, putting it in a Helpers directory (sans Contents). If you have an Xcode \u201cCopy Files\u201d phase copy to Resources for a framework, for instance, it doesn\u2019t put it in Contents/Resources, but in Resources so it made some sense to do it this way.
Sure enough, that worked. Of course, after fixing it, someone pointed out how some of the system frameworks use the Helper directory. I guess I should\u2019ve checked there first. At least I have some confirmation that I was on the right track. Note that you should put the Helper directory under Versions/A. You can symlink to the top level but that\u2019s optional. I did it mainly to give myself a more consistent path to access it in the very unlikely event that I end up shipping different versions of the framework.
\n\n\n\nOverall, this experience has been very frustrating. There is little to no documentation on all the various things that can go wrong in your bundle that will cause things to fail, and when it does fail, the logging is very inconsistent. Lastly, none of the tools or processes in place (codesign
, spctl
, notarization) catch these cases. These are all issues related to the static structure of the app bundle so it seems like they should be detectable. Having a tool that developers can run on their bundles before submitting them would be very helpful as the current ones are far from complete in that regard.
After all this, I\u2019m still not sure if the translocation problem is still there or not. I\u2019m not about to remove a workaround just to have it fail for users just so I can get some feedback so that question will remain unanswered for the time being. The lack of definitive and correct information during this whole ordeal is a bit disturbing and makes me think that there\u2019s no one that actually knows for sure how things really work.
\n\n\n\nFor those at Fruit Company, I’ve filed FBAs FB8981011 and FB8981016.
\n ", "content_text": "As mentioned in my last post, I had various issues with codesigning and notarization during Hazel 5\u2019s launch. Now before I get into it, remember during all this that Hazel is codesigned and notarized with no warnings or errors. In my release build process, I do a codesign \u2014verify as well as spctl to make sure everything is hunky-dory before submitting to Apple for notarization.\n\n\n\nThe biggest problem at launch was some users getting an \u201cUnidentified developer\u201d alert when opening the dmg. I had various users send in logs, but it was only when someone found a log message pertaining to the rpath for one of the binaries in the bundle that I was able to identify the problem. Strangely enough, that person didn\u2019t receive the \u201cUnidentified developer\u201d error alert.\n\n\n\nTurns out, I had mistakenly added a binary to the top level bundle (it was originally in a framework). The binary had an rpath which escaped the framework bundle as it depended on a sibling framework. This worked fine when the binary was in the framework bundle but when it was at the top level of the main app bundle, it escaped the app bundle itself. Not sure how the binary got added to the Copy Files phase there but it was an easy fix to remove.\n\n\n\nAnother issue was that the installer wasn\u2019t triggering for some people. For the installer to trigger, Hazel needs to detect that it is running from a disk image. Further investigation turned up that Hazel was being translocated. If you don\u2019t know what translocation is, I suggest reading this article:\u00a0https://lapcatsoftware.com/articles/app-translocation.html\n\n\n\nWhen translocated, the binary is no longer on the disk image, instead it is copied to a temp location on disk. Hazel is unaware of this and as a result, doesn\u2019t run the installer. Why was Hazel being translocated? I\u2019m still not sure. It\u2019s my understanding that if an app and its containing dmg is signed and notarized, it shouldn\u2019t be translocated. As a workaround, I ended up using the private SecTranslocate.h APIs to detect the translocation and compensate appropriately.\n\n\n\nPossibly related to the above, there was also an issue with the embedded helper app not running. Logs from users showed that the quarantine flag was still set on the helper and that was preventing it from being run. When the user copies an app, like say from a disk image to /Applications, the quarantine flag should be cleared for the app and everything inside but for some reason it was not clearing it for the embedded binaries. Note that unlike when a user launches an app from Finder where they will be asked to run the app, a login item helper will fail to launch without any prompt. As a short term workaround, on first run, I had Hazel recursively remove its quarantine flag before it attempted to run the helper.\n\n\n\nEven with the workarounds, something didn\u2019t sit right with me. I suspected there was something wrong with my bundle that was causing these issues. I ended up filing a DTS incident to get some feedback from Apple. The DTS engineer was able to reproduce the issue on a VM and dig up a log message indicating that it could not clear the quarantine flag on the Autoupdate helper app in the Sparkle framework. For those that don\u2019t know, Sparkle is a very commonly used framework for apps to update themselves. The Autoupdate helper runs when your app is terminated so that it can install and run the new version.\n\n\n\nThis all lead to an investigation into where should Autoupdate, or executable binaries in general, be put in a framework. Now, I had looked into this once before . Sparkle originally put Autoupdate in Resources which is incorrect and can cause subtle issues. The solution I came up with back then was to put any executables alongside the framework binary, which would be in Versions/A with a symbolic link at the top level of the framework bundle. This seemed to work at the time. It got through codesigning and notarization checks without issue and ran fine after that.\n\n\n\nBut it seems that the problem is more subtle than that as whatever code that clears quarantine flags on embedded bundles didn\u2019t like that. I was pointed to this article which suggests I put the program in Contents/Helpers. Despite the insistence that this was the way to do it, it flat out did not work. An important thing to note is that framework bundles do not have a Contents directory. Putting a Contents directory, either in Versions/A or at the top level will make codesign barf, complaining about an invalid bundle format. My guess is that when codesign sees a Contents directory, it considers the bundle to be another (non-framework) type of bundle. After wasting a good bit of time on this, I went with what I thought made more sense, putting it in a Helpers directory (sans Contents). If you have an Xcode \u201cCopy Files\u201d phase copy to Resources for a framework, for instance, it doesn\u2019t put it in Contents/Resources, but in Resources so it made some sense to do it this way.\n\n\n\nSure enough, that worked. Of course, after fixing it, someone pointed out how some of the system frameworks use the Helper directory. I guess I should\u2019ve checked there first. At least I have some confirmation that I was on the right track. Note that you should put the Helper directory under Versions/A. You can symlink to the top level but that\u2019s optional. I did it mainly to give myself a more consistent path to access it in the very unlikely event that I end up shipping different versions of the framework.\n\n\n\nOverall, this experience has been very frustrating. There is little to no documentation on all the various things that can go wrong in your bundle that will cause things to fail, and when it does fail, the logging is very inconsistent. Lastly, none of the tools or processes in place (codesign, spctl, notarization) catch these cases. These are all issues related to the static structure of the app bundle so it seems like they should be detectable. Having a tool that developers can run on their bundles before submitting them would be very helpful as the current ones are far from complete in that regard.\n\n\n\nAfter all this, I\u2019m still not sure if the translocation problem is still there or not. I\u2019m not about to remove a workaround just to have it fail for users just so I can get some feedback so that question will remain unanswered for the time being. The lack of definitive and correct information during this whole ordeal is a bit disturbing and makes me think that there\u2019s no one that actually knows for sure how things really work.\n\n\n\nFor those at Fruit Company, I’ve filed FBAs FB8981011 and FB8981016.", "date_published": "2021-01-25T13:34:32-04:00", "date_modified": "2021-01-25T13:34:32-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" }, "tags": [ "Hazel", "Software", "Tools", "Xcode" ] }, { "id": "https://www.noodlesoft.com/blog/?p=569", "url": "https://www.noodlesoft.com/blog/2020/12/20/hazel-5-launch-postmortem/", "title": "Hazel 5 Launch Postmortem", "content_html": "\nAs promised, I thought I’d write about my launch. While not disastrous, it had its share of bumps. I had hoped that I had learned something from the Hazel 4 launch four years ago. One of the issues was server capacity. This year, I deployed an extra server. It was an asymmetrical setup, with my main setup handling the website and doling out free upgrades to recent purchasers, while the second server handled the store. Unfortunately, it wasn\u2019t enough. The store still got swamped. Given how busy I was handling requests and trying to troubleshoot other issues, I didn\u2019t have time to test and deploy yet another server, plus they would all be hitting the same database so it was unclear if it would help much. Given that this type of load tends to subside within the day, I rode it out.
\n\n\n\nOne thing I could have done to help alleviate this was to spread out sending messages to the mailing list. Before sending anything to the list, traffic was quite manageable. Once the list got blasted, so did my site. I\u2019m not sure if my email campaign provider supports it, but sending messages in chunks or just slowing down the sending rate would have probably minimized the problems.
\n\n\n\nThen there were packaging issues. Hazel is codesigned and notarized yet on some people\u2019s systems, it would reject Hazel, either wholesale or in parts. This is worth a whole post on its own so expect one later. Suffice it to say, I did fix some of the issues and came up with workarounds for the others.
\n\n\n\nAnd finally, there were actual issues with the software.
\n\n\n\nFirst was a bug with trial mode expiring soon after install. I had Hazel reset the trial period for people coming from a previous version but it contained a bug which I did not catch. I did have a beta period but the version used then accepted Hazel 4 licenses, which meant that trial mode was not tested.
\n\n\n\nThe other major bug was black backgrounds appearing in some views on 10.13. I take total responsibility for this as I did not test for 10.13. I did have a 10.13 partition on a drive I keep with various macOS versions, but it got nuked by an early Big Sur beta install which went awry. I tried reinstalling but my installer was corrupt. Add to that that Apple doesn\u2019t allow you to download old installers and you can see how this fell by the wayside as other issues came up. It is ultimately my fault and my apologies to those running 10.13. As for the issue, it seems that 10.13 has problems with certain named/system colors when the app is linked against 11.0. Solution was to do special-case code for 10.13 using non-named colors.
\n\n\n\nThere were plenty of other bugs but those were the most apparent and the ones I had to address quickly.
\n\n\n\nAnd with all of the above issues, I had to deal with thousands of people reporting them. Especially in the first few days, it was a frantic balancing act of being responsive to users while trying to carve out time to investigate the issues they were reporting. Logic would dictate stopping the bleeding first (i.e. investigate and address the problems) but it\u2019s hard to ignore the huge number of messages piling up. Some would say that having all that attention would be a good problem to have, but when it was happening, it sure didn\u2019t feel like it.
\n\n\n\nLessons to be learned:
\n\n\n\nOddly, I found that the press was noticeably absent. It seems that even though the Mac market keeps growing, there are fewer and fewer outlets reporting and reviewing Mac products. Hazel has enough of a following that it didn\u2019t matter as much but it feels as if things have regressed on that front, which is a bit sad.
\n\n\n\nNext time, I\u2019ll be talking about my journey into the nightmare world of code signing and notarization. Fun times to be had by all. Until then\u2026
\n\n\n\n\n ", "content_text": "As promised, I thought I’d write about my launch. While not disastrous, it had its share of bumps. I had hoped that I had learned something from the Hazel 4 launch four years ago. One of the issues was server capacity. This year, I deployed an extra server. It was an asymmetrical setup, with my main setup handling the website and doling out free upgrades to recent purchasers, while the second server handled the store. Unfortunately, it wasn\u2019t enough. The store still got swamped. Given how busy I was handling requests and trying to troubleshoot other issues, I didn\u2019t have time to test and deploy yet another server, plus they would all be hitting the same database so it was unclear if it would help much. Given that this type of load tends to subside within the day, I rode it out.\n\n\n\nOne thing I could have done to help alleviate this was to spread out sending messages to the mailing list. Before sending anything to the list, traffic was quite manageable. Once the list got blasted, so did my site. I\u2019m not sure if my email campaign provider supports it, but sending messages in chunks or just slowing down the sending rate would have probably minimized the problems.\n\n\n\nThen there were packaging issues. Hazel is codesigned and notarized yet on some people\u2019s systems, it would reject Hazel, either wholesale or in parts. This is worth a whole post on its own so expect one later. Suffice it to say, I did fix some of the issues and came up with workarounds for the others.\n\n\n\nAnd finally, there were actual issues with the software.\n\n\n\nFirst was a bug with trial mode expiring soon after install. I had Hazel reset the trial period for people coming from a previous version but it contained a bug which I did not catch. I did have a beta period but the version used then accepted Hazel 4 licenses, which meant that trial mode was not tested.\n\n\n\nThe other major bug was black backgrounds appearing in some views on 10.13. I take total responsibility for this as I did not test for 10.13. I did have a 10.13 partition on a drive I keep with various macOS versions, but it got nuked by an early Big Sur beta install which went awry. I tried reinstalling but my installer was corrupt. Add to that that Apple doesn\u2019t allow you to download old installers and you can see how this fell by the wayside as other issues came up. It is ultimately my fault and my apologies to those running 10.13. As for the issue, it seems that 10.13 has problems with certain named/system colors when the app is linked against 11.0. Solution was to do special-case code for 10.13 using non-named colors.\n\n\n\nThere were plenty of other bugs but those were the most apparent and the ones I had to address quickly.\n\n\n\nAnd with all of the above issues, I had to deal with thousands of people reporting them. Especially in the first few days, it was a frantic balancing act of being responsive to users while trying to carve out time to investigate the issues they were reporting. Logic would dictate stopping the bleeding first (i.e. investigate and address the problems) but it\u2019s hard to ignore the huge number of messages piling up. Some would say that having all that attention would be a good problem to have, but when it was happening, it sure didn\u2019t feel like it.\n\n\n\nLessons to be learned:\n\n\n\nTry and slow down or space out announcements. Having everyone find out at once is asking for trouble. One idea I toyed with before launch but didn\u2019t implement was to have a preview for those on the mailing list. Have a separate store that was available early where they could purchase an upgrade before the release to the public at large. That might have helped with the initial crush.When running a beta test, be mindful of the holes in your testing, including differences between the beta and final product and missing demographics in your pool of beta testers.Keep your priorities straight. Not everything needs to be handled immediately. It’s ok to ignore stuff.Accept that no matter how much you prepare, you are never fully ready for what comes next.\n\n\n\n\n\n\n\nOddly, I found that the press was noticeably absent. It seems that even though the Mac market keeps growing, there are fewer and fewer outlets reporting and reviewing Mac products. Hazel has enough of a following that it didn\u2019t matter as much but it feels as if things have regressed on that front, which is a bit sad.\n\n\n\nNext time, I\u2019ll be talking about my journey into the nightmare world of code signing and notarization. Fun times to be had by all. Until then\u2026", "date_published": "2020-12-20T16:57:57-04:00", "date_modified": "2020-12-20T16:59:00-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" }, "tags": [ "Hazel", "Noodlesoft", "Software", "System Administration" ] }, { "id": "https://www.noodlesoft.com/blog/?p=560", "url": "https://www.noodlesoft.com/blog/2020/12/09/hazel-5/", "title": "Hazel 5", "content_html": "\nI\u2019m almost a month late with this announcement but Hazel 5 is out! I\u2019ve been quite busy since the launch but after releasing 5.0.3 (yes, there have already been three patches) I feel like I have a little breathing room to post even if I’m bit exhausted.
\n\n\n\nI won\u2019t give a full rundown of what\u2019s new but you can get more details here.
\n\n\n\nThe most obvious thing you\u2019ll probably notice is that Hazel is no longer a preference pane, instead shipping in an app form factor. Why? The main reason is Apple. If you missed my post on this topic, in short, Apple screwed over preference panes in Catalina. The result is a buggy mess and I\u2019ve seen almost no improvement on that front since then. It seemed clear to me that preference panes were a developmental dead end.
\n\n\n\nI had already been planning on releasing a version 5 so I was prepared to make some major changes. Problem was,\u00a0I had to make sure I released 5.0 around when Apple\u2019s next OS (now known as Big Sur)\u00a0would arrive. Why? Because any Big Sur compatibility work put into Hazel 4 would most likely not be usable in version 5. Partly because of the major changes between the two but mostly because many of the issues that affect preference panes since Catalina aren\u2019t a problem for apps. I could either do double the work or cut my losses and do a big push for version 5 in the time available.\u00a0The downside is that the conversion to an app displaced other features I had planned. Some of these will make it into point releases but the bigger ones may have to wait until 6.0.\u00a0
\n\n\n\nIt is nice to be able to have things in an app. There are fewer limitations but at the same time, it changes expectations. One of the major reasons why I had Hazel as a preference pane was that people expected preference panes to be for configuring services that run in the background. Since releasing as an app, I\u2019ve had numerous people ask me to provide a way to hide the dock icon. People have the notion that they need to keep the app running for Hazel to run its rules, not realizing there\u2019s a helper doing all that separately and that they can quit the app at any time. I did add in a little tip that pops up if you activate Hazel after a few minutes of inactivity (which would imply, to me, that they were keeping it running longer than needed) but I may need to be a bit more forceful in educating users.
\n\n\n\nBesides all the interface improvements, I\u2019ve also added support for tables and lists. This expands the possibilities with text matching, hopefully allowing users to consolidate their rules. This took a good deal of back and forth in the design until I finally settled on what\u2019s there now. There\u2019s a chance these features will change in the future, especially with how list items work, but I\u2019ll try and make sure it is done in a way to preserve compatibility with old rules. That\u2019s always been a concern for me: making sure any changes I make to the rule schema/interface are done in a way such that old rules are expressible in the new paradigm. Except in the rare case where I drop a function entirely, I strive to make sure everything carries over.
\n\n\n\nOne focus this time around was making the install process a bit nicer. Hazel 5 ships as an app on a disk image. The preferred way to install is to run it right off the disk image. Hazel will detect this case and offer to install into Applications (or a folder of your choosing) and relaunch. Or if you prefer, you can drag Hazel to a folder and run it there, in which case, the installer doesn\u2019t kick in. The latter should reassure users that the app is self-contained and doesn\u2019t install stuff in unexpected places. I\u2019ve always felt that when you are first presented with an app, a double-click should run it, ready to do work. This includes any steps needed to get to that point, like installation. That was something that worked very well when Hazel was a preference pane and I wanted that same experience as an app. Having the user drag the app to Applications, navigate to it and then launch it seems like too many steps and I felt I could do better. If you want to do this with your own app, there are frameworks you can use.
\n\n\n\nAnother thing I\u2019ve added is the \u201cFull Disk Access Guide\u201d. For some operations, such as managing your Trash, Hazel requires full disk access. Unfortunately, Apple dropped the ball on this, providing little to no guidance or APIs to detect these cases and having no UI to help the user do it, thus leaving it to individual developers to cook up their own schemes. Previously, I pointed the user to a webpage which outlined the steps of navigating to the correct pane in System Preferences, unlocking it and then dragging the app into the list. For Hazel 5, I now bring up the correct pane in System Preferences and show a window/overlay which attaches itself to System Preferences, showing each step with arrows for guidance. Screenshot included below. And if it looks familiar to you, yes, I stole it from SuperDuper, with permission from its developer Dave Nanian (thanks Dave!).
\n\n\n\n\n\n\n\nPricing is always a tricky issue. It\u2019s always hard coming up with the right balance of something users will pay while also making sure your business is sustainable. But let\u2019s address the elephant in room, or maybe the lack of said elephant. Subscriptions. I never really considered them for two reasons (a) I\u2019m not particularly fond of them and neither are a good number of users and (b) I don\u2019t need them. I\u2019ve been fortunate in being able to keep doing this while charging a price that is fair to me and my users. Could I make more money? Sure, but if you\u2019ve followed this blog for any period of time, you should realize that\u2019s not my main goal.
\n\n\n\nThat all said, I did end up raising prices as a lot of work went into this release. While users have been pretty supportive of the price changes, I can\u2019t please everyone. In my defense, I\u2019ll point out that I\u2019ve been pretty good with providing significant amounts of functionality for free in between major releases (don\u2019t believe me? Check out my release notes). Additionally, my major releases are pretty far apart (about every 4 years). Not that I\u2019m doing that on purpose and I can\u2019t guarantee the next one will happen at the same interval. It just happens to be how I do development. Major release sees major shift in architecture, paradigm or functionality. Minor releases flesh that out until I feel like that has run its course. Rinse, repeat.
\n\n\n\nAnd on that note, I hope to get one more release out before the end of the year. With luck, this will include a bonus feature which should make tables even more useful. Also, I\u2019ll try and write up a post-mortem for the launch as it didn\u2019t go quite so smoothly and I\u2019m sure there are lessons to be learned there. And before I forget, thanks to you for your support. It\u2019s been a long journey and it feels great reaching this milestone.
\n\n\n\n\n ", "content_text": "I\u2019m almost a month late with this announcement but Hazel 5 is out! I\u2019ve been quite busy since the launch but after releasing 5.0.3 (yes, there have already been three patches) I feel like I have a little breathing room to post even if I’m bit exhausted.\n\n\n\nI won\u2019t give a full rundown of what\u2019s new but you can get more details here.\n\n\n\nThe most obvious thing you\u2019ll probably notice is that Hazel is no longer a preference pane, instead shipping in an app form factor. Why? The main reason is Apple. If you missed my post on this topic, in short, Apple screwed over preference panes in Catalina. The result is a buggy mess and I\u2019ve seen almost no improvement on that front since then. It seemed clear to me that preference panes were a developmental dead end.\n\n\n\nI had already been planning on releasing a version 5 so I was prepared to make some major changes. Problem was,\u00a0I had to make sure I released 5.0 around when Apple\u2019s next OS (now known as Big Sur)\u00a0would arrive. Why? Because any Big Sur compatibility work put into Hazel 4 would most likely not be usable in version 5. Partly because of the major changes between the two but mostly because many of the issues that affect preference panes since Catalina aren\u2019t a problem for apps. I could either do double the work or cut my losses and do a big push for version 5 in the time available.\u00a0The downside is that the conversion to an app displaced other features I had planned. Some of these will make it into point releases but the bigger ones may have to wait until 6.0.\u00a0\n\n\n\nIt is nice to be able to have things in an app. There are fewer limitations but at the same time, it changes expectations. One of the major reasons why I had Hazel as a preference pane was that people expected preference panes to be for configuring services that run in the background. Since releasing as an app, I\u2019ve had numerous people ask me to provide a way to hide the dock icon. People have the notion that they need to keep the app running for Hazel to run its rules, not realizing there\u2019s a helper doing all that separately and that they can quit the app at any time. I did add in a little tip that pops up if you activate Hazel after a few minutes of inactivity (which would imply, to me, that they were keeping it running longer than needed) but I may need to be a bit more forceful in educating users.\n\n\n\nBesides all the interface improvements, I\u2019ve also added support for tables and lists. This expands the possibilities with text matching, hopefully allowing users to consolidate their rules. This took a good deal of back and forth in the design until I finally settled on what\u2019s there now. There\u2019s a chance these features will change in the future, especially with how list items work, but I\u2019ll try and make sure it is done in a way to preserve compatibility with old rules. That\u2019s always been a concern for me: making sure any changes I make to the rule schema/interface are done in a way such that old rules are expressible in the new paradigm. Except in the rare case where I drop a function entirely, I strive to make sure everything carries over.\n\n\n\nOne focus this time around was making the install process a bit nicer. Hazel 5 ships as an app on a disk image. The preferred way to install is to run it right off the disk image. Hazel will detect this case and offer to install into Applications (or a folder of your choosing) and relaunch. Or if you prefer, you can drag Hazel to a folder and run it there, in which case, the installer doesn\u2019t kick in. The latter should reassure users that the app is self-contained and doesn\u2019t install stuff in unexpected places. I\u2019ve always felt that when you are first presented with an app, a double-click should run it, ready to do work. This includes any steps needed to get to that point, like installation. That was something that worked very well when Hazel was a preference pane and I wanted that same experience as an app. Having the user drag the app to Applications, navigate to it and then launch it seems like too many steps and I felt I could do better. If you want to do this with your own app, there are frameworks you can use.\n\n\n\nAnother thing I\u2019ve added is the \u201cFull Disk Access Guide\u201d. For some operations, such as managing your Trash, Hazel requires full disk access. Unfortunately, Apple dropped the ball on this, providing little to no guidance or APIs to detect these cases and having no UI to help the user do it, thus leaving it to individual developers to cook up their own schemes. Previously, I pointed the user to a webpage which outlined the steps of navigating to the correct pane in System Preferences, unlocking it and then dragging the app into the list. For Hazel 5, I now bring up the correct pane in System Preferences and show a window/overlay which attaches itself to System Preferences, showing each step with arrows for guidance. Screenshot included below. And if it looks familiar to you, yes, I stole it from SuperDuper, with permission from its developer Dave Nanian (thanks Dave!).\n\n\n\n\n\n\n\nPricing is always a tricky issue. It\u2019s always hard coming up with the right balance of something users will pay while also making sure your business is sustainable. But let\u2019s address the elephant in room, or maybe the lack of said elephant. Subscriptions. I never really considered them for two reasons (a) I\u2019m not particularly fond of them and neither are a good number of users and (b) I don\u2019t need them. I\u2019ve been fortunate in being able to keep doing this while charging a price that is fair to me and my users. Could I make more money? Sure, but if you\u2019ve followed this blog for any period of time, you should realize that\u2019s not my main goal.\n\n\n\nThat all said, I did end up raising prices as a lot of work went into this release. While users have been pretty supportive of the price changes, I can\u2019t please everyone. In my defense, I\u2019ll point out that I\u2019ve been pretty good with providing significant amounts of functionality for free in between major releases (don\u2019t believe me? Check out my release notes). Additionally, my major releases are pretty far apart (about every 4 years). Not that I\u2019m doing that on purpose and I can\u2019t guarantee the next one will happen at the same interval. It just happens to be how I do development. Major release sees major shift in architecture, paradigm or functionality. Minor releases flesh that out until I feel like that has run its course. Rinse, repeat.\n\n\n\nAnd on that note, I hope to get one more release out before the end of the year. With luck, this will include a bonus feature which should make tables even more useful. Also, I\u2019ll try and write up a post-mortem for the launch as it didn\u2019t go quite so smoothly and I\u2019m sure there are lessons to be learned there. And before I forget, thanks to you for your support. It\u2019s been a long journey and it feels great reaching this milestone.", "date_published": "2020-12-09T11:40:27-04:00", "date_modified": "2020-12-09T11:40:27-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" }, "tags": [ "Hazel", "Noodlesoft", "Software" ] }, { "id": "https://www.noodlesoft.com/blog/?p=551", "url": "https://www.noodlesoft.com/blog/2020/08/24/a-couple-of-random-xcode-tips-to-speed-up-your-builds/", "title": "A couple of random Xcode tips to improve your builds", "content_html": "Recently, I took some time to do some clean up on my Xcode project as it has collected its share of odd scripts and settings over the years. Little did I know that I\u2019d make a couple of discoveries surprising enough that I\u2019d actually bother to blog about it.
\nThe first thing I wanted to address was build speed. Over the years, it\u2019s felt like build times have gotten longer. Of course, before we start mucking with things, we needed a way of measuring which leads me to the first tip: you can have Xcode display build times in the main activity display in the titlebar. Just use this default:
\n\n\ndefaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
\n\n\n\nAfter doing that and performing a build, it should look something like this:
\n\n\n\n\n\n\n\nI tried tightening things up: getting rid of unnecessary steps, removing redundancies, making sure all script phases had inputs and outputs specified. They had minimal impact. Looking at my build logs in Xcode (which helpfully show the time for each step), I noticed that code signing was taking up a significant amount of time. Around 3-8 seconds each occurrence, even for standalone binaries. I have quite a few of these as well as frameworks so that time adds up. Note that for debug builds, I had the \u201c\u2014timestamp=none\u201d option set so that was not the culprit in this case.
\n\n\n\nPoking around, I came across this thread. While I didn\u2019t have the main problem described there of duplicate certificates, buried in that thread was the following advice: trim ~/Library/Preferences/com.apple.security.plist\u00a0
\n\n\n\nOpening that file up revealed that I had several entries, all except one pointing to non-existent files with the one valid entry pointing to my login keychain. After removing the invalid entries, code signing only took up to 1 second, max. This shaved 40-60 seconds off of my full release builds and 10 seconds off of incremental ones. Huge savings.
\n\n\n\nAnother thing I noticed in the cleanup was that some of my frameworks were being copied without their headers. I had a script of my own to remove the headers after copying for deployment builds, but the frameworks remained header-free even when I disabled/removed this script. To make things even stranger, this was was only happening for one target as another target would always have the headers in included frameworks. I checked all sorts of settings but it was only after asking in a Slack channel did I find the answer. Thanks to\u00a0Nicholas Riley, who didn’t miss a beat and pointed me to this thread.
\n\n\n\nApparently, there\u2019s a hidden setting in your project.pbxproj file for copying frameworks where you can specify whether headers get copied over. This is not exposed anywhere in Xcode\u2019s UI, as far as I can tell. It\u2019s also a mystery why it gets set on some targets and not others. The only way to enable/disable this is to edit the project.pbxproj by hand.\u00a0
\n\n\n\nThe setting looks something like this:
\n\n\n\n\u2026={isa =PBXBuildFile; fileRef = F19543FC17EC99FB62CA62C8 /* HockeySDK.framework */; settings ={ATTRIBUTES =(CodeSignOnCopy,RemoveHeadersOnCopy,);};};
\n\n\n\nThe flag in question is RemoveHeadersOnCopy
. It appears the setting sticks even if Xcode writes to the file after your edit. Of course, if you add new frameworks to copy, you may need to edit the file again.\n\n
Hopefully the above helps you out with your builds. If you have any eye-opening tips to make your build process quicker/better, comment below as I\u2019d love to hear them.
\n\n\n\n\n\n\n\nApple announced numerous changes in Catalina in WWDC but there\u2019s one that they failed to mention. System Preferences has had a major change: preference panes now load in a separate process. Apple ones get their own while all the third party ones get stuck in a process called \u201clegacyLoader (System Preferences)\u201d.
\n\n\n\nIt\u2019s becoming more common nowadays to split up programs into separate processes to isolate them from each other, usually done in the name of stability and security. The upshot of this to me is that all display and events happen via IPC between my pane and System Preferences. If done right, this should all be seamless and I shouldn\u2019t notice a thing:
\n\n\n\n\n\n\n\nOf course, it\u2019s never that simple.
\n\n\n\nFirst off, dark mode is broken. You can test this out by creating a blank preference pane in Xcode and loading that. For you Apple folks, that\u2019s FB7076716. Interesting side note: problem doesn\u2019t manifest itself if SIP is disabled.
\n\n\n\nThe other problem is that magenta. What is that? Apparently, it\u2019s a security feature. Any windows besides the main preference window will have their transparent areas colored magenta. I\u2019ve been trying to pin down the rules as to when this occurs but it\u2019s been slow going and also the screenshot above contradicts what I\u2019ve been told. Note that my software is notarized so it\u2019s not like this is only applying to unknown software.
\n\n\n\nTo top this all off: none of this has been announced or documented. I\u2019ve only found out about this through backchannels and then later, via a \u201cconversation\u201d via Feedback Assistant (FB6758586). It\u2019s a big change and requires some major overhauls on my part. Aside from leaving things as they are, my options are to either rework my whole UI to avoid using any extra windows or convert my preference pane to an app. The latter is a long term goal but neither of those are realistic for doing over the summer between WWDC and Catalina\u2019s launch. And mind you, that\u2019s assuming they actually announced and documented this stuff up front (which they didn’t). How Hazel is going to look on Catalina is very much up in the air right now.
\n\n\n\nMaybe this will help other people writing pref panes as info on this is nowhere to be found (if I\u2019m wrong on this, please send a link my way as I dying for any clarification on this). I don\u2019t know how much of this Apple will fix as a good part of it is meant as a feature but one can hope that it will somehow sort itself out in the end.
\n\n\n\n\n ", "content_text": "Apple announced numerous changes in Catalina in WWDC but there\u2019s one that they failed to mention. System Preferences has had a major change: preference panes now load in a separate process. Apple ones get their own while all the third party ones get stuck in a process called \u201clegacyLoader (System Preferences)\u201d.\n\n\n\nIt\u2019s becoming more common nowadays to split up programs into separate processes to isolate them from each other, usually done in the name of stability and security. The upshot of this to me is that all display and events happen via IPC between my pane and System Preferences. If done right, this should all be seamless and I shouldn\u2019t notice a thing:\n\n\n\n\n\n\n\nOf course, it\u2019s never that simple.\n\n\n\nFirst off, dark mode is broken. You can test this out by creating a blank preference pane in Xcode and loading that. For you Apple folks, that\u2019s FB7076716. Interesting side note: problem doesn\u2019t manifest itself if SIP is disabled.\n\n\n\nThe other problem is that magenta. What is that? Apparently, it\u2019s a security feature. Any windows besides the main preference window will have their transparent areas colored magenta. I\u2019ve been trying to pin down the rules as to when this occurs but it\u2019s been slow going and also the screenshot above contradicts what I\u2019ve been told. Note that my software is notarized so it\u2019s not like this is only applying to unknown software.\n\n\n\nTo top this all off: none of this has been announced or documented. I\u2019ve only found out about this through backchannels and then later, via a \u201cconversation\u201d via Feedback Assistant (FB6758586). It\u2019s a big change and requires some major overhauls on my part. Aside from leaving things as they are, my options are to either rework my whole UI to avoid using any extra windows or convert my preference pane to an app. The latter is a long term goal but neither of those are realistic for doing over the summer between WWDC and Catalina\u2019s launch. And mind you, that\u2019s assuming they actually announced and documented this stuff up front (which they didn’t). How Hazel is going to look on Catalina is very much up in the air right now.\n\n\n\nMaybe this will help other people writing pref panes as info on this is nowhere to be found (if I\u2019m wrong on this, please send a link my way as I dying for any clarification on this). I don\u2019t know how much of this Apple will fix as a good part of it is meant as a feature but one can hope that it will somehow sort itself out in the end.", "date_published": "2019-08-28T13:09:29-04:00", "date_modified": "2019-08-28T14:17:03-04:00", "authors": [ { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" } ], "author": { "name": "mr_noodle", "url": "https://www.noodlesoft.com/blog/author/admin/", "avatar": "https://secure.gravatar.com/avatar/b0b3cd2e0a687f20033e3013234df4cc?s=512&d=mm&r=pg" }, "tags": [ "Hazel", "OS X", "Software", "User Interface" ] }, { "id": "https://www.noodlesoft.com/blog/?p=529", "url": "https://www.noodlesoft.com/blog/2019/04/04/frameworks-and-auxiliary-binaries/", "title": "Frameworks and Auxiliary Binaries", "content_html": "In my frameworks, I have extra programs that my framework code needs to use. Before, I would have these auxiliary programs outside the framework bundle and would set a variable in the framework at runtime to point to the location. Now, having everything self-contained in the framework bundle makes things a bit nicer.
\nThis approach is not without it\u2019s little gotchas, which I\u2019ll go through here.
\nThe basics are straightforward enough. In Xcode, for your framework target, add the binary to the target dependencies and add a Copy File build phase which copies it to the Executables location.
\nWith a normal app bundle, these binaries are put in the MacOS
subdirectory. In your code, you can use -[NSBundle pathForAuxiliaryExecutable:]
which knows to look in that directory.
With frameworks, it\u2019s not as simple. First off, there is a Versions
directory with (potentially) various versions underneath. There is a symlink to the current version as well as symlinks at the top level of the framework directory. These symlinks point to the individual directories and files in the framework, including a symlink to the main framework image. Binary images are not put in their own subdirectory as they are with app bundles.
Any other executables aside from the framework binary are not automatically symlinked. On top of that, NSBundle can\u2019t find them unless they are at the top level. So, in addition to the above steps, you need to add a Run Script
build phase which symlinks your extra binaries to the top level. Make sure to use the -h
flag (in addition to -s
) to ln
so as to not resolve the Current
link.
Now, suppose your executable links against another framework in your app? For example, let\u2019s take the following situation:
\n\nIn this case, let\u2019s say someprogram
links against the Bar
framework. We\u2019ll need to specify an @rpath
but what isn\u2019t clear here is what @loader_path
is (for an overview of @rpath
and @loader_path
, check out this post).
It would make sense that @loader_path
is the top level of the framework. After all, NSBundle
will return the top level symlink to your binary which is what you actually run in your code. In such a case, the rpath would be @loader_path/../
(we want to go one level up from someprogram
so that we can see Bar.framework
).
Unfortunately, that isn\u2019t the case. Even though the resulting crash report you would get from doing the above will show the path to the symlinked binary, the loader seems to resolve the link, and then set @loader_path
to that. So, in this case, it is referring to the original binary in Versions/Current/
. Taking this into account, the correct rpath would be @loader_path/../../../
Not a huge deal but hopefully this will save someone from some confusion. As usual, it\u2019s possible I\u2019m missing out on something here, in which case, please comment below on how wrong I am.
\n
Now that the dust has mostly settled, I thought I\u2019d follow up on my previous post concerning Mojave and its new privacy protections.
\nWhen Mojave was first released, there were complaints about Hazel not working. In these cases, Hazel was in the privacy list, but not checked. Users claimed to have not seen any sort of prompt. It\u2019s hard to say if the prompt was just missed somehow or if there was a bug where the prompt was not showing up.
\nMonths later, the issues stopped (or at least people stopped reporting them). I can\u2019t say whether some sort of bug was fixed or if people are just now more familiar with how all the new privacy protections work. I\u2019m leaning towards a bug of some sort as the reports have stopped altogether; I\u2019d expect the occasional report of confusion if it was just a knowledge thing.
\nRegarding unit tests, it seems that changing my unit tests to run within an app, and adding the appropriate usage strings to the test app, was enough to get them to run. There is an issue of including Appkit in unit tests that are testing Appkit-independent functionality, possibly in resulting in subtle false positives in some tests. I suspect those cases will be very rare and, frankly, I\u2019m just glad I can actually run my tests on Mojave now.
\nOne issue that remains is filesystem level protections. With Mojave, certain directories (which I believe still aren’t documented) are protected, not by permissions, but a separate system tied in with SIP. The problem with this is lack of transparency both to us devs as well as users. I\u2019ve had users waste a bunch of time trying to fix the issue by tweaking permissions and ACLs, not realizing that there is another system in place that is invisible to them. Very few users were able to suss out that they needed to add Hazel to the \u201cFull Disk Access\u201d list (instructions on how to do that can be found here).
\nOverall, it\u2019s confusing since there\u2019s little to no indication in the OS. Finder can view these folders fine whereas other Apple apps (like Terminal) can\u2019t. The red badge on the folder icon looks the same as one for a folder protected by UNIX permissions.
\nAt least, there seems to be one way as a dev to be able to make sense of things. Accessing protected directories (for instance, by using access()
) will fail with an EPERM
error. This differs from accessing a directory protected by UNIX permissions. In those cases, you will get an EACCESS
error. While that\u2019s great for differentiating between the two cases what\u2019s unclear to me is if there are other situations, outside of Mojave privacy protections, that would give me an EPERM
error. Nonetheless, in the latest release, I\u2019ve tried to detect this in Hazel and put up an alert. It\u2019s a fairly uncommon case so I suspect most users will not run into this.
By now, most of the kinks have been worked out but it would be nice if Apple were to document this stuff. The path getting to this point was far more rocky than it should have been.
\n
This morning I released a beta of Hazel with a good deal of trepidation. If you’ve been following the dev blogosphere, you should know that the AEpocalpyse is coming. For those not in the know, Mojave introduces privacy protections for access to AppleEvents, prompting the user whenever an app tries to send AppleEvents to another app.
\nHere’s some reading to get you up to speed:
\nFelix Schwarz: macOS Mojave gets new APIs around AppleEvent sandboxing \u2013 but AEpocalypse still looms
\nDaniel Jalkut: Apple Events Usage Description
\nDave Nanian: macOS Mojave: Opening New Vistas in Security for Mac Users
\nPaulo Andrade: Apple Events And The State Of macOS Automation
The result of all this is that we have a not-very-well-thought-out and buggy feature which was added late in the beta with no documentation. The last part makes it particularly hard as we have no way of knowing if the current behavior is a bug or by design, nor whether there will be any more changes or fixes before Mojave ships.
\nAs it stands right now, I am faced with the following problems:
\nAEDeterminePermissionToAutomateTarget
doesn’t work very wellIn short, unless Apple fixes this soon, or even better, rolls it back to be released later, things are going to be a bit bumpy in Mojave. As a user, you may be surprised how often AppleEvents come up in the apps that you use.
\nThe Hazel beta is out (forum login required) so if you are on Mojave (or even if you’re not; I need to make sure I didn’t break things on previous OS versions), give it a try. Reports from the field will help greatly. My options may be limited given the scant documentation and tools provided by Apple but hopefully something can be done.
\nUpdate (Sept 13): Beta 11 is out. It fixes a couple of issues I’ve found:
\ntccutil
tccutil
itself is still broken in that it does not work when specifying a bundle identifier. Makes it such that if you want to reset permissions, you have to do it for all apps, not just for the one you care about. This results in you getting re-prompted all over again. The fix to the Privacy settings above does alleviate much of the need for this but this still indicates a lack of thoroughness when implementing this new system.
\n