Archive for October 2, 2024

Wednesday, October 2, 2024

Juno for YouTube Removed From the App Store

Christian Selig (tweet, Mastodon, Hacker News):

For those not aware, a few months ago after reaching out to me, YouTube contacted the App Store stating that Juno does not adhere to YouTube guidelines and modifies the website in a way they don’t approve of, and alludes to their trademarks and iconography.

I don’t personally agree with this, as Juno is just a web view, and acts as little more than a browser extension that modifies CSS to make the website and video player look more “visionOS” like. No logos are placed other than those already on the website, and the “for YouTube” suffix is permitted in their branding guidelines. Juno also doesn’t block ads in any capacity, for the curious.

I stated as much to YouTube, they wouldn’t really clarify or budge any, and as a result of both parties not being able to come to a conclusion I received an email a few minutes ago from Apple that Juno has been removed from the App Store.

The App Store guideline is stacked against developers:

5.2.2 Third-Party Sites/Services: If your app uses, accesses, monetizes access to, or displays content from a third-party service, ensure that you are specifically permitted to do so under the service’s terms of use. Authorization must be provided upon request.

So it doesn’t matter whether the app was actually violating the terms of use. If YouTube complains and won’t provide authorization, there’s nothing you can do. There seems to be no limiting factor that would prevent any Web site from objecting to any app that displays Web content.

Juli Clover:

YouTube does not have a dedicated app for the Vision Pro, which is why Selig designed and released Juno last February. Prior to when the Vision Pro launched, YouTube said that it would not develop a Vision Pro app, nor would it allow the YouTube iPad app to run on the headset. With Juno removed, those who want to watch YouTube on Vision Pro will need to use Safari.

Kyle:

Dang, just last night I thought to myself, “if it wasn’t for Juno I would never use my Vision Pro.”

David Barnard:

Welp… with that, the one use-case I really cared about on Vision Pro is now gone (or at least unable to be updated, and Google may eventually break the app).

Vision Pro is probably the worst “business investment” I’ve ever made. As much as I love the hardware, there’s just not enough content and not enough compelling apps. If Google does break Juno, my several hour a week usage will probably drop to near zero.

John Gruber (Mastodon):

I don’t expect to see YouTube launch a native VisionOS app soon, and even if they do, I doubt it’ll be anywhere near as good as Juno. What I was obviously wrong about in that February post was thinking that YouTube wouldn’t care about Juno’s existence, given that Juno did not block ads. All it did was make the YouTube experience great on Vision Pro.

This makes Selig — one of the most gifted indie developers working on Apple’s platforms today — 2 for 2 on getting hosed by big platforms for which Selig created exquisitely well-crafted clients.

It’s a shame, but clients for services that you don’t control just seem to be a bad place to be. If the service is free, the company providing it can kill your app. If it’s paid, Apple will want a cut of the revenue, even though it doesn’t pass through you.

Previously:

Update (2024-10-03): Andre LaBranche:

There is exactly one reason that Juno is very easy for YouTube to kill and yt-dlp is very hard for YouTube to kill.

Pinning iCloud Drive in Sequoia

Howard Oakley:

The reason for this bizarre and annoying interface is the way that pinning is implemented.

When you pin files individually or in groups of up to ten, each file gains its own pinning extended attribute, of com.apple.fileprovider.pinned. But when you pin a folder, only that folder gains the extended attribute, none of the files or folders within it. The whole folder and the paths within it are designated as being pinned. And, as far as I can tell from the absence of any better information in Apple’s missing documentation, there’s no single method to determine whether a file in iCloud Drive is pinned.

Instead, you have to both

  • look for the extended attribute attached to the file, and
  • check all the folders in its path to determine if any of them has the extended attribute, which would then pin everything in their path.

Apple doesn’t document any file or URL attribute that can be used to determine whether a file or folder is pinned.

I think the design makes sense in that if I pin a folder I do want its future contents to be pinned. This is also how inclusions and exclusions for backup software generally work. But it seems that the interface could be clearer and more helpful.

