This is a follow-up to my recent blog posts Apple Photos phones home on iOS 18 and macOS 15 and The internet is full of experts. I've read a lot of the discussion about and responses to my blog posts, which has forced me to hone my own thinking and arguments on the subject. I characterized Apple's new Enhanced Visual Search feature as a privacy...
My recent blog post Apple Photos phones home on iOS 18 and macOS 15 has received widespread attention, and perhaps inevitably, it has also received widespread criticism by random internet commenters. A common criticism is that I somehow discredited myself by stating, honestly, "I don't understand most of the technical details of Apple's blog...
This morning while perusing the settings of a bunch of apps on my iPhone, I discovered a new setting for Photos that was enabled by default: Enhanced Visual Search. (I manually disabled it before taking the screenshot below.) Apps > Photos"> This setting is also new to Photos on macOS Sequoia, and enabled by default. Oddly, this new feature has...
This blog post has undergone some revision and correction since first published. It turns out, contrary to my initial assumption, that the code signatures of the apps is largely irrelevant. Thanks to Avi Drissman of the Google Chrome team for assistance! According to the Apple Developer Documentation, "macOS Launch Services is an API that enables...
Yesterday, Apple released Safari version 18.2, included with iOS 18.2 and macOS 15.2, as a separate update for macOS 14 and 13. I've already discussed one new feature of Safari 18.2, Copy Link with Highlight, in another blog post. Now I'd like to discuss another new feature, automatic https upgrade. From Apple's announcement: Safari 18.2 on iOS,...
I'm not talking about the tint of the extension icons this time. I'm talking about the size of the extension icons in the Safari toolbar on Mac. I've explained the difference between Safari app extensions and Safari web extensions before, so I won't repeat the explanation here, except to note that my own StopTheMadness Pro and StopTheScript are...
As far as I can tell, the Apple developer boycott of Feedback Assistant, which I launched a year ago, appears to have gone nowhere and made little impact, unfortunately. I personally ended my boycott a couple of months ago when I filed a Feedback about visionOS that I didn't want to publicize. I've filed only a few bug reports since then, but...
StopTheMadness Pro has three variants, one each for iOS, macOS, and visionOS, because I created native apps for each platform rather than simply porting an iPad app to Mac and Vision Pro. The way the App Store works, each native app variant must be reviewed separately by Apple, so every update to StopTheMadness Pro must now pass through an...
This is a follow-up to my blog post macOS Sonoma silently enabled iCloud Keychain despite my precautions from five months ago. The TL;DR of that blog post is that when you have iCloud enabled but not iCloud Keychain, updating from Ventura to Sonoma causes iCloud Keychain to be silently enabled. (I don't know yet whether that still occurs when...
In my first blog post of the year, way back at the beginning of January, I wrote about how Safari can improve extensions, offering a number of suggestions. Last month, Apple released a major update to Safari, version 18 for iOS and macOS, so now it's time to look back at how my suggestions fared. 1. Bring the Manage Extensions widget to Mac from...
This problem was highlighted the other day in an update to Michael Tsai's earlier blog post about “Damaged” Mac App Store Apps, but I think it's important enough to warrant a dedicated blog post, because Mac developers who missed the update need to know about it. The problem is that if you compile your app with the macOS 15 SDK in Xcode 16, and...
I never use the sidebar in macOS Safari and always keep it closed. However, since I updated to Safari 18 on macOS 14.7, I've been seeing new Safari windows open with the sidebar open. This is driving me crazy! It doesn't happen every time, though. It's seemingly random, which makes the issue extremely difficult to diagnose. It frequently happens...
It turns out that the monthly screen recording prompts are not even the most annoying new "feature" of macOS 15 Sequoia. Behold! "If you turn Bluetooth off you will not be able to use your Bluetooth devices." I mean, duh?!? Does this prompt appear monthly? No, that would be far too convenient. So how often? Every. Single. Time. You. Try. To....
All credit for this discovery should go to Ricci Adams, who told me about it. But Ricci doesn't have a blog, and I do, so here it is. Thank you very much, Ricci, and please start a blog! Much has already been written about the new monthly screen recording prompt in macOS 15 Sequoia. As always, Michael Tsai has an excellent summary. The good news...
My M1 Mac mini, which I use for software testing, has five APFS boot volumes, one each for macOS 15 Sequoia, 14 Sonoma, 13 Ventura, 12 Monterey, and 11 Big Sur. Today I learned that I can no longer change the startup security policy or disable System Integrity Protection (SIP) on any of the boot volumes. (I actually didn't bother to test macOS...
Today I downloaded a copy of my data from https://privacy.apple.com, Apple's Data and Privacy website. (For some reason it took 5 days after my request for the data to be ready for download.) I highly recommend that you download your data too, because you might be shocked how much Apple has on you. Apple's advertisement "What happens on your...
When I search for the same text in multiple Safari tabs, I experience a lot of trouble with Safari failing to remember the search string in the find panel. As a workaround, sometimes I open a new TextEdit document, start a search for the desired text, and switch back to Safari, which then remembers the search string across multiple tabs. Today I...
I learned of this issue from a Reddit post and decided to investigate. When I enable the built-in firewall on macOS Sonoma, I've noticed that my DNS query times increase - we're talking several times slower. The built-in firewall can be enabled and disabled in the Network pane of System Settings. I'm able to reproduce the issue not only on macOS...
I keep this website under version control in a git repository on my MacBook Pro. The tricky part is getting the website files from my laptop onto my web server. In the past I did this manually via SFTP, which obviously sucked. With help from the excellent customer service of my web host Tiger Technologies, whom I've been with since 2006 and...
I first saw this bug on the macOS 15 Sequoia betas, which I ignored as a beta issue, but I've started to see the bug on Sonoma too after updating to macOS 14.6, and the bug continues on macOS 14.6.1. I've seen the bug on both my MacBook Pro and my Mac mini. Out of nowhere, an "Updates Available" notification appears, despite the fact that I...
When you launch an app, macOS connects to Apple's OCSP service to check whether the app's Developer ID code signing certificate has been revoked by Apple. In November 2020, Apple's OCSP service experienced a mass outage, preventing Mac users worldwide from launching apps. In response and remedy to this outage, Apple made several explicit promises...
Yesterday, App Store developers were paid for app purchases made during the period of June 2 through June 29, 2024. You may recall that Apple underpaid App Store developers for app bundle purchases made in February through May, due to a bug in Apple's accounting software. I wrote about this issue originally on May 10, with a follow-up on June 3....
Here's a tip for iOS app developers and mobile web developers: today I learned that Smart App Banners don't appear in private browsing. I haven't seen this documented anywhere! Smart App Banners appear above a web page in Safari when the page includes a special HTML element, for example: You can tap the banner to download the app from the App...
Dearest gentle reader, this author opens new Safari windows with an empty page, like a proper member of The Ton. A new private window normally appears as below, untitled. Back in April, I posted on Mastodon about a bug introduced in Safari Technology Preview version 192 that caused the start page rather than an empty page to be shown in new...
Yesterday I discovered a deluge of recent fake customer reviews for a number of top paid apps in the United States Mac App Store. (Each country has its own version of the App Store with separate reviews.) I've now checked the reviews for all of the current top 40 paid apps in the Mac App Store, and 8 of those apps have a large number of fake...
In April, a StopTheMadness Pro customer contacted me about an incompatibility with the Amazon Web Services Management Console. I had never used AWS before, but I noticed that it has a free tier, so I decided to sign up in order to debug the incompatibility. The first AWS dark pattern is that the free tier still requires payment information, e.g.,...
A bookmarklet is a bookmark stored in a web browser that contains JavaScript commands. Here's a simple, useless example: javascript:alert('Hello,%20World!'); To run bookmarklets in Safari on macOS, you need to enable "Show features for web developers" in Safari Advanced Settings and "Allow JavaScript from Smart Search field" in Safari Developer...
Advanced tracking and fingerprinting protection is in the Safari Advanced Settings on both iOS and macOS. The setting has three options: disabled, enabled in private browsing, or enabled in all browsing. Last year I wrote about why I disabled advanced tracking and fingerprinting protection in Safari. This year I found another reason: it breaks my...
This is a follow-up to my blog post macOS Sonoma silently enabled iCloud Keychain despite my precautions. A follower on Mastodon gave me a nice tip on how to prevent this in the future: create a configuration profile. First, download the Apple Configurator app from the Mac App Store. Then open Apple Configurator, select New Profile from the File...
I really want to report bugs to Apple. In fact I do frequently report bugs to Apple via the WebKit Bugzilla. I want to report bugs to Apple so badly that sometimes I write entire blog posts here about Apple bugs. But Apple's Feedback Assistant is a frustrating nightmare, for a number of reasons, and I'm refusing to use it. Back in November I...
Mail app on macOS has a privacy setting Block All Remote Content that prevents downloaded emails from connecting to the internet. For example, HTML emails frequently include image links, which can be used for tracking: when the image is loaded from a remote server, the owner of the server knows that you've opened the email! Block All Remote...
This is a follow-up to my blog post Apple started cheating me out of App Store bundle purchases. The good news is that Apple appears to have resolved most of the issues. Let me give a timeline: May 9: By closely analyzing my App Store Connect financial reports, I discovered that Apple appeared to be underpaying me for StopTheMadness Pro upgrade...
I bought a new M1 MacBook Pro in April 2022. A little over two years later, I'm seeing a service recommended message, and the maximum capacity of the battery is now down to 78%. Admittedly, my MacBook Pro experiences heavy usage: basically all day, every day. The batteries in my previous 2014 Intel MacBook Pro, which experienced the exact same...
Four days ago, I updated my MacBook Pro from macOS Ventura to Sonoma. Since then I've encountered several bugs. This morning, for no apparent reason, Sonoma System Settings decided to show me the warning, "Verify Your Recovery Key". The warning includes some very scary text: To avoid losing access to your account, verify your recovery key. The...
Two days ago I updated my main development Mac from Ventura to Sonoma. Besides the bugs already mentioned yesterday, I've found another new bug. This bug did not exist in Ventura and earlier. You can reproduce the bug via the GUI or Terminal. Create a new folder in Finder Create a new file, for example a text file, and save it in the new folder...
This is a follow-up to my blog post Updating from macOS Ventura to Sonoma silently enables iCloud Keychain. In the addendum to that blog post, I discussed a workaround, which was to delete my WiFi password right before rebooting into the updater. In a trial run on my M1 Mac mini, the workaround was successful. Thankfully, iCloud Keychain remained...
This is not a new issue. It was discovered last year, and it also affects updating from iOS 16 to iOS 17. As far as I'm aware, I'm the first to have noted the issue publicly: The latest iPadOS beta seems to have silently enabled iCloud Keychain. (Although I don’t actually have any passwords on the iPad.) Jul 25, 2023 Later, after iOS 17 and macOS...
TL;DR I've discovered that starting in February, Apple mistakenly subtracts the price of the previously purchased app twice from the proceeds of a "Complete My Bundle" purchase, thereby causing me to take a loss on each such bundle purchase. This accounting change has cost me thousands of dollars over the past few months. Update: May 15 2024 This...
How do I report a YouTube bug? I don't know, so I'm going to blog it. Steps to reproduce: In Safari on iPhone or iPad, open the Apple “Let Loose” video: https://m.youtube.com/watch?v=f1J38FlDKxo Pause the video Open Playback Settings Select Quality 2160p Press OK The spinner spins indefinitely, and the video doesn't play again. Below is a video...
After I posted my funny story of how I recovered the password of an encrypted Mac disk image, I received an email from a reader of the blog, who schooled me on some UNIX. Believe it or not, I don't know everything; know-it-all is just a character that I play on the web. I'd like to express my thanks and appreciation for this blog post to...
This is a story about so-called "secure" password entry that doesn't allow you to see the password you're typing. Back in 2009 I filed a report with Apple—a "Radar" as it was called at the time, now called a "Feedback"— requesting a standard way to show typing in secure text fields. My report, my Feedback (FB5392624), is still open 15 years...
The App Store app on macOS is the default handler of URLs with the macappstore: scheme. App Store preview web pages automatically open the App Store app by setting the location of an HTML element to a macappstore: URL. My free open source app Stop The Mac App Store registers itself as the default macOS handler for the macappstore: scheme,...
Here's a screenshot of the Search pane in the Preferences window of Safari 16 on macOS Big Sur. (This was before Preferences became Settings in macOS.) Note that the preference "Include search engine suggestions" is clearly associated with the "Search engine" preference. Safari 17 (on macOS Monterey and later) added separate settings for search...
I've always attributed slow Xcode launches to Xcode simply sucking, but I've noticed that the FileMerge app frequently launches slowly too. When this happens, the app can take a dozen bounces in the Dock before finally opening. FileMerge resides in the folder Xcode.app/Contents/Applications/ within the Xcode bundle and can be opened from the...
Are you still on macOS Ventura or Monterey and prefer not to install Sonoma yet? Sadly, the brain trust at Apple have decided that your preferences don't matter. (These are the same people who decided to rename Preferences to Settings and wreck the app.) Instead, you get harassed by frequent notifications imploring you to "Upgrade to macOS...
The HTML element was introduced ten years ago by Google Chrome. However, dialog didn't become a web standard until 2022, when Firefox and Safari added support for the element. A dialog is a box shown in front of all other web page content, similar to an alert, but a dialog is much more configurable than an alert and can be shown either modally...
The Safari Extensions section of the iOS Settings app has a More Extensions link that takes you to the Safari Extensions section of the App Store. In the App Store Safari Extensions section, there's a list of Essential Safari Extensions, selected by App Store editors. Note that the list of 23 extensions does not include and never has included my...
This is a follow-up to my post StopTheMadness Pro postmortem: crApp Store still crappy. As I explained in that post, I recently released StopTheMadness Pro, a major update to my Safari extension StopTheMadness, and since the App Store doesn't support paid upgrades, my workaround was to create app bundles in the iOS App Store and Mac App Store...
As a longtime Safari extension developer, I have a number of suggestions about how Safari could improve its extension support. I've already filed some of these suggestions with Apple's Feedback Assistant, but since I'm now boycotting Feedback Assistant, I thought I'd post the list on my blog. Another benefit of blogging the suggestions is of...
In case you missed the announcement, StopTheMadness Pro is available now! StopTheMadness Pro is a major update and paid upgrade to my Safari extension StopTheMadness. Last year I blogged about App Store pricing inflexibility. Nothing much has changed since then. Sadly, those issues persist. I decided to bite the bullet for StopTheMadness Pro,...
The App Store has strict screenshot requirements. Your app screenshots must conform to specific device screen sizes. For iPhone, those sizes are a 5.5-inch display and either a 6.5-inch or 6.7-inch display. I don't know why the screenshot requirements are so strict, because most App Store developers completely ignore the specific screen sizes...
Apple released iOS 17.2 today, and I've noticed that it has started to show the wrong Safari extension icons in some places for some extensions. The same happens on iPadOS 17.2. By design, each Safari extension has two icons: (1) an app icon, in full color; (2) a Safari toolbar icon, black and transparent template. Below are the app icons in...
If you compile an AppKit app with the macOS 14 SDK in Xcode 15, the default font size of several NSControl subclasses increases from 12 to 13 when the app runs on macOS 14 Sonoma. I discovered this the hard way yesterday when I noticed that my box—an NSBox, that is—was no longer big enough for my controls. I haven't done an exhaustive review of...
What happens when you update a Safari extension in the App Store while Safari is open? If it's a Safari app extension, such as my own StopTheMadness, you see this: In contrast, a Safari web extension, such as my own Homecoming for Mastodon, can be updated while Safari is open. I have a theory about why, which I'll discuss later in this blog post....
I wasted at least an hour debugging what I incorrectly assumed was a Mac app sandboxing issue, because I believed what the NSFileManager error told me. Below is the source code of a command-line tool to demonstrate the issue. #import #define SourcePath @"/Library/Receipts/InstallHistory.plist" #define DestinationPath...
The myth of Snow Leopard was started by Senior Vice President of Software Engineering Bertrand Serlet at WWDC 2009. This famous keynote slide was, to put it euphemistically, a bit of product marketing. Non-euphemistically, it was a big lie. Snow Leopard had quite a few new features, including significant changes "under the hood", so to speak. In...
Michael Tsai's encyclopedic blog has discussed issues with Mac App Store receipt validation in 2019 and again in 2022. In summary, Apple's old sample code for developers was broken, some developers tried to fix it, and Apple later posted new sample code (at the same URL). However, I've recently run into a case that seems to call into question all...
Following up on yesterday's announcement of an Apple developer boycott of Feedback Assistant, I've now created an official web page for the boycott, an email address, an RSS feed, and a Mastodon account. Moreover, I'm going to compile a public list of boycott participants, to be posted on the official site. You can definitely participate in the...
I'm organizing a boycott of Apple's Feedback Assistant, starting immediately, and I encourage all Apple developers to join me. Here's how I propose that each of us can effectively participate in the boycott and let Apple know that we're boycotting Feedback Assistant: File a new Feedback about Feedback Assistant (in Developer Tools & Resources)...
This blog post is a follow-up to How to fix the disastrous new Xcode 15 console, which was itself a follow-up to Xcode 15 logs nil as an empty string, not (null). I mentioned in the previous blog post that I filed three bugs with Apple, one of which was FB13289059 "Xcode 15 console logs truncated". Since then I've had some back and forth with...
Last year I wrote about why the macOS Ventura share menu is bad, but that was from a user interface perspective. It turns out that the share menu in Ventura—and now Sonoma—is also bad from a privacy perspective. Here's an example, using http://example.org. In the web inspector, I changed the More information link from https to http so that I...
Advanced tracking and fingerprinting protection is a new feature of Safari 17 that's enabled by default in private browsing on iOS and macOS. I analyzed the details of this feature after it was introduced back in June at Apple's Worldwide Developers Conference (WWDC). Despite the fact that I'm obviously interested in protection from tracking and...
Safari 17 has a new hidden feature that I wasn't even aware of until a customer brought it to my attention. I haven't seen it mentioned anywhere by Apple in their release notes. You may already be aware that for a number of years, Safari has asked your permission every time you click on a link, such as an RSS feed, that opens in an app other than...
This is a follow-up to my recent blog post Xcode 15 logs nil as an empty string, not (null). I've now found three different bugs in the new Xcode 15 console. FB13268283 Xcode 15 console logs nil as empty string rather than (null) FB13270074 Console logs missing on first run after launching Xcode 15 FB13289059 Xcode 15 console logs truncated In my...
A few days ago, Howard Oakley wrote an article LaunchServices problems in Sonoma 14.0, I wrote a comment on the article, and today Howard wrote a follow-up article LaunchServices problems and Ventura. This article is a follow-up to Howard's follow-up. You should read Howard's articles before mine, otherwise mine might not make much sense, and I...
I just discovered a shocking, troubling, and as far as I know, undocumented change in Xcode 15: the functions os_log and NSLog now log nil as an empty string. The previous behavior, going back forever as far as I remember, was to log nil as (null). Here's a sample command-line tool run with Xcode 14: And here's the same tool run with Xcode 15:...
This is a follow-up to my previous blog post Mastodon instance admin deleted all of our DMs after 15 days. After I published that blog post, I was arguing with someone (ignorant) online who engaged in blaming the victim and insisted that I ought to be backing up my Mastodon data weekly to avoid data loss. During that argument, I realized that...
I've just migrated Mastodon instances for the second time this year. My new Mastodon account is @lapcatsoftware@mastodon.social. Eight months ago, I migrated to appdot.net because Mastodon instance mstdn.plus with over 4K users suddenly broke, and mastodon.social was not accepting new signups at that time. My first migration was triggered by an...
For software testing purposes, I use a Mac mini with four APFS boot volumes, one each for Big Sur, Monterey, Ventura, and Sonoma. These were all "fresh" macOS installs with no upgrades or data migration. For the most part, the Mac mini contains very little of my personal data. I do sign in with my Apple ID, but that's it. I never receive, read,...
After testing the iPadOS 17 beta since WWDC, I decided to start over fresh today and "Erase All Content and Settings" on my iPad. There were a couple of reasons for this. First, since iPad 17 beta 4, the Settings app wanted me to verify my recovery key for some reason, and I couldn't get rid of that warning. (FB12749748 for any Apple engineers in...
Today Apple published lists of new features available with iOS 17 (to be released September 18) and macOS 14 (to be released September 26). One of those features caught my eye. Indeed it made my eyes bulge. Automatically pause animated images. Pause animated images by default, such as GIFs in Messages and Safari for your visual comfort. This is...
Last month I asked, How do I report a Google Search bug? In retrospect, it appears that blogging was an effective method of reporting a Google Search bug, because that bug appears to be fixed now! So I'm going to try again this month with a new bug. Once again, this Google Search bug affects Safari on iOS. Let me illustrate the bug with...
I want to use Safari, but sometimes it frustrates the hell out of me, and in some ways it's vastly inferior to Chrome and Firefox. One of my biggest pet peeves is Safari "Intelligent Tracking Prevention" (ITP). This feature is enabled by default and called "Prevent cross-site tracking" in Safari Privacy Settings. Of course I want to prevent...
I do most of my computing, including social media, on my MacBook Pro rather than on my iPhone or iPad. I have no interest in mobile-only social networks, and that's why I've been avoiding Threads by Meta (née Facebook). This week, however, Threads introduced a web client, so I decided to sign up today and take a look. Unfortunately, Threads is...
Yesterday I disclosed an unfixed security vulnerability in macOS Ventura's App Management protection. The explanation was fairly technical, and you had to use Apple's Xcode developer tool in order to test the vulnerability yourself with my sample app. Today I want to illustrate the vulnerability a little more clearly to a non-developer audience....
App Management is a new macOS security feature in Ventura introduced at WWDC last year: If an app is modified by something that isn't signed by the same development team and isn't allowed by an NSUpdateSecurityPolicy, macOS will block the modification and notify the user that an app wants to manage other apps. Clicking on the notification sends...
I found a Google Search bug in Safari on iOS. Or rather, a StopTheMadness customer found the bug and reported it to me. I investigated and determined, to my relief, that the bug wasn't mine, because I could (eventually) reproduce it with StopTheMadness disabled. The question is, how do I report this bug to Google? They have a public issue...
Last week I wrote Firefox 115 can silently remotely disable my extension on any site. This blog post is a follow-up with more information. First, Mozilla has published a support article about the new quarantined domains feature. Here's an excerpt: Firefox version 115 introduced Quarantined Domains to protect our users' privacy and security when...
Content warning: This blog post is navel-gazing. It's fine if you're not interested in that, but then please just stop reading now and close the browser tab instead of becoming annoyed that I'm wasting your time. Thank you! For several reasons, one of which is the introduction of Threads (an Instagram app), I've been thinking a lot lately about...
Firefox version 115.0 was released on July 4, but I'm not celebrating. I'm concerned about a new "feature" in the release notes. Certain Firefox users may come across a message in the extensions panel indicating that their add-ons are not allowed on the site currently open. We have introduced a new back-end feature to only allow some extensions...
1. Naming There are only two hard things in Computer Science: cache invalidation and naming things. I joked during the WWDC keynote that "Vision Pro" sounds like a health insurance plan. Conspiracy theory: a common criticism of Tim Cook is that he has no vision; now he does, literally. Incidentally, I did think that macOS Sonoma was a fine name....
About a month ago I wrote a blog post and a follow-up about how Little Snitch—and all network content filter extensions, as it turns out—leak your IP Address. Last week the developer of Little Snitch responded to my blog posts, though they didn't directly mention me: There has been some discussion recently about the bypassing of Little Snitch by...
A blog post by Cory Underwood inspired me to poke around in the macOS Sonoma beta to discover more details about the new Link Tracking Protection in Safari 17. From Apple's press release: Link Tracking Protection in Messages, Mail, and Safari Private BrowsingSome websites add extra information to their URLs in order to track users across other...
From Apple's new Security updates document: App Sandbox now associates your macOS app with its sandbox container using its code signature. The operating system asks the person using your app to grant permission if it tries to access a sandbox container associated with a different app. For more information, see Accessing files from the macOS App...
I have a bit of a mystery, and I'm hoping that my readers can help me with it. When I was manually backing up my M1 MacBook Pro today, I experienced something bizarre that I can't explain. Last year I wrote about my backup strategy for my new MacBook Pro. What I do is boot into recovery, mount the Data volume, and then run the following commands...
This blog post doesn't have the answers. I'm trying to learn about passkeys, but I don't claim to be an expert. I do have a lot of questions, especially for Apple, because I'm an Apple user and developer. According to Betteridge's law of headlines, "Any headline that ends in a question mark can be answered by the word no." Nonetheless, I want to...
A few days ago I wrote Little Snitch "denied" connections leak your IP address in which I explained that connections denied by Little Snitch are still leaking your IP address, a major privacy issue. The addendum of the blog post notes that I had briefly tested LuLu and saw some of the same behavior. After I published my blog post, I sent a link...
Little Snitch is a macOS app and network filter extension made by Objective Development Software. I purchased Little Snitch years ago, continue to use it, and will continue to use it. I've also done a lot to promote Little Snitch on my blog and even in the news media. However, this blog post raises a privacy issue with Little Snitch that bothers...
I've had a hate-hate relationship with Apple's Feedback Assistant for well over a decade, since before its name was changed to Feedback Assistant from Radar. (I think it's still known internally as Radar.) At various times over the years I've even boycotted Radar/Feedback Assistant out of frustration, refusing to file any bug reports with Apple....
Years ago I stopped using iMessage because it was losing messages. Some messages were simply not delivered, with no error or explanation. I found this unacceptable, and it never happened to me with SMS. I understand that SMS is not end-to-end encrypted, but what's the point of encryption if the message never makes it from end to end? So I've been...
Today Apple announced the availability of peer group benchmarks for developers in App Store analytics. App Analytics in App Store Connect is a helpful tool with a breadth of features to help you understand and improve how your app is performing on the App Store. With metrics related to acquisition, usage, and monetization strategy, App Analytics...
Back in November I wrote a blog post titled I don't want to go back to social media. In retrospect, I realize that I do want to go back to social media, in fact did go back to social media (to Mastodon, that is, not to Twitter, which I definitely don't regret leaving). So this blog post is a kind of mea culpa. I wasn't wrong about everything I...
Apple used to parody permission prompts in Windows Vista. Many years later, the last laugh is on Mac users. This permission prompt is new in macOS 13 Ventura. To see it, just Print this web page, Open in Preview, and click any link. Preview app shipped with Mac OS X 10.0. In fact, Preview was carried over to Mac from NeXTSTEP. I don't know why,...
Happy Valentine's Day to everyone except Apple's App Store Review! My story does have happy ending: my Safari extension StopTheScript is now updated in the iOS App Store. If you're not familiar, StopTheScript is unique in that it stops all JavaScript on your selected web pages, including inline JavaScript, a capability not possessed by Safari...
My previous blog post described how Mastodon instance mstdn.plus with over 4K users suddenly broke. After 6 days of breakage, and 6 days of no word from the instance administrator, an automated email arrived yesterday from mstdn.plus stating that my archive was ready for download. I had started an archive of my mstdn.plus data the same day the...
Does it matter which Mastodon instance you choose? I've seen many people claim that it doesn't matter, and moreover that you can easily switch instances. I learned the hard way that this claim is unwarranted, a disservice to new Mastodon users. Your choice of instance is important, indeed crucial. Until yesterday I was on mstdn.plus, a Mastodon...
Apple's documentation for the class NSURLSession (or URLSession for Swift coders) contains a warning marked "Important": The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you don’t invalidate the session, your app leaks memory until the app terminates. This warning doesn't...
Last year I wrote Bing and DuckDuckGo removed my business web site describing how https://underpassapp.com had been removed from Microsoft Bing search results, and thereby also from DuckDuckGo search results, since DDG relies on Bing. As described by my friend Jesse Squires in the blog post My website disappeared from Bing and DuckDuckGo, Part 2,...
A couple years ago I wrote about the monstrous Open in the Twitter app banner in Safari, which is caused by the Twitter app's adoption of Apple's Universal Links. My very clever (IMO) solution to this problem was to create a Mac app, very cleverly (IMO) named StopTheTwitter, that technically impersonated the official Twitter app by copying its...
This morning I came across a post on Reddit about App Store refunds. I'll quote it in full: Hello! Recently I forgot to cancel two free trials for a couple apps that I’d purchased. I figured it wouldn’t be an issue getting them refunded, and went to reportaproblem.com to request a refund. Both refund requests were denied, so I requested they be...
Last month in Part 2 of my unfortunately ongoing series "App Store Connect is the worst web site ever made", I wrote that Touch ID login no longer works right on App Store Connect and that I filed Feedback (FB11775777) with Apple about the issue. Yesterday I was looking through Feedback Assistant for other issues, and I noticed that my App Store...
Apple's bug reporting system Feedback Assistant is a black hole. I once filed a bug report against the bug reporter itself, requesting a public, searchable bug database, and here's what happened: Much has changed. Yet nothing changed. Time is a flat circle. For the sake of Safari extension developers everywhere, I've decided to post my Safari...
This is a follow-up to my blog post from several months ago, How to restore the Preferences menu item to macOS Ventura. In that blog post, I explained how you could use the default NSMenuShouldUpdateSettingsTitle to control whether apps have the menu item title "Preferences…" or "Settings…" on Ventura. To restore pre-Ventura behavior for all...
I'd like to thank Mark Rowe (AKA bdash) for critical help in making this discovery. After every macOS update, I see this dialog when I launch Xcode. I thought this happened to everyone — that is, everyone with Rosetta and Xcode installed — but I was wrong. So why me? Do Apple engineers have a personal vendetta against me? Well, yes, but that's...
On November 9, Apple released macOS Ventura 13.0.1, as well as iOS 16.1.1 and iPadOS 16.1.1. The release notes list two security vulnerabilities fixed. libxml2 Available for: macOS Ventura Impact: A remote user may be able to cause unexpected app termination or arbitrary code execution Description: An integer overflow was addressed through...
One thing I loved about Mac OS X was that Apple took responsibility for curating, installing, and updating Unix libraries and tools. I say Mac OS X rather than macOS because sadly, in recent years Apple has removed many parts of the Unix foundation from the Mac and also shirked its responsibility to update the remaining Unix components (see for...
Badges? We ain't got no badges. We don't need no badges. I don't have to show you any stinkin' badges! If you're like me (lord help you) and still running macOS Monterey, avoiding Ventura and System Settings like the pandemic, you may have noticed that macOS shows you an "advertisement" for the Ventura update, in the form of a persistent Dock...
I left Twitter several weeks ago. If you want to know why, you can read the addendum of this blog post, but I don't want that to distract from my main point here, so I'll put it off until the end. For various reasons, many Twitter users are currently looking for an alternative to Twitter: Mastodon, Micro.blog, Tumblr, Cohost, etc. A number of...
I complained about App Store Connect a few days ago, and I'm already back to complain about it again. While preparing an app update for submission, I discovered that What's New in This Version no longer accepts the On the other hand, it does still accept the > character. is not allowed."> This is a problem for me because the release notes of my...
App Store Connect is the web site that members of the Apple Developer Program use to manage their App Store apps. I check it daily to see yesterday's sales numbers (live App Store sales numbers are haphazard at best and have stopped working entirely the past week) and to check for new App Store user reviews of my apps. Inexplicably, Apple...
I started this as a personal programming and technical blog, and I'd like to keep it that way. I write many articles that are of interest only to programmers, such as the recent How to regenerate Xcode managed provisioning profiles. However, since I've become an indie developer, I also want to write about my software. Some of the articles I've...
Many years ago I had a self-hosted WordPress blog, but that became a pain because I had to keep installing WordPress security updates to patch vulnerabilities. Also, I had to customize the WordPress code somewhat to suit my preferences. For a few years I stopped blogging entirely, and when I eventually restarted I decided that I wanted a very low...
If you want to reduce your reliance on Twitter, consider RSS. In a way, RSS feeds are what Twitter ought to be: a reverse chronological list containing only content that you chose to follow. (Indeed, Twitter had RSS feeds until 2012.) Below is a list of some RSS feeds that might be useful to Apple developers and others with a strong interest in...
This is a follow-up to my article Check your App IDs for unused capabilities. The other day I was about to upload a new build of StopTheMadness to App Store Connect, but at the last minute I noticed that the build still had the Game Center entitlement, even though I had already removed the entitlement from my AppID. Where was it coming from?...
Apple's Worldwide Developer Conference (WWDC) session What's new in privacy introduced a new security feature in macOS Ventura called App Management. Here's an excerpt from the session transcript. Gatekeeper checks the integrity of newly-downloaded apps. In macOS Ventura, Gatekeeper will now check the integrity of all notarized apps, not just...
Small indie developers have always relied on word of mouth recommendations, because we don't have big budgets for paid advertising. Ironically, in the App Store era we may have become even more dependent on word of mouth recommendations, because App Store top charts favor cheap crap and massive hype over sustainable artisanship, while...
On September 1, I filed a bug with Apple's Feedback Assistant (FB11426949) about Safari extensions titled "Web Extension storage callbacks in the wrong order". Usually Apple will email you when your feedback status changes, but in this case they didn't notify me. Instead, while I was manually browsing my bug reports I discovered that the status...
My most recent Mac App Store submission of StopTheMadness was rejected by Apple App Review for the reason "Your app contains the Game Center entitlement, but it does not link against the GameKit framework." This was puzzling, because my app does not contain the Game Center entitlement! % codesign --display --entitlements -...
When System Integrity Protection (SIP) is enabled, as it is by default, macOS restricts apps from accessing certain files and folders such as ~/Desktop, ~/Documents, and ~/Downloads. If I run a simple ls command in Terminal, % ls ~/Downloads I get a Windows Vista style permission dialog. And if I click "Don't Allow", then Terminal is not allowed...
In the past, I've written about my adventures with UITextView. At present, I'm writing about a new problem I have with UITextView in iOS 16: it crashes while editing, which is one of the worst problems possible! Ironically, the crash is caused by a workaround for another, less serious problem: NSLayoutManager defaultAttachmentScaling doesn't...
On the macOS 13 Ventura beta, the venerable "Preferences…" menu item has been replaced by the iOS-like "Settings…" menu item in Apple's built-in apps. The menu item also gets automatically replaced in third-party apps if they're compiled with the macOS 13 SDK in the Xcode 14 beta. Fortunately, I've discovered a way to undo this change and stop...
This blog post isn't just about Google Chrome, it's also about Safari and Firefox. Chrome is currently the worst offender, because the user gesture requirement for writing to the clipboard was accidentally broken in version 104. A public demonstration of the brokenness has been posted on Web Platform News. If you simply visit the demonstration...
A couple of months ago I blogged about how you can stop Safari from switching your Twitter timeline by selecting "Disable Removal of Non-Cookie Data After 7 Days of No User Interaction (ITP)" in the "Experimental Features" submenu of Safari's "Develop" menu. If you don't select this experimental feature, then Safari's "Intelligent" Tracking...
I'm frustrated because an important feature of the cross-platform WebExtensions API for web browser extensions has been broken in Mac Safari — and only in Mac Safari — for two years. It works everywhere else: Firefox, Google Chrome, other Chromium-based web browsers, and even in Mobile Safari! The feature I'm talking about is run_at...
I constantly accidentally hit the dictation button when editing URLs in the Safari address bar on my iPhone 7 (soon to be replaced, as iOS 16 drops iPhone 7 support), so I was looking for a way to remove the dictation button. For reasons that will become apparent later, the following screenshots are not from my iPhone 7 but rather from the iOS...
The new macOS Ventura System Settings app has been widely criticized. I've personally written two articles criticizing it. The new macOS Ventura Share menu, on the other hand, hasn't yet received much discussion or criticism. This is due partly to System Settings taking a lot of the rhetorical focus — it's so blatantly bad! — and partly to the...
As a Safari extension developer, I have a Safari extension saved search on Twitter. Over the past couple of months, this saved search has shown the exact same tweet many times, with the exact same typo, from a different Twitter account each time. (I used a more specific search below in order to highlight this tweet.) Where did this tweet come...
On April 22, I filed a bug (FB9992639) with Apple's Feedback Assistant titled "Bluetooth re-enabled after every iOS and macOS update". I believe this issue started with iOS 14 and macOS 11, but in any case it definitely happens now with every iOS 15 and macOS 12 update, including today's iOS 15.6 and macOS 12.5 updates, on every device I own. (I...
I've written about NSURL once before. I did not have good things to say. I do not have good things to say this time either. Here's the documentation for the resourceSpecifier property of NSURL: This property contains the resource specifier. Any percent-encoded characters are not unescaped. For example, in the URL...
A year ago I blogged about a macOS bug that causes all of your installed Safari web extensions to disappear silently and mysteriously from Safari. The bug seems to have started on Big Sur, and unfortunately it hasn't gotten any better on Monterey. If anything, the bug gotten worse. It's happening to me rather frequently now. And it continues to...
I want to start by saying that I speak only for myself. I don't speak for other Objective-C programmers, nor do they speak for me. We are not of one mind. The same is true of Swift programmers: some of them seem quite reasonable to me, and others seem rather… fanatical. Regardless, it's almost impossible to have a productive discussion about...
Lately I've noticed that every time I login to my user account on macOS Monterey, the root process fseventsd goes nuts, using almost 100% CPU for 5 to 10 minutes straight. I don't know how long this issue has been happening, because the fans rarely go nuts on my new M1 MacBook Pro. I would've noticed immediately from the fans revving on my 2014...
macOS 12 Monterey doesn't support my 2014 MacBook Pro, so I bought a new MacBook Pro in April. For a long time afterward I thought there was a bug in Keychain Access app that causes it to randomly launch in the background, behind the active app. I keep Keychain Access in my Dock and launch it from there, typically to copy a password and paste it...
Link Unshortener is my Mac app that expands shortened web links, following redirects until it reveals the destination URL. Version 9.0 of Link Unshortener is now available in the Mac App Store, and this update is big! Link Unshortener 9.0 adds a convenient list of all your installed web browsers so that you can open a link in any browser with one...
Suppose you don't use Twitter for a week on one of your Apple devices. This can easily happen to me, because I own half a dozen Apple devices. Or suppose you decide to take a long break from "doomscrolling". Or maybe you just go on a vacation for a week. When you return home from your Twitter vacation, you may find that Twitter has also returned...
Yesterday I was searching with DuckDuckGo and noticed to my dismay that my business web site https://underpassapp.com was missing entirely from the search results! (My personal web site https://lapcatsoftware.com is still in DuckDuckGo, however.) Many people don't realize that DuckDuckGo sources its search results from Microsoft Bing. I learned...
The incident I refer to as the Mac OCSP appocalypse occurred in November 2020. Apple's Developer ID Online Certificate Status Protocol (OCSP) service went down, which caused Mac users worldwide to experience issues with launching their apps. I was among the first to discover the cause of this app launching issue. In response to the Mac OCSP...
I have some additional thoughts after Part 1. First, I've seen some people vehemently defend the System Settings redesign who haven't yet installed macOS 13 Ventura or used the new System Settings. I find this ridiculous. Why are people like this? It's like they revel in ignorance. Anyway, they're missing the fundamental maxim I quoted in Part 1,...
"Most people make the mistake of thinking design is what it looks like. People think it's this veneer, that the designers are handed this box and told, "Make it look good!" That's not what we think design is. It's not just what it looks like and feels like. Design is how it works." - Steve Jobs The venerable System Preferences app has been...
Last week I wrote a blog post about how my bug fix update was stuck in App Store review. Somehow my blog post came to the attention of Apple's senior director of App Review, Trystan Kosmynka, who sent me an unsolicited email about it later that day. I didn't actually realize until yesterday, when I saw a tweet from Kosta Eleftheriou, that the...
Timeline summary: Tuesday 5:39pm: Tweaks for Twitter Mobile update submitted Tuesday 5:43pm: Tweaks for Twitter Mac update submitted Wednesday 4:29am: Tweaks for Twitter Mac update "In Review" Wednesday 7:56am: Tweaks for Twitter Mac update "Pending Developer Release" Wednesday 12:32pm: Tweaks for Twitter Mobile update "In Review" Thursday...
I released my web browser extension StopTheMadness four years ago in the Mac App Store. It was initially priced at $4.99 USD and supported only Safari. Since then I've added a ton of new features, as well as support for Firefox and Chromium browsers. It's almost embarrassing how primitive version 1.0 of StopTheMadness was compared to the current...
Today I learned that Safari, and only Safari, allows the HTML image element to show a video. A web page just has to set the src attribute of an to an MP4 video URL. The video will auto-play, albeit without sound, even if you've set your Safari Preferences to "Never Auto-Play". Here's an example. It turns out that this feature was introduced in...
A week ago it was reported that a number of developers were receiving an email from Apple: App Store Improvement Notice This app has not been updated in a significant amount of time and is scheduled to be removed from sale in 30 days. No action is required for the app to remain available to users who have already downloaded the app. You can keep...
Google Chrome version 101 was released today, and I've discovered to my dismay that it removed the long-standing flag #fill-on-account-select "Fill passwords on account selection". For some strange reason, this very useful flag was never exposed in Chrome's preferences, but you can — or could! — find it by opening chrome://flags in a Chrome tab....
A few days ago I blogged about my new M1 MacBook Pro. It's mostly been fine, but now I'm experiencing a significant problem: I can't figure out how to make a backup! I back up my home folder daily, and that continues to work as before, but I also back up the entire internal disk weekly, and that doesn't work. With my 2014 Intel MacBook Pro, I can...
I just bought a new MacBook Pro as my main development computer, because macOS Monterey doesn't support my previous main development computer — a 2014 MacBook Pro — and Xcode now requires Monterey. This will become crucial at the beginning of June with the new WWDC Xcode beta. The specs of my new MacBook Pro: 16-inch screen, M1 Pro, 16 GB RAM, 1...
I just bought a new MacBook Pro, because macOS Monterey doesn't support my 2014 MacBook Pro. I'll blog in more detail about the new MacBook Pro later, but I want to mention something very odd that I quickly discovered: there was an empty AppleInternal folder in the root / folder of Macintosh HD. This was visible in Finder. The /AppleInternal...
Thanks to Mactracker for maintaining historical lists of Mac models and prices. The Mac Pro was introduced in 2006 at a base price of $2499. However, the Mac Pro was effectively the Intel successor to the PowerPC Power Mac. The computer case design was introduced in 1999 with the Power Macintosh G3 and remained mostly the same in fundamentals...
App Store Connect is the web site that members of the Apple Developer Program use to manage their App Store apps. I check it daily to see yesterday's sales numbers (live App Store sales numbers are haphazard at best and have stopped working entirely the past week) and to check for new App Store user reviews of my apps. Inexplicably, Apple...
"If you want sideloading, then you can just buy an Android phone." This is an ubiquitous response to the request that Apple unlock iPhone and allow installation of software from outside the App Store (which has always been possible on the Mac). It reminds me of the "America, love it or leave it" response to criticism of US government policies....
Misinformation from… Stephen Fry? February 22 2022 by Jeff Johnson Support this blog: StopTheMadness, Tweaks for Twitter, StopTheScript, Link Unshortener, PayPal.Me The world-famous Stephen Fry tweeted yesterday about my Safari extension Tweaks for Twitter. Under most circumstances I'd be thrilled if someone with over 12 million followers tweeted...
How to make a home page bookmark to Twitter in Mobile Safari February 3 2022 by Jeff Johnson Support this blog: StopTheMadness, Tweaks for Twitter, StopTheScript, Link Unshortener, PayPal.Me A customer of my Safari web extension Tweaks for Twitter asked me how to add a bookmark to their iOS home screen to open Twitter in Mobile Safari. The Add to...
Whenever I install a new version of macOS, I always disable Siri in the setup screen. In fact I always disable Siri on my iOS devices too. I have no interest in Siri, and I don't want my devices to phone home to Apple with so-called "anonymous" data that always turns out to be less anonymous than claimed. I expected that the OS would respect my setup screen choice, and indeed if I look at the Siri pane in System Preferences, everything looks disabled.
Apple made a breaking change to Safari extension preferences storage in iOS 15.2 and iPadOS 15.2, which were released to the public yesterday. I believe but haven't confirmed that this breaking change was also made in Safari 15.2 for macOS, which was included in yesterday's Monterey update. I assume that Safari 15.2 is forthcoming for macOS Big Sur and Catalina too, though for some reason it hasn't yet been released (despite the 0day security vulnerabilities already announced in the release notes).
My Safari extension StopTheMadness has a ton of features, which is great! Except when it's not. One downside to all those features is that an individual feature can get overlooked or forgotten. One such feature is "Show video controls", included with StopTheMadness for 2 years on macOS and since the beginning (September) on iOS. When this website option is enabled, StopTheMadness replaces the web site's custom video controls with Safari's native video controls, including picture-in-picture, full screen, AirPlay, and the timeline scrubber! It works not only on YouTube but on almost every site on the web with custom video controls.
As a Safari extension developer, I run into a lot of Safari bugs. A week ago I wrote about a bug where Safari forgets your history. This week I'm writing about a different bug. The bug was reported to me by one of my customers, as many bugs are, including last week's. Technically, it was more of a feature request than a bug report: the request was for my extension to "stop the madness". The madness in this case is Safari background tabs spontaneously coming to the front again, an obviously undesirable behavior. The initial report was for an obscure (to me) web site in New Zealand, but then I asked around, and someone said it also happened on ESPN, which is not so obscure (to me).
Clicking a link in a web browser changes the URL, and if you look at the browser's history after clicking, you'll see both the old URL and the new URL. The URL can also be changed programmatically, using the JavaScript Location API. After a new location is assigned in JavaScript, you should also see the old URL and the new URL in the browser's history. You should, and you do in Chrome and Firefox. But not in Safari! For some reason, Safari forgets the URLs. This bug appears to be many years old: it occurs in the latest version 15.1, and it occurs in the oldest version that I could test, Safari 11 on macOS 10.13 High Sierra. You can reproduce the bug by simply clicking the button below. The button runs a little script to change the location from my blog to my business web site.
According to Apple's API documentation, the function DNSServiceNATPortMappingCreate "Requests a port mapping in the NAT gateway, which maps a port on the local machine to an external port on the NAT." This function has been available to developers for more than five years, and it continues to work fine on macOS 11.6.1 Big Sur. It's not marked as deprecated in the documentation or in the framework header files from the macOS 12 SDK. However, the function simply doesn't work on macOS 12 Monterey and never has. I filed a bug in Apple's Feedback Assistant on June 8, the day after we got the first developer preview of Monterey at this year's Worldwide Developers Conference. I know of several other developers who also filed the same bug. Yet almost 5 months later, with Monterey having been released already to the general public, DNSServiceNATPortMappingCreate still doesn't work. I've heard that the bug hasn't been fixed in the macOS 12.1 beta either. Any software that relies on DNSServiceNATPortMappingCreate is out of luck on Monterey.
For background to this post, you can read yesterday's Apple vandalized my icon in the latest betas and The Safari extension blues from a few weeks ago. In this post I want to document the mass confusion and dislike over Safari extension toolbar icon tinting, which started with Safari version 14 in 2020, continues to the present, and was just made worse in the Safari 15.1 beta.
A few weeks ago I wrote a blog post called The Safari extension blues, in which I described how Safari tints many extension toolbar icons with the system accent color, by default blue, and how my own StopTheMadness avoids the tinting. This blog post is a sequel, so if you haven't read the previous one yet, I hope that you'll go back and read it now for essential context. Don't worry, it's fewer than 1000 words, interspersed with pretty (and ugly) pictures.
For the past several days at least, Google search results have not included AMP links on iOS 15, but they still include AMP links on iOS 14. I've determined that Safari's User-Agent makes the difference. (You can spoof the User-Agent on iOS using the Safari web inspector on macOS.) Here's my iPhone's User-Agent:
StopTheScript is my new Safari extension for iOS 15 and iPadOS 15 that stops all JavaScript on your selected websites! It comes just two weeks after I brought my Safari extensions StopTheMadness and Tweaks for Twitter to iOS and iPadOS. StopTheScript is the only Safari extension in existence now that stops inline JavaScript on the web page as well as externally loaded JavaScript. Did you know that Safari content blockers can't actually block inline JavaScript? There's a demo you can test the StopTheScript website.
Answer me these questions three. What is your name? What is your quest? What is your favorite color?
Yesterday Apple released iOS 15 and iPadOS 15 with a great new feature: Safari extensions! On my iPhone running iOS 15, when I select "More Extensions" in Safari Extensions Settings, it goes to the Safari Extensions page in the iOS App Store.
A month ago I ran into an obscure Google Chrome bug on macOS that caused the "All cookies and site data" page in Chrome settings (chrome://settings/siteData) to load very slowly. You can see this page if you open Preferences, select "Privacy and security", "Cookies and other site data", and then "See all cookies and site data". I filed a bug report with Chromium's issue tracker. Since then, some members of the Chromium team have been trying to track down the cause of the bug, a normal and boring process. However, this week I got an update on the issue that was shocking to me:
I ran git status on a newly created, very small repository, but the command took more than 10 seconds to finish. This was highly unusual, as git status is mostly instantaneous for me. Indeed it was instantaneous the next time I ran it on the same repository. Puzzled, I could only think of one thing out of the ordinary: I had just rebooted my Mac. So I tried rebooting again, and then the issue occurred again!
Twitter inexplicably changed the color purple on their website today. It seems they also changed pink/red, but I'm going to focus on purple, because that's my Twitter theme color (and my favorite color, because Prince). You can set your theme color by pressing the "More" button in the Twitter left sidebar and selecting "Display" in the popup menu.
On macOS High Sierra there was a system preference "Use dark menu bar and Dock":
Since I released my Safari extension Tweaks for Twitter three months ago, I've received a number of bug reports from customers saying that the extension doesn't appear in Safari. And when my app calls the API [SFSafariApplication showPreferencesForExtensionWithIdentifier: completionHandler:] to show the extension in Safari Preferences, there's an error "SFErrorDomain error 1". This issue never happened with my other Safari extension StopTheMadness, which is three years old. The two extensions use different Safari extension API: Tweaks for Twitter is a Safari web extension, a newer API, whereas StopTheMadness is a Safari app extension, an older API. I've never been able to reproduce the issue with Safari web extensions myself until yesterday, so now I have more details to share. I suspect the reason I can now reproduce it is that I recently updated to Big Sur.
I bought my first Mac, an iMac G4, in 2002. It came installed with Mac OS X 10.1 Puma, and I've been installing minor and major Mac OS X and macOS updates ever since, with the one exception of Mac OS X 10.7 Lion, which in my opinion was the worst Mac OS version ever (before now). My current machine is a 2014 MacBook Pro, which I had updated from Mavericks through Mojave. I did skip macOS 10.15 Catalina, however, which I've heard was very buggy, and I had been holding off as long as possible on macOS 11 Big Sur, which I've seen is very ugly. Ultimately, though, I couldn't wait any longer, because I need to run the latest Xcode beta in order to develop Safari extensions for iOS, and the latest Xcode beta requires Big Sur, so I finally decided to update to Big Sur on Saturday. This was a disaster.
My Twitter account has been mistakenly locked for the 4th time. This morning, Craig Mod wrote a tweet about YouTube.
I don't understand why programmers — who could theoretically write their own blogging engine — write on Medium. There's not even a need to roll your own system, because a number of off-the-shelf options already exist. WordPress, anyone? Anyway, I usually try to avoid clicking on medium.com links, but occasionally there's a Medium article that I don't want to miss. For example, I read one today about the Apple Security Bounty program. That Medium article, though important, is not the subject of this non-Medium article. The subject is the awful Medium user interface and how to make it less awful. If you want to see how awful it is, try to select and copy some text from the linked article. Go ahead, I'll wait… forever.
I'm working on bringing my Safari extensions StopTheMadness and Tweaks for Twitter from Mac to iOS, and it's progressing well! During this process I've noticed that there are some platform-specific differences between Safari iOS and Safari Mac extensions, as indeed there are between Safari Mac extensions and Google Chrome extensions, even though they all use the same cross-platform Web Extension format. (There's an older Mac-specific Safari app extension format, but that won't be available on iOS.) One easily noticeable platform-specific difference is the extension icons. Safari unfortunately tends to eschew the use of color now: you can see that all of Safari's built-in toolbar items are grayscale. If you're porting your Chrome extension to Safari Mac, you may notice that your toolbar item suddenly seems out of place and conspicuous; it's almost like landing in Kansas after having been to the land of Oz. Ironically, the Safari toolbar itself gets color in macOS Monterey, but not the toolbar items.
I'm working on StopTheMadness for iOS, and I ran into my first bug already. The bug involves the Safari setting Preload Top Hit, which I blogged about recently. I encourage you to disable Preload Top Hit, but unfortunately that setting is enabled by default in Safari on both iOS and macOS, so my extension can't avoid it. The bug is that Safari's Preload Top Hit breaks run_at document_start for injected content scripts in web extensions.
Before I (pre)announce the big news, a brief macOS update: I've done preliminary tests of my Mac App Store apps — StopTheMadness, Link Unshortener, Tweaks for Twitter, Underpass — on the developer beta of macOS 12 Monterey, and they all seem to work fine. My free app Stop The Mac App Store also works on Monterey. I'm not expecting compatibility issues with my Mac software. I'll continue to test on Monterey during beta period. If you experience any issues with one of my apps, please contact support.
By default, "Preload Top Hit in the background" is enabled in the Search tab of the Preferences window in Safari for Mac. Do yourself a favor and disable it, because the downsides outweigh the small upside.
Six months after the Mac OCSP appocalypse, here we go again, and here I go again. Back then I discovered that the trustd process was having trouble connecting to ocsp.apple.com, an issue temporarily solved by preventing connection attempts to that domain (for example in Little Snitch). Yesterday I started noticing another issue with trustd, but this time the issue was a little different: very high CPU usage. I've heard from several other people who started noticing the same issue yesterday too, one of whom helpfully referred me to this reddit thread with even more reports. On investigation, I found that the nsurlsessiond process was connecting to the server valid.apple.com, and immediately afterward trustd CPU jumped from 0% to 100%. It seems that the issue can be temporarily solved by preventing nsurlsessiond from connecting to valid.apple.com. You may have to reboot or force quit trustd to get its CPU usage back to normal. It's important to note that this is only a temporary workaround to the CPU usage problem; trustd is an important macOS system process that checks certificate validity and revocation status, so you probably don't want to block valid.apple.com forever.
Safari version 14 for macOS, released last year, added support for the cross-platform Web Extensions API. The intention was to make it much easier to port your Chrome extensions to Safari, by allowing you to use the same code on each platform. (This applies to Firefox extensions too, but I'm going to focus on Chrome, because that's where the main interest seems to be for Safari ports.) In the ideal case, your Chrome extension's code will "just work" in Safari, no changes required. Believe it or not, even chrome.* JavaScript API calls work in Safari! But there's a catch. You knew there'd be a catch. Or several catches. In this blog post, I'll give an overview of the issues you may face in porting your Chrome extension to Safari.
Today I released StopTheMadness version 21 in the Mac App Store. StopTheMadness is only 3 chronological years old, but software versions are like dog years. I just wanted to highlight some new features here, because most features in my web browser extension tend to be invisible. You wouldn't even know about them unless you read the release notes. And who does that? "Bug fixes and performance improvements."
On April 13 I submitted Link Unshortener 7.0 to App Store Connect for review. It was approved with no issues, and I released the update in the Mac App Store the next morning. This was the sixteenth release of Link Unshortener. By pure coincidence that I'm just realizing now, Link Unshortener 7.0 shipped exactly one year after Link Unshortener 1.0. The update added a great feature worthy of the anniversary, but it became clear that the new feature needed refinements, so I submitted another version to App Store Connect three days later. While I was asleep that night, my submission went into review and was rejected. In the morning I read the unpleasant news:
If NSURL invites you to a party, you should pass. Why? Because NSURL parties are passé. To be more specific, NSURL is based on an obsolete RFC. (Note: RFC is an acronym for Read the F-ing Commandment, while NS is an acronym for No Swift.) The obsolescence of NSURL is all explained in the class documentation for NSURL.
This isn't a late April Fools joke. (My April Fools joke that I got hired by Apple as a Swift Evangelist backfired with a profusion of congratulations.) This blog post is a kind of follow-up to some previous blog posts. Last month I wondered what's the best way to distribute Mac apps without notarization, and I decided that the best way was downloading with curl directly to the Applications folder. Unlike web browsers, curl does not add the com.apple.quarantine extended attribute to downloaded files. Still, this method is not ideal, because the app developer has to send users to the scary place: the command line! So I've continued to wonder if there's a relatively simple way to do it with a graphical interface. (If you think you can "just right click", well no, that's not quite how it works.) And then it finally hit me like a brick of gold wrapped in a lemon: I already knew how to remove the quarantine with a GUI, because this was my Mac sandbox escape! If you recall, a year ago I showed how to escape the sandbox by opening a maliciously crafted executable in TextEdit and then telling TextEdit via AppleScript to save the executable file. This causes the quarantine to be removed from the executable, because TextEdit has the special com.apple.security.files.user-selected.executable entitlement. I never received a bug bounty from Apple, and as far as I can tell this sandbox escape still exists in Big Sur. Which is actually good news for us right now, because we can use it to distribute Mac apps! For your enjoyment, I've created an example, which I call Gatecrasher:
What's wrong with this screenshot? (It was taken on a non-retina monitor, but other than that…)
Months ago I noticed something strange in the Little Snitch Network Monitor: Safari was still connecting to web sites after every window had been closed. At the time, I thought this was just a Safari bug. I brought the issue to the attention of some Safari engineers, who I had hoped would look into it. Since then, Safari has seen several software updates, and recently I remembered to check again to see whether the issue was resolved. Unfortunately I could still reproduce it, so I decided to investigate further. To my horror, I discovered that Chrome and Firefox were doing it too. That's too much a coincidence to be a bug, right? Could it be that web browsers are keeping open connections after windows are closed on purpose? If you don't have Little Snitch installed on the Mac (you should!), you can still see the open (ESTABLISHED) connections using the lsof (list open files) command-line tool in Terminal:
In the past couple of days, news sites such as ZDNet and iMore have reported that macOS can display a notification advertising Safari when you first launch Microsoft Edge. It turns out that this "feature" actually appeared first in Mac OS X 10.10 Yosemite, as described in an old blog post by Daniel Aleksandersen, an engineer for the web browser Opera. The Safari advertisement can occur with any alternative web browser, such as Opera, not just with Microsoft Edge. Ironically, it can occur even with Apple's own Safari Technology Preview! I've discovered reliable steps to reproduce the advertisement, using the information from Aleksandersen's blog post.
Sometimes a developer needs to send a Mac app to a user for testing, and in that case it's a pain to upload the app to App Store Connect first and wait for Apple to notarize the app before you distribute it. Another problem is that notarization requires apps to enable the hardened runtime. As I explained in a previous blog post, sandboxing and the hardened runtime are two independent technologies, and while the App Store requires apps to enable sandboxing, it doesn't require apps to enable the hardened runtime. Thus, if you normally distribute your app exclusively in the Mac App Store, the app might not have enabled the hardened runtime, and you won't be able to notarize the app for distribution outside the Mac App Store, which you may discover to your frustration at the last minute. (Needless to say, TestFlight for Mac doesn't exist yet, sigh.)
macOS 11 Big Sur has a bug that prevents some apps from appearing in the "Default web browser" menu in the General pane of System Preferences, which makes it difficult to set one of those apps as your default web browser. My own Link Unshortener is affected, among many others. I blogged about this bug two months ago. I'm told that the bug still exists in the latest 11.3 beta versions, unfortunately, so I'm pessimistic about the prospects of a fix coming from Apple. Therefore, I've decided to take matters into my own hands and write an app to change your default web browser on Big Sur. This new app is named "Default web browser". (There are only two hard things in computer science: changing your default web browser and naming things.)
The Search Preferences in Safari for Mac contains a list of search engines, such as Bing, DuckDuckGo, and Google, from which you can pick one as your default search engine. But what if you want to use multiple search engines in Safari? It turns out that you can! The same preference pane also contains a little known feature, Enable Quick Website Search.
A couple months ago I wrote about Mac App Store updates failing on Mojave. This issue continued for a while after my blog post, but eventually Apple seemed to resolve it. Temporarily. Unfortunately, a very similar issue has arisen recently. Some Mojave users say that this issue was caused by installing Security Update 2021-002, which was released on February 9. Other Mojave users say that the Security Update was just a coincidence in time. I can't say definitively one way or another, but I can say definitively that the issue currently affects me (I did install Security Update 2021-002) and many other Mojave users. Apple's support community discussions are full of reports of App Store failures. There's no longer a "cancelled" error message in App Store app, like there was back in December. Instead, the App Store progress spinner simply continues spinning, and the app never downloads. (I can tell that the app download never starts, because I have Little Snitch installed.) This issue affects both app updates and new app installs, making both fail, no matter how many times you try.
I was trying to build my app StopTheMadness, which I had been building successfully in Xcode for years, but suddenly the build started failing with a mysterious code signing error. Argh!
I know what you're thinking: there's a wrong way to delete Xcode's DerivedData? It turns out, yes, there is! The good news is that manually moving the DerivedData folder to the trash from Finder is the right way, or a right way. The bad news is that rm -fR from the command-line is the wrong way. To see why, we need to look at another command-line tool, hidden deep within your system:
Have you ever been annoyed that Mac App Store pages in Safari automatically open App Store app? Would you like to stop that from happening? Good news, now you can! I've just released a free open source Mac app called Stop The Mac App Store that allows you to stop Safari (and Safari Technology Preview) from opening the App Store app.
macOS 11 Big Sur has a bug that prevents some apps from appearing in the "Default web browser" menu in the General pane of System Preferences, which of course makes it difficult to set one of those apps as your default web browser.
In its relentless zeal to release major macOS updates every year, Apple is leaving its users behind. Not just behind in their macOS versions but also behind in their app versions installed from the Mac App Store. Many macOS Mojave users, including myself, have experienced frequent failures of App Store to update their installed apps. Whenever this occurs, App Store shows the completely unhelpful error message "cancelled".
Apple has published AppKit release notes for macOS Big Sur 11 and for macOS 10.14 but strangely not for macOS 10.15 Catalina. Thus, it's difficult to determine what changed in AppKit for Catalina. I have discovered one thing that changed: the shadowOffset implementation of NSShadow. Curiously, the API documentation for shadowOffset is now shared between AppKit and UIKit.
Today I'm disclosing a macOS privacy protections bypass. I discovered that an application can use the venerable Unix command-line tool "ls" (list directory contents) to bypass both TCC (Transparency, Consent, and Control) and the sandbox, enabling unauthorized access to file metadata in directories that are supposed to be protected. This issue remains unaddressed in the latest public versions of Big Sur, Catalina, and Mojave, and is therefore, in one sense, a zero-day. Here is the timeline leading to my disclosure:
This blog post describes a few things I found while "adapting" my AppKit apps for macOS 11 Big Sur. Apple has documented some changes in its AppKit Release Notes for macOS Big Sur 11, but these are not comprehensive. My blog post is not comprehensive either, but it does go beyond Apple's release notes. I should also mention the helpful site macOS Big Sur changes for developers, which also goes beyond Apple's release notes.
As a Safari extensions developer, I'm becoming frustrated with the quality of Safari for Mac. It has too many bad bugs, and they're causing problems for me, even costing me money. For example, there's a bug introduced over nine months ago, which I blogged about before, that prevents Safari users from enabling the extensions they've installed. This bug still exists in Catalina and Big Sur. When the bug first appeared, enabling extensions failed silently, but then later Apple added a (mostly useless) alert on failure, without actually solving the problem. Customers email me mystified, and I even randomly experience the problem myself, since I frequently need to enable my extensions for testing. A few months ago I blogged about a bug in Safari's WebExtensions API that was preventing me from releasing a new extension I was working on. That bug, which is a showstopper for me, is still not fixed either, not even in Safari Technology Preview, much less Safari.
On Thursday, the day that macOS 11 Big Sur was released, Apple's Developer ID Online Certificate Status Protocol (OCSP) service went down. This seems to have been part of a larger outage affecting a number of Apple services, as indicated by their System Status. When you launch a Mac app, macOS may check with Apple's Developer ID OCSP to see whether the app developer's code signing certificate is revoked. Since 2012, macOS (then known as Mac OS X) has required that all apps downloaded from the web (outside the Mac App Store) be signed with a valid Developer ID certificate, issued by Apple to developers. The purpose of Developer ID, according to Apple, is to prevent the spread of malware; if Apple discovers that a developer has distributed malware, Apple will revoke that developer's code signing cert, and then macOS will prevent any software signed with that cert from launching, thus protecting Mac users. Unfortunately, if there's an internet connection problem involving the Developer ID OCSP, that can also prevent Mac apps from launching. For several hours on Thursday, Mac users around the world experienced extreme slowness when launching their installed apps. It's possible that millions of Macs were affected by this OCSP problem, a major if short-lived computing disaster. Many Mac users, completely unaware of why their apps wouldn't launch, feared that there was a problem with their operating system, or even with their hardware.
Last week, Mac users with HP printers were unable to print or run their printer software, because HP's code signing certificate was temporarily revoked. In this blog post I'll talk about how this works from a technical perspective, and clear up some misconceptions about the situation. Software distributed outside the Mac App Store, such as a printer driver from HP, is signed with a Developer ID code signing certificate. This certificate is issued by Apple's Developer ID Certification Authority (CA). There's a different CA, the Apple Worldwide Developer Relations Certification Authority, that's used for Mac App Store development. Information about Apple certificates and CAs can be found on the Apple PKI (Public Key Infrastructure) page. You can use the codesign command-line tool to see the certificate used to sign an app. For example, if you have my own app StopTheNews installed, use this command:
In Google Chrome's "Cookies and site data" settings, accessible via the Preferences menu item or directly with chrome://settings/cookies in the address bar, you can enable the setting "Clear cookies and site data when you quit Chrome". However, I've discovered that Chrome exempts Google's own sites, such as Search and YouTube, from this setting.
How do you pronounce GIF? I would claim that it's pronounced like "Jeff", but that's not important. What if you don't want to pronounce or indeed see animated GIFs? There's a preference "Reduce motion" in macOS System Preferences, Accessibility, Display, but for some reason this preference doesn't apply to animated GIFs. Fortunately, there's a workaround if you prefer not to display GIFs in Safari: use a style sheet. If you open Safari's Preferences window to the Advanced tab, you can set your own .css file as the style sheet. Here's some sample CSS that should hide GIFs on web pages.
In an earlier blog post, I explained why you can't "just right click" to open an unsigned app downloaded on macOS. It's not as simple as that. But can we make it simpler? When you download a file from the web, from email, or from an instant message, macOS "quarantines" the file. In technical terms, the com.apple.quarantine extended attribute is added to the file. If you attempt to open a quarantined app, macOS Gatekeeper checks whether the app has been validly code signed and notarized. If the app fails this check, then Gatekeeper prevents the app from opening. However, if an app is not quarantined, then opening the app bypasses the Gatekeeper requirements. Is there a simple way to remove an app from quarantine?
This is a follow-up to the article Enabling the Debug menu in Safari 14 on Big Sur and Catalina by Dan Moren. In the past, you could enable the hidden Debug menu in Safari by using the command defaults write com.apple.Safari IncludeInternalDebugMenu -bool true in Terminal app. However, Dan discovered that this no longer worked for him, and he was forced to manually edit a plist file in order to enable the Debug menu. So what happened here? This is the question my blog post will answer.
Yesterday Apple released Safari 14 for macOS Catalina and Mojave. This may be surprising, if you weren't expecting Safari 14 until macOS Big Sur, but in retrospect, last year Apple released Safari 13 for Mojave and High Sierra before Catalina, and the previous year Apple released Safari 12 for High Sierra and Sierra before Mojave, so we should have known that Safari 14 was coming "early". Apple actually releases major macOS Safari updates simultaneously with major iOS updates (such as iOS 14 yesterday), because iOS also contains major Safari updates. The iOS and macOS versions of Safari share code — and thus security vulnerabilities! — so Apple has to release security fixes on both platforms simultaneously, otherwise one platform's update would zero-day the other platform.
Earlier this year I wrote about how Gmail hijacks your link clicks, swapping the visible URL with a tracking URL hidden in the data-saferedirecturl attribute of the HTML anchor element. Fortunately, my browser extension StopTheMadness protects you from this Gmail "clickjacking". I don't use Facebook, so I hadn't noticed, but a StopTheMadness customer reported a similar problem happening there. On investigation, we found that links in Facebook DMs were using the data-lynx-uri attribute to hide an https://l.facebook.com/l.php tracking URL.
On August 17, Epic Games filed a motion for a temporary restraining order against Apple Inc. Here's an excerpt from Epic's proposed restraining order:
In 2012, Apple added Gatekeeper to Mac OS X (now macOS). When you try to run Mac software downloaded from the internet, Gatekeeper checks whether the software was signed with a valid Developer ID certificate. If not, then Gatekeeper refuses to run the software. Over the years, Gatekeeper has become more strict, recently adding a notarization requirement. On macOS Catalina, Gatekeeper not only checks whether the software was signed by a valid Developer ID certificate, it also "phones home" to check whether Apple has notarized the software, again refusing to run it if the check fails. Mac developers must sign up for the Apple Developer Program, sign a legal agreement, and pay an annual fee of USD $99 plus tax in order to obtain a Developer ID code signing certificate and upload software to Apple for notarization.
The iOS App Store has been compared alternatively to a retail store and to a game console. Retail stores and game consoles are very different entities, so I'm not sure how, rhetorically speaking, both comparisons are allowed and considered apt. In any case, neither comparison is accurate, presently or historically. We know the origins of the App Store, because it originated only a dozen years ago. The model for the App Store wasn't retail stores. It wasn't game consoles. It wasn't even the smartphones that existed at the time. The model for the iPhone App Store was the iTunes Music Store. Where did the 30% App Store commission come from? No coincidence, 30% just happened to be the commission on songs in the iTunes Music Store!
A tweet by Tony Haile, CEO of Scroll, received widespread attention yesterday. Haile said,
A month ago I disclosed a macOS privacy protections bypass, and I offered a sample app for download that demonstrates the issue. Unfortunately, it turns out that the app had a little bug. In applicationDidFinishLaunching it calls CFPreferencesSetValue(KeepsWindowsOpenPref, kCFBooleanTrue, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost), and in applicationWillTerminate it calls CFPreferencesSetValue(KeepsWindowsOpenPref, kCFBooleanFalse, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost), where KeepsWindowsOpenPref = CFSTR("NSQuitAlwaysKeepsWindows"). The bug is that kCFPreferencesCurrentHost should have been kCFPreferencesAnyHost.
A couple weeks ago I introduced my new browser extension StopTheSwift, which forces Apple's online developer documentation to show Objective-C API instead of Swift. Since then, I've received a report that StopTheSwift wasn't working right on certain pages, such as https://developer.apple.com/documentation/uikit/uipasteboard/detectionpattern. StopTheSwift 1.0 simplemindedly added ?language=objc to the end of documentation URLs, but it turns out that sometimes there are different URL subpaths for Swift (uipasteboard/detectionpattern) and Objective-C (uipasteboarddetectionpattern).
This is a note for users of App Store Connect and StopTheMadness. Since the App Store Connect redesign last month around WWDC, there may be an incompatibility between drag and drop reordering of screenshots and the StopTheMadness "Drag and drop" website option. So if you're having any trouble with that, just create new custom website options for appstoreconnect.apple.com and disable the "Drag and drop" option. More instructions are on the StopTheMadness support page. I'll see if I can fix the issue, but it's a bit difficult to test at the moment, because I'd have to create a new app version in App Store Connect.
Many of the API pages in the Apple Developer Documentation have a language selector that allows you to choose whether to see the API in Swift or Objective-C. Swift is the default:
If you enter diskutil list in Terminal, you can see that your Mac's internal disk has a recovery volume, and if you hold down ⌘r at boot, your Mac boots into the recovery volume. If you've installed multiple macOS boot volumes, either on your Mac's internal disk or on an attached external disk, you may also have multiple recovery volumes. When you hold down ⌘r at boot, your Mac selects the recovery volume associated with the Startup Disk selected in System Preferences, so you can change the recovery volume by changing the Startup Disk. Starting with macOS Catalina, the recovery volume requires a login for some reason. According to Apple's support documentation, "You might be prompted to enter a password, such as a firmware password or the password of a user who is an administrator of this Mac." The word "might" seems a bit misleading: you will be prompted to enter a password on macOS Catalina and later (later AKA Big Sur). The big (Big) question, though — and the purpose of this blog post — is, the password from which volume?
JavaScript in a web browser is mostly invisible, for better or worse. When my paid extension StopTheMadness is working, you mostly don't notice it, and that's the point. My good JavaScript in the extension prevents bad JavaScript in web pages from affecting users. The value of StopTheMadness is obvious when you install it and some annoying web behavior immediately stops. However, the ongoing value of the extension is less obvious, since it Just Works™, as the saying goes. This is not a worry for StopTheMadness customers, who seem quite happy according to feedback and reviews, but it is a worry for me as the developer of the extension, and a user. In fact it started as a personal project for my own use. It just works for me too, and it has for a long time, so the question is how can I market the extension if I can't explain to people what specific problems it solves? The irony is that my problems are already solved. I've often joked that I should randomly disable StopTheMadness to show people what they'd miss without it. (Don't worry, I won't actually do this!)
Today I'm disclosing a macOS privacy protections bypass. (You may recall that I disclosed another one last year.) The privacy protections system (also known as TCC: Transparency, Consent, and Control) was introduced in macOS Mojave, and one of its purposes is to protect certain files on your Mac from access by unauthorized apps. I've discovered a way for an unauthorized app to read the contents of protected files, thus bypassing the privacy protections. This issue exists in Mojave, Catalina, and the Big Sur beta. It remains unaddressed and is therefore, in one sense, a zero-day. Here's the timeline leading to my disclosure:
This is the third part to what is now a three part series on disassembling system libraries on macOS 11 Big Sur. Part 1 explains how to extract the system libraries from the dyld shared cache, and Part 2 explains some difficulties in disassembling Objective-C in those extracted libraries. Part 3 will provide a solution to those difficulties!
This is a follow-up to my blog post yesterday Extract the system libraries on macOS Big Sur, in which I explained how to extract the system libraries from the dyld shared cache. Although you can successfully disassemble these extracted libraries, there's still a problem: the otool command-line tool fails to understand many Objective-C references in the disassembly. Let's take a look at an example from my favorite framework, AppKit. The following is from the implementation of the -[NSApplication init] method. In order to call [super init], the implementation has to get the NSApplication Objective-C class. For convenience I use my own command-line tool riptool, which is a wrapper around otool that resolves rip-relative addresses.
According to the macOS Big Sur 11 Beta Release Notes, "the system ships with a built-in dynamic linker cache of all system-provided libraries. As part of this change, copies of dynamic libraries are no longer present on the filesystem." If the libraries are no longer present on the filesystem, that makes it awfully hard to disassemble them! Fortunately, there are ways to extract the system libraries from the cache. One way is provided by Apple itself: the dyld_shared_cache_util command-line tool. Unfortunately, this tool does not come installed with macOS Big Sur. However, the tool is open source, so we can build it ourselves. You can download the dyld project from Apple Open Source. The latest version is a little behind, at macOS 10.15.3, but that works fine for our purpose. The download contains a convenient Xcode project. Don't bother trying to build all targets in Xcode, just build the dyld_shared_cache_util target. You'll need to make a number of modifications in order to build and run the target successfully. I'm assuming that you're building with Xcode 12 on Big Sur.
You may think that only Google is guilty of clickjacking search results, but DuckDuckGo is guilty too. Although the "crime" is not nearly as bad in this case, DuckDuckGo still uses JavaScript to intercept your link clicks, and there's no good reason for it. One consequence of this clickjacking is that your Safari browsing history gets messed up. Let me illustrate with an example. I searched for "StopTheMadness", clicked on the link for the product's home page, clicked on the link for the product's support page, and then opened Show All History in Safari:
Today I've released version 15.2 of my web browser extension StopTheMadness in the Mac App Store. This update contains a new website option called "Mouse movement". When this option is enabled, StopTheMadness stops sites from using JavaScript to track the movement of your mouse pointer (or trackpad pointer). One benefit of the new feature is that it protects your privacy. Some sites such as Facebook are notorious for tracking your mouse movements. Another benefit is that it stops some common website annoyances. For example, it stops the little popups from appearing when you hover over links on Wikipedia or when you hover over user accounts on Twitter. The new website option "Mouse movement" is available in all browsers supported by StopTheMadness: Safari, Firefox, Google Chrome, Microsoft Edge, and Brave.
This is a follow-up to Catalina is checking notarization of unsigned executables. In that blog post, I explained how I was trying to compare packet traces of app notarization checks with packet traces of (apparent) shell script notarization checks. The traces looked the same. The request packets even had the exact same number of bytes. The only problem with the comparison was that the requests and responses use https and are thus encrypted. Is there a way of decrypting them?
Today Apple released macOS Catalina 10.15.5, as well as Security Update 2020-003 for macOS Mojave and High Sierra. Apple also published support articles listing the security content and non-security content of those updates. In the latter article, at the end of "Enterprise content", there's a note about the softwareupdate command-line tool:
As reported by MacRumors and other media outlets, Apple issued hundreds (thousands?) of third-party app updates yesterday in the iOS App Store (but apparently none in the Mac App Store). These were not new versions of the apps submitted by the developers but rather re-releases of the current versions, modified somehow by Apple. (Apple itself must code sign all apps for distribution in the App Store.) It has been speculated that these new releases are to fix a recent issue plaguing iOS users that prevents them from opening their installed apps. Instead, they see an alert that says "This app is no longer shared with you. To use it, you must buy it from the App Store."
This is a follow-up to Allan Odgaard's excellent article macOS 10.15: Slow by Design. I want to talk specifically about the first section "Spawning a new Process", because there has been widespread misunderstanding of this. Odgaard provides a simple test to show that the first run of an executable is delayed while Catalina checks the executable's notarization status online. This occurs even for shell scripts, which cannot be code signed!
This is not an announcement of Link Unshortener for iOS. Unfortunately, it's the opposite. I did begin development, but I've determined that unless a pleasant surprise (miracle) occurs at WWDC next month, Link Unshortener for iOS is not a viable product, due to iOS API limitations.
I've noticed the Objective-C keyword __kindof in system framework header files, but I've never used it in my own code. What's the purpose of the keyword? Is it necessary? Is it useful?
The title of this article is tongue-in-cheek. I have no desire to stop Daring Fireball. Quite the opposite! I'm grateful that DF exists and thrives. But "Stop the [Thing]" has become a kind of personal brand. It's said that naming things is one of the hardest problems in computing, and that seems right, because my app names are becoming derivative: StopTheMadness, StopTheNews, and StopTheTwitter. Today I released StopTheMadness version 15.0 in the Mac App Store with a new feature: support for site-specific CSS in Safari's user style sheet! The inspiration for this new feature was none other than Daring Fireball.
Some people install the first party Twitter app on macOS Catalina in order to get push notifications — which Twitter doesn't enable anymore for third party clients — but otherwise have no wish to use the (crappy Catalyst) app. Nonetheless, when you visit a twitter.com web page in Safari when the Twitter app is installed, Safari "helpfully" suggests that you open the link in the Twitter app.
I have a Gmail account, but I always access it in Mail app, never in webmail, so I wasn't aware of some Google mischief until recently. I had previously written about how Google Search hijacks your link clicks and replaces the apparent URL with a tracking URL. It turns out that Gmail also does something similar.
My previous blog post disclosed a Mac sandbox escape. To save myself time and effort, I simply copy and pasted my original email to Apple Product Security. (After all, I'm not getting paid a bug bounty for my work!) This probably wasn't ideal for public consumption, because my email presumed a high level of knowledge on the subject possessed by Apple Product Security but not necessarily possessed by the general public. So I'm writing now to clarify a number of points that I feel have not been broadly understood.
This blog post discloses a sandbox escape on macOS. I reported the issue to Apple Product Security on December 19 2019, the day the Apple Security Bounty program finally opened. (I discovered the issue in August 2019.) Today I received an email from Apple Product Security saying "we do not see any actual security implications." I've heard this kind of response before — they don't see any security implications… until they do — but in any case I obviously won't be receiving a bounty for this issue, and I'm free to publish it, again letting the public judge for themselves whether there are security implications. To save myself time, I'm just going to copy and paste my original report:
I've written before about a caveat with NSFormatter. Now I'm writing about one again. I've discovered what I consider to be a bug in NSFormatter and NSTextField. One of the roles of a formatter is to prevent the user from entering invalid characters into a text field. For example, if you have a text field that is designed to take a number, you might limit entry in the text field to numerical digits. This is accomplished by subclassing NSFormatter and implementing the method isPartialStringValid: proposedSelectedRange: originalString: originalSelectedRange: errorDescription: to return NO when it detects invalid characters. However, I've discovered a situation in which that method returns NO, but the text field still adds an invalid character to its string value.
I've been working from home for a long time. Now that many of you have joined me in working without an office, will you also join me in working without a nib? You might ask why, and as luck would have it, my previous blog post in the "Working without a nib" series explained why! After why, the next logical question is how. In this blog post I'll talk about a subject that's always been particularly tricky in Cocoa: NSWindow memory management. When you work with a nib, NSWindowController "magically" handles NSWindow memory management. Of course, that just pushes the problem up to the meta-level, because nothing magically handles NSWindowController memory management. Anyway, when you work without a nib, you don't need NSWindowController. So how does NSWindow memory management work?
This blog post is a heads-ups to Safari extension users, Safari extension developers, and hopefully the Safari extensions engineering team at Apple about a bad bug in Safari with extensions and context menus. The bug is that if you have a Safari extension enabled, and the Safari extension has a context menu item (as many extensions do), then opening a context menu on a link can sometimes cause the link to open, as if you had just clicked the link instead of control-clicking. This bug was introduced recently; my suspicion is that started with the software releases on March 24, which included Safari 13.1 for Mac. I have filed a report (FB7666007) in Apple's official bug reporting system. The following are steps to reproduce on the latest versions of Catalina and Mojave with Safari 13.1 installed. (The bug also occurs with Safari Technology Preview 104.)
Today I've released a new app in the Mac App Store! The app is named Link Unshortener, and its purpose is to expand shortened web links.
This is a tip to help Xcode find the proper documentation for the methods you use in your source code. Apparently Xcode needs a lot of help. I had implemented some Foundation framework methods in my code, but I was having trouble getting the documentation in Xcode. Option-clicking on the method declarations popped up popups that just said "No Quick Help", and command-clicking on the method declarations did not show the methods in the Foundation framework headers but rather did nothing other than momentarily change the highlight color of the method declarations in my source code. You've probably experienced this phenomenon before. It's ever so much fun! In this case, however, I found a solution.
This blog post is not an April Fools joke. It addresses a serious documentation problem. There are millions of lines of Objective-C code in active use, and of course millions of Macs in active use. But how does a new developer work with them?
At long last, Underpass version 1.2.0 is now available in the Mac App Store and iOS App Store. Underpass for Mac was last updated in January 2019, and Underpass for iOS in December 2018. If you're not familiar, Underpass is a peer-to-peer file transfer and chat app with end-to-end encryption for complete privacy and security. Underpass is unlike any other chat app because it doesn't use a third-party service. The app is both a server and a client, so any two instances of the app running on a Mac or iOS device can make a direct network connection to each other, either on the internet or on a LAN, including ad hoc peer-to-peer wifi networks! You can use Underpass to exchange files and text between your own Apple devices or with another Underpass user.
In macOS 10.15.3, Apple introduced a bug that can prevent you from enabling or disabling Safari extensions. In order to enable or disable an extension, you must click the checkbox next to the extension in the Extensions pane of Safari Preferences. The support site for my own extension StopTheMadness has instructions and screenshots explaining how to enable a Safari extension, but under normal circumstances it's relatively easy. When the bug occurs, however, then clicking the checkbox does nothing: the checkbox doesn't get checked, and the extension doesn't get enabled either. This is a serious bug affecting many users and all Safari extensions by every extension developer. Unfortunately, the bug was not fixed in macOS 10.15.4, which was released yesterday, so we're still stuck with the bug for the immediate future. The purpose of this blog post is to raise awareness about the bug, for Safari extension users, Safari extension developers, and the Safari engineering team itself.
A couple of months ago I disclosed an issue I had discovered and reported to Apple Product Security: Safari runs disabled extensions. At the time, Apple Product Security felt that there were no actual security implications to this, which is why I went public. However, they seem to have had a change of heart after the publication of my blog post. Apple fixed the issue in Safari 13.1, released today, and credited me in the document describing the security content of Safari 13.1. Under "Additional recognition" at the end it says, "We would like to acknowledge Jeff Johnson of underpassapp.com for their assistance." That's me! So apparently there were security implications, as I argued.
During this unprecedented period of working from home, Zoom is unsurprisingly among the top 10 paid apps in the Mac App Store, currently #7.
Some friends have inquired how they can support me financially beyond buying my apps StopTheMadness and Underpass. These apps are one-time, upfront purchases, with no upgrade fees or subscriptions. I had hoped that my app sales would be sufficient, but my sales have never been great, and the current pandemic is causing a dramatic economic decline in most industries, including software. This decline in sales is affecting me and a number of other indie developers I know. Therefore, I've now decided to provide a public PayPal link for those who might be interested. If you've benefitted from my activities over the past few years — adding features to StopTheMadness, blogging about technical issues here, publishing free open sources apps such as StopTheNews and Bonjeff — and you wish to financially support those continued activities, you can now PayPal Me. If you don't want to, or can't afford it, that's perfectly fine, but if you do want to, and are able to afford it, I guess it's silly of me to turn down offers at this point.
You can use /usr/bin/otool -tV from the command-line to disassemble Mach-O files. If you don't know what Mach-O's are, they're like Krusty-O's only tastier and healthier. One problem with otool, however, is that it doesn't resolve rip-relative addresses. In the x86_64 (64-bit Intel) architecture, rip is the register that contains the instruction pointer. A rip-relative address is an address specified by an offset, either positive or negative, from the instruction pointer. For example, 0x99eac(%rip) is an rip-relative address in this disassembly:
This blog post attempts to give an overview of what happened to Safari extensions in the past few years, from the perspective of a developer (me) with many years of experience working on Mac apps and Safari extensions.
StopTheMadness, the beloved and highly rated Safari and Firefox extension in the Mac App Store, has added support for Google Chrome, Microsoft Edge, and Brave. That's five web browsers supported for one purchase! A one-time purchase, not a subscription. The new version 11.0 of StopTheMadness is released today and available now worldwide. It's fully compatible with macOS Sierra and later, including the current macOS Catalina.
Little Snitch is great at catching apps "phoning home". Much to my surprise, a couple of months ago Little Snitch caught a disabled Safari extension phoning home (where "home" was Amazon Web Services). In fact this extension had never been enabled in Safari. After further investigation I learned that on every launch, Safari runs every registered extension — that is, every extension that appears in Safari's Extensions Preferences — whether the extension is enabled or disabled.
You may have seen the Swift function fatalError() used in code samples, but in my opinion the function ought to be avoided entirely, especially in production code, because using the function exposes TMI in release builds. When fatalError() is called in a source file, the compiler writes the full system path of the source file into the compiled binary, for both debug and release builds, because the function is designed to print the source file path along with its log message. Anyone can see the file path by running strings or otool -tV on the binary from the command line. The output will be something like this:
I'm not a professional security researcher, I'm just an app developer. I don't know how security bounty programs work, as I've never participated in one until now. On August 8 at the Black Hat 2019 conference, Apple announced an expansion of their bounty program for security vulnerabilities. The previous, limited bounty program was by invitation only, and it covered iOS only, whereas the expanded bounty program would be open to anyone and cover all of Apple's operating systems, including macOS. I have over a decade of experience in Mac development, and I've discovered several security issues in macOS during that time, so Apple's announcement of a bounty program inspired me to look for more. Within a couple of months — before the release of macOS 10.15 Catalina on October 7 — I found a couple of issues to report.
When you open Safari's Extensions Preferences, you may see some scary warnings, such as "Can read sensitive information from webpages, including passwords, phone numbers, and credit cards on: all webpages" and "Can see when you visit: all webpages".
What happens on the web stays on the web, right? Unfortunately, wrong. We know about web cookies, which sound better than they taste. When you visit a web site in a browser such as Safari, the site may store bits of data called cookies on your disk. Cookies are often abused for tracking but remain a necessary evil to allow you to remain logged into web site accounts. What you may not realize is that cookies are just the tip of the iceberg. We're talking hundreds of megabytes or even gigabytes of iceberg, enough to put a laptop's disk underwater. I thought the purpose of a web browser was to browse the web, didn't you? If I wanted to browse my file system, I'd use Finder. For the purpose of this blog post I did browse my file system, and I'll tell you what I found.
Eight months ago I wrote an article about the true and false security benefits of Mac app notarization, in which I argued that the publicly touted benefits of notarization — revocation and malware scans — are bunk, but there was one true benefit — two-factor authentication. Now I must admit that I was wrong.
It's well known that if you drag a file from Finder and drop it into Terminal, the full path of the file will output in Terminal. The same behavior occurs with copy and paste too. This has always been a very convenient but innocuous operation… until macOS 10.15 Catalina. I've discovered that on Catalina, pasting a file from Finder not only outputs the file path in Terminal, it also invisibly and permanently grants Terminal access to the file, bypassing any macOS privacy protections!
This is a follow-up to my recent blog post about the hardened runtime, which was itself a follow-up to my earlier blog post about the hardened runtime. So you can call this a hardened runtime trilogy. Just don't call it a comeback. In episode III (Revenge of the Service), I wish to expand on something I said in episode II (Attack of the Contacts):
My friend Ilja Iwas had a question: if a Mac app enables the ENABLE_NS_ASSERTIONS build setting, why doesn't the app crash when it calls NSAssert in the applicationDidFinishLaunching: method of the NSApplicationDelegate protocol? Good question! Curiously, the app does crash when it calls NSAssert in the applicationWillFinishLaunching: method, so we have a bit of a mystery.
This is a follow-up to my earlier blog post as well as a response to a a blog post by the developers of GitFinder that was highlighted by Michael Tsai. Although GitFinder is distributed outside the Mac App Store, the developers nonetheless chose to sandbox it. The GitFinder app does not have the sandbox entitlement to access a user's Contacts (com.apple.security.personal-information.addressbook), but the GitFinder app does embed an xpc service with that sandbox entitlement. The xpc service accesses some information in the user's Contacts and passes that information back to the app. GitFinder does not currently enable the hardened runtime, but next year Apple will require all apps to enable the hardened runtime in order to get notarized for distribution outside the Mac App Store. The developers of GitFinder are upset because enabling the hardened runtime requires giving the Contacts sandbox entitlement to the app as well as to the embedded xpc service. Why is that necessary?
On February 9 I emailed Apple Product Security and reported a vulnerability that allows an app to bypass macOS privacy protections. I mentioned this the same day in a blog post. The vulnerability still exists in macOS 10.15 Catalina. Yesterday I learned that this vulnerability would not be eligible for Apple's Mac bug bounty program (because it was reported before the program was announced). Thus, I'm disclosing the vulnerability to the public today. Apple has had 8 months to address the vulnerability, and they've chosen not to address it. I believe that I've already gone above and beyond the duty of responsible disclosure by keeping my secret for so long. It's not even a particularly profound secret, for the vulnerability is hiding in plain sight, as you'll see.
On August 8 at the Black Hat 2019 conference, Apple announced that they were expanding their bug bounty program for security vulnerabilities. Apple's previous, limited bug bounty program was available only to Apple-selected security researchers, and it covered only iOS. The expanded bug bounty program would be open to anyone, and it would cover all of Apple's operating systems, including macOS.
This is an update to my post from last week Important Information Regarding the Safari Extensions Gallery, which described an email I received from Apple Developer Relations warning that the Safari Extensions Gallery will no longer be available in September 2019. I was expecting this to happen at the end of September, presumably when macOS 10.15 Catalina is released to the public. However, yesterday afternoon I received another email from Apple Developer Relations, just 8 days after the first email. The new email said that the Safari Extensions Gallery is no longer available. And indeed, the previous URL of the Safari Extensions Gallery https://safari-extensions.apple.com/ now redirects to the Mac App Store in Safari, while the URL completely fails to load in other web browsers such as Chrome and Firefox. The Safari Extensions Gallery is officially discontinued.
Yesterday afternoon I received an email from Apple Developer Relations titled "Important Information Regarding the Safari Extensions Gallery". According to the email, "the Safari Extensions Gallery will no longer be available in September 2019."
On macOS, an app can register to handle URL schemes. Web browsers such as Safari, Chrome, and Firefox register to handle the schemes for web pages, http or https. Non-browser apps may register to handle other URL schemes; for example, an email client may register to handle the well known mailto scheme. When a URL is opened in a web browser, and the browser itself cannot handle the URL scheme, the browser looks for another app to handle the URL. If there's a handler app for the URL scheme, then the browser will open the app and pass the URL along to that app. Thus, clicking a mailto:[email protected] link will open your email client with a new email addressed to Tim Cook.
Today I released StopTheMadness version 8.0 in the Mac App Store. There's one new feature: StopTheMadness can now stop Safari from autosubmitting login forms!
Today I released StopTheMadness version 7.1 in the Mac App Store. There's one new feature: StopTheMadness now stops web sites from detecting that you're in private browsing mode in Safari!
I'm happy to report that all of my apps seem to be fully compatibile with macOS 10.15 Catalina. This includes StopTheMadness, Underpass, StopTheNews, and Bonjeff.
My Twitter account has been locked for a third time. I have no idea why.
According to Apple's new App Store - Principles and Practices page, "We believe that what’s in our store says a lot about who we are." I hope that's not true, because the App Store is rife with scams. Apple says, "It’s our store. And we take responsibility for it." I know that's not true. If you do a little looking, it doesn't take long to find scammers in the App Store. I've done it. Has Apple done it? I haven't found evidence that Apple takes responsibility for the App Store.
Have you ever been annoyed that Safari on macOS 10.14 Mojave wants to open Apple News articles in News app instead of in Safari? Well no more! I've just released a new, free, open source Mac app called StopTheNews that stops Safari from opening Apple News articles in News app. Instead, StopTheNews opens the original article URL in Safari. StopTheNews also works with Safari Technology Preview, if that's your default web browser.
Exactly one year ago today, I released StopTheMadness version 1.0 in the Mac App Store. StopTheMadness has come a long way since then and is currently at version 6.1. (No apologies for version number inflation!) The app has gained some great new features, including a Firefox add-on to go along with the original Safari extension. It has increasingly emphasized protecting your privacy on the web, blocking tracking methods such as hyperlink auditing (anchor "ping"), invisible beacons, and uniquely identifying URL query parameters.
As I mentioned in my blog post Safari link tracking can no longer be disabled, the hidden preference chrome://flags#disable-hyperlink-auditing to disable hyperlink auditing had already been removed from the beta versions of Google Chrome. Today, Google shipped Chrome 74 to the public, and this hidden preference is now indeed gone for everyone. The change log for Chrome 74 includes the removal of disable-hyperlink-auditing from Chromium.
Almost everyone, including Apple, has painted a false picture of the security benefit of Mac app notarization. There is a true benefit, which I haven't seen anyone mention, but I'll discuss it here. On the other hand, the publicly touted benefits of notarization are bunk, in my opinion, and I'm going to debunk them in this post too. Most notably, I'll explain how the notarization malware scan is superfluous security theater, a mere marketing gimmick that I believe ought to be abolished because of the burden it places on legitimate developers.
My blog post Safari link tracking can no longer be disabled generated a lot of discussion and controversy. Eventually the WebKit project itself felt compelled to respond publicly with their own blog post. I won't respond to their blog post here, because I feel that my follow-up blog post Some thoughts on anchor ping already anticipated and addressed the arguments they made. I do want to talk about an additional form of tracking technology mentioned in the WebKit article: the Beacon API. Both WebKit and Mozilla admit that beacons were designed for tracking and analytics. Unlike anchor "ping", there was never a way to disable beacons in Safari… until today!
Last week I blogged about how Safari link tracking can no longer be disabled. Safari 12.1 removed a hidden preference that was the only way to disable hyperlink auditing, a method for tracking your link clicks via the anchor "ping" attribute. Coincidentally, Google Chrome also removed its hidden flag recently; in the Chrome beta versions you can no longer disable hyperlink auditing, though you can still disable it for now in the "stable" Chrome version. My blog post has sparked a lot of discussion on the web, and it looks like the Safari and Chrome teams are starting to be moved by the public pressure. If you want to keep up with the latest news about this subject, Michael Tsai's blog is a great resource, as always.
The iTunes Affiliate Program for apps paid registered Affiliates a percentage of app sales that resulted from links to the Apple App Store from the Affiliate's web site. The iTunes Affiliate Program still exists for music, books, movies, and TV shows, but Apple ended the program for apps on October 1 2018. Yesterday, six months later, I finally got paid the remaining balance owed to me as an iTunes Affiliate. Getting paid was an ordeal that took many emails from me to the iTunes Affiliate Program. I know that some developers still haven't gotten paid fully, so I hope this blog post helps them to recover their money.
This is a follow-up to my recent article Safari link tracking can no longer be disabled. I'm quite surprised that my complaining about a hidden preference in Safari has generated so much discussion on the internet. I'm also quite pleased, because I think it's important to draw attention to the privacy implications of the HTML anchor ping attribute and have a public debate about it. I've heard so many people say that they weren't even aware that anchor ping existed until they saw my article, so I'm glad to raise awareness.
HTML5 added a "feature" to the web called hyperlink auditing. You can read the specification from the Web Hypertext Application Technology Working Group (WHATWG). Hyperlink auditing is added to a web page via the ping attribute on an HTML anchor element (), i.e., a link. Here's a example, followed by the HTML code for a simple test page that implements it:
Yesterday I received a crash report for Bonjeff, my open source Swift app that shows you a live display of the Bonjour services published on your network. Since I'm (in)famous for my Objective-C advocacy, I wrote an open source app in Swift to demonstrate publicly that I can also write Swift. (Honestly, though, a Swift app has been more trouble than it's worth, but that's a blog post for another day.) The crash was in the CFNetwork function NetService.dictionary(fromTXTRecord:), which corresponds to +[NSNetService dictionaryFromTXTRecordData:] in Objective-C. The crash report stated that the problem was "value type is not bridged to Objective-C".
My Twitter account has been locked again. I don't even know what happened this time. It just seemed to happen randomly.
Good news, everyone! I finally got proper credit from Apple Product Security for the Mojave privacy protections bypass that was fixed in macOS 10.14.1 back on October 30, 2018. The Apple support page describing the security content of macOS Mojave 10.14.1 was updated on February 15, 2019 with my new CVE-2018-4468.
At the end of this blog post I'll provide an update to yesterday's blog post, but first and more importantly I want to report a new hole that I just found in macOS Mojave's privacy protections. This hole exists in every version of Mojave, including macOS Mojave 10.14.3 Supplemental Update released on February 7.
I found a bug in the new privacy protections of macOS 10.14.0, and that bug was fixed in macOS 10.14.1. I've already described the bug in a previous blog post. I support the requests for a Mac bug bounty program by security researchers such as Linuz Henze and Patrick Wardle, but I personally am not asking for a monetary bug bounty and never have asked for money in exchange for the bug report. (Though a bug bounty would be nice!) All I want is public credit for reporting the bug. To date, Apple Product Security has failed to credit me.
Have you ever heard of The Old Switcheroo? Google pulls that magic trick when you click on a search result link. Below is what it looks like when you hover over a search result link in Safari with the ⌘ key pressed just before you click to open in a new tab. Pay particular attention to the status bar at the bottom:
The most requested feature for StopTheMadness has been Firefox support. Today, you got it! StopTheMadness in the Mac App Store now includes a Firefox extension. This is a free update for current owners of the Safari extension. And for new customers, StopTheMadness for Mac remains at the same (too) low price. That's 2 (two) browser extensions for the price of 1!
Disclosure: As the developer of a (beloved, highly rated) Safari app extension, the contents of this blog post are relevant to my financial interests. (I'll write the obligatory Reddit/Hacker News comment in advance to save them the trouble: "Just a developer whining about Apple not featuring them more prominently. Why is this even news? Pointless." You're welcome!)
This is my last scheduled text view adventure. There may be more, but they're unscheduled. And let's face it, the best adventures are unscheduled. So stay tuned, the best is yet to come. Or not. If you need to catch up on my previous adventures, you can read Part 1, Part 2, and Part 3. There will be a quiz at the end of the universe.
Part 1 and Part 2 of my text view adventures were about NSTextView for Mac. Part 3 here and Part 4 in the future will be about UITextView for iOS. In Part 2 I wrote about how to handle pasting of arbitrary file types, including movies, into NSTextView. You might wonder how UITextView handles this. The answer is… not very well. On iOS 12, "Copy" is not even listed among the actions when you share a movie from Photos app. However, you can "Save to Files", and Files app will allow you to copy a movie file. If you want to allow users to save files "On My iPhone" in Files app, you need to add LSSupportsOpeningDocumentsInPlace and UIFileSharingEnabled to your app's Info.plist file.
When you download a Mac app from outside the Mac App Store and launch the app for the first time, macOS checks whether the app was signed with a valid certificate from a developer registered with Apple's paid Developer ID program. The macOS technology responsible for this verification is called Gatekeeper. On macOS 10.14 Mojave, Gatekeeper added a step to the verification: in addition to checking whether an app was signed with a Developer ID certificate, it also checks whether the app was notarized by Apple. App notarization requires that a developer submit the app to Apple for an automated malware scan, and if no malware is found, Apple notarizes the app; the notarization status is stored on Apple's servers, and a notarization ticket can be "stapled" to the app by the developer so that Gatekeeper can see the notarization when the app is launched. Every version of an app must be notarized separately, the notarization does not carry over to later versions. Apple has provided some documentation of Mac app notarization for developers and for end users.
In Part 1 of my multipart text view adventures, I wrote about an NSTextView memory management bug with attachments that could result in "zombie movies". Zombie movies are bad, m'kay. You don't want to see zombie movies. I explained how to make the zombies disappear, and I thought I killed the zombies, but later I realized that zombies are dead already, so killing them is fruitless. Who knew? It turns out that the zombies were merely in hiding, waiting to attack again. The only true way to avoid zombie movies is to never make them in the first place.
I'm planning to write a series of blogs posts about my recent adventures with text views, i.e., NSTextView and UITextView. The current plan is 3 parts. However, if the box office receipts are high enough, I may continue to milk the franchise indefinitely. This post, Part 1, describes a bug in NSTextView and how to work around it.
The relationship between the hardened runtime and sandboxing can be confusing to Mac developers, both because the hardened runtime is new and because it's not well documented by Apple. I'll attempt to explain the relationship here. App sandboxing was introduced in Mac OS X 10.7 Lion and eventually became a requirement for all Mac App Store apps, though developers can also choose to sandbox apps distributed outside the Mac App Store. The hardened runtime was introduced in macOS 10.14 Mojave and is currently optional for all apps, though it is required in order to notarize your app. Apple has announced that at some point in the future, all apps distributed outside the Mac App Store will need to be notarized, which means they will need to be "hardened" too. I suspect that Apple will eventually require Mac App Store apps to hardened as well. This may be surprising to developers, who associate sandboxing with the App Store and the hardened runtime with Developer ID, but the two technologies are independent of the distribution method and independent of each other, which means that a single app can be sandboxed and hardened.
This is a follow-up to my earlier blog post Another hole in Mojave privacy protection. Three days ago macOS 10.14.1 was released, the first software update to Mojave. Apple published a support document about the security content of macOS 10.14.1 on the same day. As of today, the support document does not mention the privacy protection bypass that I discovered and alluded to in my blog post. Nonetheless, macOS 10.14.1 does appear to fix the main issue, although there remain other avenues for bypassing Mojave's privacy protections under certain conditions. I'll discuss everything I know here.
On October 16, Apple announced that developers could start offering app bundles in the Mac App Store. App bundles have already been available in the iOS App Store for 4 years. After a relatively long road (not 4 years, but 2 weeks), my own StopTheMadness Underpass Bundle is finally available now in the Mac App Store on macOS 10.14 Mojave. This bundle includes my two Mac App Store apps StopTheMadness and Underpass at a discounted price. Moreover, if you've already purchased one of these apps, you can use Complete My Bundle to purchase the other app and still take advantage of the bundle price. Also, Underpass for iOS is available for free in the iOS App Store, so you can get all three of these apps for very little money! Hopefully I can make it up in volume…
I want to talk about a recent announcement by Twitter (and Square) CEO Jack Dorsey: https://twitter.com/jack/status/1017682342008238081. Go ahead and read it, I'll wait.
How to use Gmail in Mac Mail app with Google 2-step verification and Yubico Security Key.
On Monday, Apple released macOS 10.14 Mojave. One of the new features is supposed to be enhanced privacy protection for Mac users. However, holes that would allow malware to bypass this privacy protection have already been discovered by Patrick Wardle and SentinelOne. I've discovered a third. I emailed all of the details of my discovery to Apple product security on Monday evening. I'm publicly disclosing that I've found a privacy protection bypass, but I won't publicly disclose the details of that bypass now. I will disclose them at some point in the future, though I currently have no timeline for that. We'll see what Apple does. In the meantime, I'll offer a few points of clarification:
App Nap is a technology introduced in Mac OS X 10.9 Mavericks. Under certain conditions, such as when an app is not visible on the screen, App Nap automatically puts the app into low power state in order to extend battery life. This can cause problems if the app is performing time-sensitive tasks, which may get delayed or interrupted. Unfortunately, App Nap was designed as opt-out rather than opt-in, which means that App Nap can affect an app even if the developer didn't expect or plan for it. You can see apps going in and out of App Nap by watching the Energy tab in Activity Monitor.
Today I released Underpass version 1.0.4 for Mac and iOS, in the Mac App Store and iOS App Store respectively. I also lowered the price of Underpass for iOS to free. Free as in loss leader. This new price is intended to be permanent. As in marriage. 'Til divorce do us part.
Yesterday I released StopTheMadness version 4.0. Wow, I can't believe how much time has passed since version 1.0 shipped. It's been almost 3… months. In the beginning, this project had a shoestring budget. I ate shoestrings because I couldn't afford ramen. I'm not an artist — more of a standup philosopher — so when it came time to make the app icon, I had to come up with a "creative" solution. If all you have is Xcode, everything looks like code. Thus, I wrote an app to generate my app icon! (Sadly and ironically, the icon generating app still lacks an icon.) A little NSImageRep, a little NSGradient, a little NSBezierPath, a very little talent, and this was the result:
My main Mac is a 2014 15-inch retina MacBook Pro. It's a good machine. In some ways, it's superior to the 2018 MacBook Pro, and I have no plans in the foreseeable future to buy a new MacBook Pro. The 2014 model has a keyboard that is both quiet and reliable. It has function keys, including volume and brightness, which I use every day. It has a variety of useful ports, including MagSafe, HDMI, and USB-A, all of which I use regularly. (MagSafe has saved my MacBook Pro from harm on several occasions.) Yet the 2014 is not my favorite model ever. That honor goes to my late 2006 17-inch MacBook Pro. The "late" refers to the October introduction date; the machine itself is still functional. It mostly sits in a closet now, though I occasionally boot it up to print documents, because it runs an older version of Mac OS X with the drivers to support my old printer. In my opinion, the pre-unibody MacBook Pro was the best design ever. The difference is in the details that make this machine most friendly to customers.
The AppKit Release Notes for macOS 10.14 have finally been released. In the overview, we are told to pay special attention to the section "Swift and Objective-C API Enhancements":
In March, Xcode 9.3 shipped with a strange new feature. The Xcode Release Notes miscategorized the feature under the "Server" section:
First, the good news: my Safari app extension StopTheMadness is now compatible with macOS 10.12 Sierra!
This morning my Twitter account was locked by an algorithm.
Have you ever tried to copy some text from a web site, but the web site prevented it? Or the web site inserted an advertisement into the copied text? Has a web site ever prevented you from pasting text into an input field? Has a web site ever disabled password autocomplete, for your "security"? It's madness! But no longer. Today I'm releasing a new Safari app extension called StopTheMadness that stops web sites from messing with the standard Mac user interface features you love and depend on. StopTheMadness is available now in the Mac App Store.
Exactly a year ago I wrote a blog post about Apple's fiscal 2017 first quarter financial results. 2017 Q1 was unusual in that the quarter lasted 14 weeks, 1 week longer than most quarters. I argued that to compare 2017 Q1 with 2016 Q1, it was more useful to start with the weekly averages rather than the quarterly totals. Today Apple released its 2018 Q1 results, and the same concept applies again, because 2018 Q1 goes back to the standard 13 weeks. Here's a chart showing the year-year weekly averages:
Unless your eyes are really good, you can't see the individual pixels of an image. (How many RGB am I holding up?) For those of us with non-retina retinas, I've written a new open source command line tool called jixel to print detailed information about an image file, including the color values of every pixel. The "j" in jixel stands for … you should know by now. The source code for jixel is my gift to you this unspecified holiday season. The best gifts are homemade, aren't they? Especially when they're cheap. And I'm cheap.
The recent article Strings in Swift 4 by Ole Begemann talked about how Swift String equality is implemented as Unicode canonical equivalence. As a result, two String instances can be equal even if they contain different Unicode code units. This behavior made me worried about my Swift project Bonjeff, a Mac app that shows you a live display of the Bonjour services published on your network, because Bonjour service names are UTF-8 strings. When I audited the equality checks in the source code, I discovered that Bonjour does not compare service names by Unicode canonical equivalence, and thus it's possible to publish multiple NetService instances with canonically equivalent names. Unfortunately, this revealed a bug where Bonjeff did not properly save the individual outline view disclosure states of Bonjour services with canonically equivalent names. The problem was that UserDefaults.standard.dictionary(forKey:) returns [String:Any]?. Since the dictionary uses Swift String keys, it cannot contain more than one value for canonically equivalent Unicode strings. Thus, multiple NetService instances with canonically equivalent names would fail to be distinguished.
Starting on November 17, many iOS and tvOS apps that had not been updated for a year or two years suddenly received phantom updates in the App Store, without any action by the developers of those apps. The version numbers of the apps did not change. For some of the updates, the release notes were the same as the previous update. For others, the release notes said, "This update is signed with Apple's latest signing certificate. No new features are included." Some people speculated that Bitcode recompilation was performed on the apps. So far, Apple has not published any press release or documentation explaining why it updated all of these apps.
My infinite part series "Working without a nib" — most recent part here — explains how you can work without a nib, but I haven't spent a lot of time explaining why you should work without a nib. That was left as an exercise for the reader. It turns out, however, that readers tend to be sitting down rather than exercising. They really need to get up and go outside more. (Later, of course, after reading this article.) While I did talk about the issue a bit on a podcast, I'm not sure many people caught that episode, so I've decided to elaborate for the first time in print. Please print out this web page.
This is part III of my very irregularly scheduled series on compiler optimization. In part II a few (eight) years ago, I explained how the compiler optimizes away local variables in your code. If you haven't read it, TL;DR read it! Apparently the article has achieved cult status, inspiring longtime fans to constantly recite quotations from memory. “An ordinary build spends its time avoiding tense situations. An optimized build spends its time getting into tense situations.”
For analyzing and testing Bonjour services, I've always used the free Mac app Bonjour Browser by Kevin Ballard. However, the most recent update to Bonjour Browser was … 2006? It's amazing that an app so old still mostly works. There are a few bugs, such as the failure to resolve host names of Bonjour services, but the biggest issue is that the app download is rejected by Gatekeeper. Bonjour Browser predated Gatekeeper, which was added in 2012 to Mac OS X (which itself predated macOS), so the app is not codesigned with a Developer ID certificate. There are ways to allow the app to run on your Mac, but the situation is not ideal for distribution.
It appears that [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] never returns nil. I learned of this from Cédric Luthi. For instance, the following code unexpectedly returns an NSString with the copyright © symbol, which is non-ASCII:
Many Xcode projects are a mess. Just look at your project's build settings. Gross, right? The best way to clean up your build settings is to move them to xcconfig files. Move all of them to xcconfig files. My app Underpass has zero custom build settings in its project.pbxproj file. How is this achieved?
Nostalgia is now the norm. (Norm!) Since nobody is expected to have original ideas anymore, I thought I would revisit an old blog post of mine: NSNotificationCenter is thread-safe NOT. That post discussed the thread safety of NSNotificationCenter and raised the problem of an object getting deallocated on one thread while it was observing a notification posted on another thread. I've decided it's important to follow up on my old blog post, because the problem it raised has been solved.
Welcome to part 10 of my infinite part series "Working without a nib". You can find part 9 here, and you can find the rest of the parts over there yonder in your favorite search engine. During my (semi-)recent podcast episode, I talked about building an app without a nib. People seem to be especially interested in how you create the main menu of a Mac app without a nib (or xib, or storyboard). Many years ago I posted a sample nibless application on my old blog, but since then … much has changed. Given the renewed interest, I've decided to post a brand new sample application. You can download the Xcode project now. I call the app "High Nibless". No, seriously, it's "NiblessMenu".
I was on podcast! I talked about the making of my app Underpass, including topics such as Objective-C vs. Swift and nibs/xibs/storyboards vs. code. You can listen or download the episode at Underpass with Jeff Johnson.
Objective-C and Swift are said to be interoperable. You can add Swift files to Objective-C projects and vice versa. If you want to port a large Objective-C project to Swift, the sensible way would be piecemeal, file by file. It is well known that rewriting an app from scratch is fraught with peril, and incremental refactoring almost always produces better results. This topic has been discussed extensively elsewhere, so I won't elaborate on it here. I'm just going to talk about the technicalities of porting Objective-C files to Swift.
In recent years, the clang compiler has added a number of source annotations to Objective-C in order to clarify API intent. For example, NS_DESIGNATED_INITIALIZER formalizes the traditional Objective-C designated initializer pattern. To facilitate interoperability with Swift, Objective-C adopted nullibility annotations: nullable, _Nullable, nonnull, _Nonnull. As with all changes, however, there are tradeoffs. The use of these annotations comes with a price. Consider the following (dummy) code illustrating the designated initializer pattern (and nothing else):
I'm sure you've read this morning's news about the Mac Pro. Apple finally admitted what everyone else knew all along: attempting to cram the highest performance professional machine into a diminutive cylinder was a mistake. The real problem, however, is that the Mac Pro is not the real problem. The real problem is the Mac, and the Mac Pro is just one (too) small illustration of the problem. For a larger illustration of the problem, look at the MacRumors Buyer's Guide for the Mac:
This is not a joke. I wish it were. The Twitter topic du jour has been the new eggless default profile photo, and that change was indeed dumb and pointless, but I want to talk another change that has been rolling out over the past few months: keyword muting. Initially, I was thrilled to finally receive this new feature, which had great potential. However, weeks of usage turned my thrill to disappointment. The last straw was when I ran into this today:
My recent blog posts have been more business-y than programmer-y, so today we're going to bring back that codin' feelin'. With a twist, since I'm going to talk about iOS, which is blasphemy in these parts, but don't shout. I'm writing an iOS version of Underpass, and I needed a UITextView that automatically resizes vertically like in Messages. Searching the web reveals that, give or take, a million other developers want this too. Unfortunately, Apple does not provide an API for the behavior, instead forcing developers to figure it out for themselves. As a result, a million developers have produced a million subtly different implementations. The paradox of choice is that I couldn't choose one. To stave off death from both hunger and thirst, I decided to write my own millionth and one implementation.
This is a follow-up on my recent articles A Record 14 Weeks and Slow Week? I'll talk about several points:
Yesterday I wrote an article about a fact that has been widely overlooked: Apple's FY2017 Q1 was 14 weeks long rather than the usual 13 weeks. Some people have noted this fact, but there has been an effort to explain it away as a "slow week".
I've been asking myself the question, what is Apple's plan for Swift and Objective-C? When Swift became public in 2014, its creator Chris Lattner seemed to claim that Swift and Objective-C would coexist indefinitely. From an xcode-users mailing list post:
Yesterday, Apple posted its fiscal 2017 first quarter financial results. Let's look at the raw numbers, comparing with Q1 2016 for year/year changes. (Units are in thousands, revenue is in millions of dollars.)
Disclaimer: The purpose of this post is not to complain about my sales. You can question my strategy, my acumen, my sanity, and those questions may be valid. However, if you take it upon yourself to publicly rip on one poor indie developer, then you are a malicious, pathetic troll who needs to take a hard look at yourself while trying to choke back the vomit. There's no lower scum of the earth than someone who would step on another person when they're down. You have this in writing, and you can quote it back at any villain who ignores my disclaimer. The purpose of this post is to illustrate by example a shortcoming of the Mac App Store top charts.
This blog post is short but sweet. It answers the age-old question (if your age is 6 years old): can you ship an app in the Mac App Store without a nib? In a recent blog post I talked about making a nibless app with ARC on the latest (the only) version of macOS. In an even more recent blog post I talked about releasing Underpass, my new Mac app. Until now, though, I hadn't connected the two.
In my last blog post, I preannounced my new Mac app. Today, I'm pleased to postannounce my new Mac app! It's called Underpass, and it's for sale exclusively in the Mac App Store. Underpass should be available now worldwide. I started 20 weeks ago with only an idea and an empty Xcode project, so it's thrilling and satisfying to have an app for sale today.
If the AirPods situation has taught us anything, it's that you should never preannounce products. Or since Apple is nonetheless the most profitable company on Earth, maybe it has taught us to preannounce everything and ignore the consequences. Therefore, today I'm going to preannounce a product! It may even ship before the AirPods.
I didn't want to begin a paragraph, much less a whole article, with a lowercase character, so this is an unnecessary lead-in to what I originally wanted to say: macOS 10.12 Sierra has introduced a new feature called automatic window tabbing. Apple's SOP nowadays is to make new mac features — err, Mac features — opt-out rather than opt-in. Thus, automatic window tabbing is supposed to Just Work.™ In other words, it almost just works. I discovered through the magic of git-bisect that automatic window tabbing does not work when you programmatically create a textured window. The main menu items "Show Tab Bar", "Merge All Windows", etc., are never enabled for the window. Textured windows, which do not have a toolbar at all (or from another perspective, have toolbar all the way down), are specified by the style mask NSTexturedBackgroundWindowMask. Rather, they were specified by NSTexturedBackgroundWindowMask until that was deprecated in favor of NSWindowStyleMaskTexturedBackground, because why not.
This is a follow-up to How to Badge an App’s Icon in the Dock by Matthias Gansrigler, or as he's known in the developer community, "Rig". I want to thank Rig for helping me to solve a problem with NSUserNotification. My app posts notifications to Notification Center using -[NSUserNotificationCenter deliverNotification:], and this worked fine for alerts and sounds, but I couldn't figure out how to handle the "Badge app icon" setting in System Preferences, Notifications. The documentation for NSUserNotification is sparse and implies that Notification Center handles everything automatically. The reality is that developers need to do almost everything themselves. Rig's blog post talked about an app that only shows a Dock badge, so I want to expand on that to talk about an app that shows alerts and plays sounds in addition to badging the Dock icon. Here's the code that I use to show an "unread" count:
Reboots are de rigueur these days, so I've decided to reboot my series "Working without a nib". Four score and minus seventy-two years ago, I brought forth on this internet a new blog post, conceived in levity, and dedicated to the proposition that no nibs are created. Since then, much has changed in the Mac world. Except of course the Macs themselves, which haven't been updated in a long time. Fortunately, the source code in my Nibless 2.0 project still works on the latest version of Mac OS X. (I hear some murmuring in the audience.) The use of the undocumented method setAppleMenu: has become redundant and unnecessary (or is it the other way around?) starting with Mac OS X 10.6 Snow Leopard (AKA the last good version). From the AppKit release notes:
In an earlier post I mentioned that the
It is said that distributing apps outside the Mac App Store is safe from meddling by Apple, because they cannot impose arbitrary rules on you or remove your apps from sale. That is true, to an extent. However, the potential still exists for Apple to put you out of business, for all practical purposes. The power to do this resides in Gatekeeper. When a user downloads your app and launches it, Gatekeeper won't allow the app to run unless it was signed by a valid Developer ID certificate. There are ways to bypass Gatekeeper, so the Mac is not completely locked down like iOS, but Gatekeeper does present a seemingly impassable barrier to the average user, so without a valid Developer ID certificate, you are unlikely to be able to sell many copies of your app.
NSFormatter is intended for subclassing. You know what they say, the road to Radar is paved with good intentions. A formatter is particularly useful if you need to restrict input to a text field as the user types. Below I've written a sample NSFormatter subclass that accepts only decimal digits. For the sake of brevity, I've provided simplistic implementations of the required -getObjectValue:forString:errorDescription: and -stringForObjectValue: overrides; depending on your needs, you may want NSNumber as the object instead of NSString. The purpose of this blog post is to point out a caveat with validating partial strings, so let's focus on the final method, which I'll call -isPartialStringValid: for short, because the full method signature is overly long. Also known as "Part-y" among good friends, this method isn't one of those who whine when you give them a nickname.
I mentioned before that the SecTransform API can be confusing. Needless to say, that is still true. Today I'm offering you a second lesson. For free. Free as in, you are required to stand and salute whenever you see me.
I just bought an iPhone 7, and I wanted to sync my Mail and Twitter accounts from my Mac. There used to be an option in iTunes to sync Mail accounts with your iOS device, but that option has been removed, unfortunately. So, what's the new "solution" for this problem? As far as I can tell, Apple now forces you to manually set up all Mail and Twitter accounts on your iOS devices. The account setup process is not particuarly complex, and you can follow your Mac settings as a guide. However, it can be a chore to type in passwords on your iPhone, especially if you follow the best practice of generating long, random passwords containing special characters. I wanted some way to get my passwords from my Mac onto my iPhone, and iTunes sync no longer works. The natural fallback solution is to use a password manager.
I guess I'm the App Translocation Dude. So be it. That makes me a "C" celebrity, and gets me into all the cool hackathons.
As I mentioned in an earlier blog post, there's a new API for App Translocation in the 10.12 SDK:
This is a follow-up to my guest post on the company blog. My employer graciously gave me the credit — or made me the fall guy — but it was truly a collaborative effort, and any grammatical errors are theirs.
Yesterday I found a flaw in the new "feature" App Translocation, AKA Gatekeeper Path Randomization. (One could even call it a "protection racket", because you either pay a percentage to be in the crap store, or Apple breaks your software updater.) Today I found another flaw. You know what they say, you've seen one, you've seen them all. (They, circa 20th century, Hearsay Publications Inc.)
Yesterday I wrote about App Translocation. Then yesterday evening I had a chance to watch the "What's New in Security?" WWDC session, and it filled in some details. What I call "App Translocation", Apple calls "Gatekeeper Path Randomization". I'm going to continue to call it "App Translocation", though, because that's shorter, and "Translocation" is a cool-sounding word. As usual, the Mac "news" media who reported on this got it wrong. They completely misunderstood the behavior. For all the news that's fit to print, just follow my blog.
I was looking through the misnamed "What's New in OS X" document, and something caught my eye under "Security and Privacy Enhancements":
They say you can't go home again. (They being my parents.) In 2012 I famously quit Twitter, because they dropped support for RSS. Recently, though, I experimented with rejoining Twitter. They haven't restored RSS, but I did become somewhat nostalgic in the meantime. As with most nostalgia, it resulted in disappointment. After a few months, I've ended my experiment, and I declare it an utter failure. Twitter continues to be the worst. Even worse than before.
According to the API for SecTransformExecuteAsync (which I won't link to because Apple will inevitably break the URL):
Apple deprecated OpenSSL in Mac OS X 10.7. So, #pragma clang diagnostic ignored "-Wdeprecated-declarations". Problem solved, right? With the Mac OS X 10.11 SDK, however, Apple took one more step — or giant leap — of removing the OpenSSL headers entirely. New problem.
Sometimes your app needs to check the Mac OS X version at runtime in order to handle a runtime behavior change in OS X that isn't already handled automatically by the Cocoa API. One standard and Apple-recommended method of checking the runtime version is via NSAppKitVersionNumber. There are constants defined in
As I noted in a previous article, Mac OS X 10.9.5 included the biggest change to Gatekeeper since the introduction of Gatekeeper. This was documented, for developers, in a technical note. Unfortunately, it doesn't appear to be documented at all for users. There's nothing mentioned about Gatekeeper on the download page, or the details page, or even on the security content page. But at least we developers knew it was coming. And to some extent, the Mac media helped to publicize it to users in a way that Apple did not.
Read it and weep: Changes in OS X 10.9.5 and Yosemite Developer Preview 5. Needless to say, this is the biggest change to Gatekeeper since the introduction of Gatekeeper. It's essentially Gatekeeper 2.
According to Apple's Threading Programming Guide, NSNotificationCenter is a thread-safe class. "You can use the same instance from multiple threads without first acquiring a lock." However, this is extremely misleading. In fact, if your app has multiple threads, then you're almost certainly using NSNotificationCenter wrong. Almost everyone makes the same mistake:
I believe that WWDC should be canceled. And I'm not just saying that because I lost the lottery. Actually, I didn't even want to go; I registered for the WWDC ticket lottery only to maximize my company's chances at getting a ticket. (We didn't get one. 0 for 7, with 7 strikeouts.) I'm not proposing that it be canceled this year, because a lot of attendees have already bought non-refundable plane tickets, but I am suggesting that this should be the final year of WWDC. I think WWDC should be discontinued, permanently.
Have you ever wondered which run loop modes a block will execute in if you submit the block for asynchronous execution on the main queue? Apparently, not many people have wondered this. (That's why you have me.) And of course, it's not documented by Apple. (That's why you have … me.)
Recently Brent Simmons talked about marking all items as read in your feed reader. This is a solution to falling behind and having too many unread items. For me, as a user, the problem with this strategy is that there are certain feeds that I never want to miss. For example, there are developer blogs that only post items a few times a year. Do you want to go on vacation for a week, fall behind on reading your subscribed feeds, and then miss one of those rare posts because you had to declare "unread bankruptcy" and mark all as read? More important, there are feeds that I use for work. We have a feed of commits to the repository, and I never want to just ignore those.
The legends speak of a man — more animal than man, really — who descended upon the web from the far north, slaying all in his path with powerful blog posts. Eventually, however, the n00bie iOS developers rose up and drove him away. They say that he has been slumbering for years, waiting for people to forget him, for complacency to set in, for the right season to return and wreak his vengeance.
Wow, two articles in two days. Don't expect this to become a habit.
I used to have a WordPress blog. I no longer update that blog, because it became a PITA to constantly update WordPress. Also, my desire to help people waned after the infiltration of our little Mac community by the horde of iOS developers. No offense. Well, not much offense. Nonetheless, I occasionally have something helpful to say to people. So, I'm just going to write a self-contained article here, with no promise of any future articles. I'm so serious about no promises that I'm not even setting up an RSS feed for articles, and if you know me, that's telling.