Previously:

Update (2024-10-03): Howard Oakley:

If you have 100 files in a folder and want to pin 99 of them, you have to select groups of no more than 10 and pin each group, ten times.

Migrating the TelemetryDeck SDK to Swift 6 Mode

Cihat Gündüz:

And this summer at WWDC 2024 the longest session of them all was migrating your app to Swift 6 for a reason. This major new update to the language brings a new level of safety – namely data-race safety – which is awesome news for more correct code, but it also comes with a lot of new requirements we all need to adapt to.

[…]

The following 3 sections explain how we fixed the ~30 issues we've run into in our code, grouped by the solution we applied and an explanation why we opted for that solution with a code sample.

[…]

As ISO8601DateFormatter is a type defined within Foundation, we can't make it concurrency-safe itself, so we just need to deal with its mutable nature and work around it. The easiest way to this in our case was to turn our let constant into a get-only computed property, like so[…]

I find this aesthetically displeasing. It would be unusual and bad form to modify the properties of a shared formatter. But there’s no way to tell Swift you’ll treat it as immutable, so therefore we give every user a fresh copy? There’s probably a way to wrap it in a Sendable type, but how much do you want to contort your code to avoid this inefficiency?

Migrating to Swift 6 mode with all of its data-race safety glory was not an easy task. Despite our small project size, we ran into many warnings that all looked similar on the surface, but each of them needed careful consideration.

Previously:

Update (2024-10-03): Jesse Squires:

Ok so it appears someone has botched Swift Concurrency for UICollectionViewDiffableDataSource.

How are you supposed to work around this?

Local Network Privacy on Sequoia

Collin Allen:

Running into a Sequoia bug where third party binaries running under a launchd agent are denied local network access despite approving the privacy prompt. This has the effect of making my iOS app’s CI unable to deploy successful builds, as my deployment tool is not one that ships with macOS.

Quinn:

  • If you run a tool from Terminal, then Terminal is considered the responsible code and, as a system app, it’s not subject to local network privacy.

  • If you run an executable as a launchd daemon, it runs as root and local network privacy does not apply to code running as root.

However, if you configure the executable to run as a launchd agent, you will see local network privacy prompts.

dverevkin:

Here my experiments also show different results - if the bundled application is launched as a launchd daemon, the prompt will appear, even though the app runs with root privileges[…]

And, apparently, even approving the prompt doesn’t work.

Previously:

Update (2024-10-31): Apple:

A third-party app or launch agent that wants to interact with devices on a user’s local network must ask for permission the first time that it tries to browse the local network. This does not apply to launch daemons running as root. Similar to iOS and iPadOS, the user can go to System Settings > Privacy > Local Network to allow or deny this access giving users control over their privacy.

This has been confusing for me because some users have been reporting that macOS is prompting for access:

Allow <App> to find devices on local networks?

even though my apps are not intentionally trying to find other devices. I don’t want to scare potential customers away, especially for access that the app doesn’t actually need!

I don’t know whether the prompt is incorrect or there’s some API they’re using that’s doing something I didn’t realize. All I can think of is that SpamSieve opens a port for communication with Apple Mail—but this uses loopback so it doesn’t pertain to other devices. And EagleFiler supports Growl, which I think does something similar.

It’s hard to investigate this because I don’t see a way to detect what’s triggering the alert. Nothing of interest seems to be logged, and sampling the app while the alert is up doesn’t show it blocked on any calls.

benson3816:

I would like to analyze when it popup and how it impacts my app user scenario. But this dialog only popup when Local Network privacy list not contain this app, once user pressed allow / don’t allow, it won’t popup again.

Local Network Privacy does not use TCC, so you cannot use tccutil to reset it for testing.

Quinn:

I generally do this sort of testing in a VM, restoring the VM to a ‘clean’ snapshot between each test.

Update (2024-11-01): Just after I wrote this post, Apple updated TN3179: Understanding local network privacy, but it doesn’t seem to offer satisfying answers.