¶ Intro: The iOS 26 Question
Welcome to Under the Radar, a show about independent iOS app development. I'm Marco Arment. And I'm David Smith. Under the Radar is usually not longer than 30 minutes, so let's get started. Alright, so tis the season of diving into... the redesigned iOS SDK, trying to adopt our apps to the redesign. And we get that nagging question, that mind virus. Could I just require iOS 26?
Like right at the start? Yeah, it happens every year. Every year we have that feeling, that little itch of, ooh, maybe this would be a lot easier. You know, after you write if available 26 times in a day, you're like, mm, this is really uncomfortable. Yep. And so, Dave, you had a blog post the other day, which was very insightful. And of course, to nobody's surprise, very well-reasoned, supported by data. This is very much your style.
And my feeling is, come on, I don't want to keep support for 18. Please, can I please require 26? And when I look at my reasons that I want... to require 26 it really basically boils down to with ios 18 i don't wanna yeah it's too hard I don't have a lot of better reasons than I don't want to. But I would like you to try to convince me to keep iOS 18 compatibility. Sure.
¶ Developer Pain: Supporting Older iOS
And I think this is one of those, exactly what you're saying. Like there is a, as a developer, there is a technical as well as... reasonable productivity perspective, there's lots of reasons why holding onto support for old versions of iOS is very cumbersome. And this is, I would say, doubly a problem I find in SwiftUI.
that it makes the technical, we'll talk about this later maybe, but the technical aspect of backwards compatibility in SwiftUI is just awkward because the way that you do it with all the modifiers on views and things, like you do this weird, you know, this modifier.
chaining is the way that SwiftUI works, it makes it really awkward to have things that are, if you want to change something in the middle of the tree, it's really difficult. Whereas in UIKit, that would have been much easier and more straightforward. But it's either way, there is a technical version of that of struggle to that so it is reasonable to want to not do it and i think the
¶ Decision Factors: Dev, Users, Market
And it was slightly tricky. And there's two dynamics that are going to come into play with should you support older versions or not. And I think... For existing, I guess there's three. There's how it affects you, how it affects your existing users, and what it does to your market for new users. And for every app, it's going to be a question of how do you value, respectively, each of those three. those three sort of decision factors. And because for you as a developer, it is...
It is 100% better not to support old versions of iOS. It is going to make your life easier. It's going to make your development faster. You're going to be more productive. A lot of things are just going to be better. This is one of those things where every year... beyond the big shiny like glass effect stuff coming in ios 26 there's just
refinements to Swift UI to Swift to, you know, iOS, all of these things are refined and improved. And so very often it's like you were previously needing to do this really complicated. you know, sort of ugly bag of hacks to do something. And then in iOS 26, they've fixed it and you can just do it directly with a fully supported, you know, system function. And so it makes your life a hundred percent easier for your existing users.
¶ Impact on Existing vs. New Users
The story is actually relatively good in the sense of your existing users who don't update or have yet to update will continue to get whatever the last compatible version of your app is. is. So they don't lose anything necessarily in terms of what they lose is future updates that would potentially benefit them. And this is awkward if there's a lingering bug that exists in your app that was...
you fixed subsequent to your iOS 28 or iOS 26 update in this case, they would never get that bug fix that, you know, they are sort of locked into whatever that last version is. And that's something you can, as a developer deal with. Like I've, when I've done some. things sort of like this. Sometimes I've made sure.
that the last version that someone gets is a version that I feel very confident about. It isn't the situation where you should do a bunch of messy underground work in your app, ship that, and then the next update that you submit right away. is the one that dropped compatibility with the previous version because, you know, you ideally will want a period of time where you do a bunch of bug fixes, make sure it's all nice and stable, and then you can cut off those users because they will get...
So on their old devices, they will get the old version. And if they get a new phone or they get a new iPad or something, they will then get the new version on that device. So your existing users have a pretty reasonable situation with that. And it's mostly just a question of whatever device. they happen to have, they may have this weird mismatch between two devices, but overall it's reasonable.
¶ New User Acquisition and Data
where things get really awkward. And this is the like business side of things where it's mostly a business question rather than a technical or kind of philosophical question is new users. have to be on the platform that have to be supported by your app in order to download the app in the first place from the app store. The way Apple does it, they don't let you
download the last compatible version, you always have to be getting the current version or no version. And so what you do by cutting off support for previous versions of iOS. So in this case, say you went iOS 26. only on day one in September, you would immediately be cutting off any user, new user to your app, I mean, who didn't have that version. And for some apps, that may not matter. That really may be totally fine.
Depends on how broad your audience is, how fast they are to adopt, how much you're trying to maximize every new user to your app.
Complicated question. In the blog post I did, I pulled the numbers for Widgetsmith for me because that's something that I'm looking at. In my case, I'm not looking at it to drop iOS 18. I'm just asking now the question of can I drop iOS 15, which is currently... the version that um it supports wow and because that's which you know and it took a long time before i dropped ios 14 as well um But like for right now, iOS 15 represents 2.2% of my new downloads of Widgetsmith.
And so if I dropped support for iOS 15, ostensibly my downloads will go down by 2.2%. And it's tricky because... It's so difficult to get a new download that in doing something proactively that reduces my downloads by two and a half percent or whatever is hard to justify in some ways to me because I'm... It's like I'm willing to do the work on the technical side to manage the backwards compatibility to get that gain. But even on the other side, if I decided to look at iOS 18...
and get a sense of how many users I would be dropping going forward. Like I looked back at last year when we went from iOS 17 to iOS 18. And by sort of the end of the year, so by... Because essentially what Apple does, they launch it in late September and it goes out in terms of it's available.
But typically, it's only available to people who go to the settings app, do general software update, and actually look for the update and hit, I want to update now. The big automatic update version doesn't typically seem to go out. until right around the third week of November. That's been that way for iOS 18. It was that way for iOS 17. It seems like they are intentionally holding back the big, broad, goes-to-everyone update until late November, presumably, once the new iPhones are out.
the bugs are sort of Potentially dealt with and fixed. And it's a very stable, broad thing. And slightly I have the conspiracy theory that they're having it go out right before Thanksgiving in case people need to have their like, you know, the technical person in the family to help anyone through things.
Maybe that's true. Maybe that isn't. That's just what I tell myself. Oh, I was thinking it might juice sales in the holiday season of new devices. Could be. Could do that too. Either way, it seems like the end of November. Yours was much more charitable. And the end of November is when it goes. out. And by that point, like for Widgetsmith, it was getting to about 70% of my downloads, you know, by, you know, sort of by the second week of December, 70% of my downloads were coming from iOS 18.
which is pretty substantial. That's a very meaningful proportion of users that would still be able to. So in this case, if we project forward and say you had the same structure, you're dropping... maybe for a period of time, maybe half of your downloads, you know, in September and October. And then by November, December, you're getting up to about, you know, only losing about 30%. And then, you know, over the course of the rest of the year, at this point, iOS 18 represents 90%.
91% of my downloads. So I'd be giving up about 9%. Um, and all these numbers and graphs and things are in the blog post. We'll link to this. So obviously, but.
¶ Balancing Factors and Personal Approach
Essentially, that's the crux of it for anyone. And there is no one answer, is I think something that is fundamental to all of this, that those three factors... Your enjoyment, your satisfaction, the technical debt and all the things that come along with it, how it affects your existing users and how it affects your new acquisition of users is just going to vary for everyone. Like for me and for most of my apps, I tend to be. very conservative with this. I tend to
do make my life more difficult in terms of the backwards compatibility thing, because I am, you know, I am willing to do that work. I've done it enough times that I know how to do it in a way that doesn't drive me crazy. And so I will do that. so that I can, in this case, have 9% more downloads.
now versus if I went iOS 18 only last year, or even if I went iOS 18 right now, it would reduce my downloads by 9%. And I would be thrilled if I was able to do some simple, some App Store optimization activity. that boosted my downloads by 9%, I would be delighted. And so I'm doing that activity and it just happens to be that it's supporting these older versions. And so that's the way the calculus works for me.
But for every app, it's going to be variable. And you just kind of have to decide whether you're going to do it that way. And I think it's the only other factor that's a little awkward is in some ways, you know, it's if you're. Most of the benefit would come from only supporting the current version, iOS, in this case, iOS 26. Anytime you support anything behind that, very often it's just as much work to support, you know, sort of.
N-3 or N-2 versions of things. Because once you're not only supporting one, you have to do that work anyway. So if you wanted to support iOS 18 and iOS 26, the difference between supporting that and iOS... 26, 18, 17, 16, that difference is much smaller. And so it's a weird dynamic that either you should be sort of all in.
or probably very conservative. There's not a lot of desire, I think, and a huge amount of benefit in this case to go back and forth. Because if you have to do the work of supporting the pre-26 design as well as the post-26 design, you're kind of... You're doing that work anyway, so you may as well get credit for it in terms of the breadth of new user acquisition.
Oh, you gave me a lot to think about. All right, first, we're brought to you by Sentry this episode. All right, founders, time to be honest. How much time is your team wasting on debugging? If you're like most startups, it's way too much. Your team should be focused on shipping features, not chasing down bugs.
That is where Sentry comes in. Sentry is a real-time error monitoring and tracing platform, so you know exactly when something breaks, where it happened, and why. So there's no more 1am Slack threads or digging through endless logs trying to figure out what's going on. a game changer. Seer.
Sentry's new AI debugging agent. It's like hiring an engineer who already knows your entire code base. Seer finds the true root cause 94% of the time, and can even generate merge-ready pull requests, plus optional tests. to prevent regressions the bottom line is you ship faster your team isn't drowning in bug alerts and instead of grinding through logs your developers get back to building the product this is
A great platform for developers who need insight into the apps you've built. This can help you retain people, improve quality, improve the user experience, improve performance. It's a great... So try it out. The good news is new users get three months free of the team plan, which covers 150,000 errors.
I have generated that many errors before. Me too. Yeah, we all have. So click the link in the show notes or go to Sentry.io and use the code RADAR. That's Sentry, S-E-N-T-R-Y.io and use the code RADAR. or just click the link in the show notes our thanks to century for their support of this show and relay so you kind of set me on a roller coaster with with your reasoning so like at first i was like like
You make a good argument at first for why I probably should support 18. And by the way, and 17. Right now, I still have about 2% of people on 17. Everyone else is on 18 except for the... two and a half percent they're already on 26 but uh you know certainly
You know, supporting 17 and 18 together is fine. I've been doing it for a year. And I haven't dropped 17 because there really wasn't much of a reason to. I have, you know, a few views in the app that have conditional, you know, things in them, but not much. So at first, as you were going through that, I was like, hmm.
I should really support it. I'll support the back one. But then at the end, as you were talking about how, well, actually, you know, after a few months, it doesn't really matter or it matters a lot less. Now I'm on a roller coaster. Backups are like, hmm. Here's some more reasons why I would love to just require 26 sometime by mid-fall.
Whenever my iOS 26 release happens, and that's something we can play with the timing of. Do you want to release on day one? Well, on day one, you can get a decent amount of press. You might get attention from Apple. But you will be competing with everyone else who did the same thing for that attention and for that editorial selection. And on day one, the fewest number of your customers will have the OS installed.
So, I think the day one game might be better for apps that are supporting the old OSs still. Whereas if you can wait, if you can hold off until October or November... to do your release at all that has the new OS. It mostly doesn't matter if you require it for many types of apps. Now, it also depends what phase of your app are you in, like business-wise and lifecycle-wise. Overcast is not growing massively anymore. It's mostly a maintenance level of people using the app.
It's, you know, I'm not getting tons of new users. I'm mostly just serving the existing users of the app at this point. But I'm not getting no new users. And I obviously want and need to keep a steady stream of people coming in because there are... Obviously, I said you're going to make people going out with every app. So you kind of need to maintain your user base. You have to keep having more coming in.
That being said, though, I am not in the growth phase anymore. So the percentage of new users that I have is way, way, way lower than the percentage of existing users that I have. So that also kind of leans towards...
¶ Practical Benefits of Latest OS
requiring it might be fine i also you know obviously there's the practical concerns if you require only the newest os All this summer, we have a lot of work to do to adopt this. We are busy. We are cramming. We're trying to hit this deadline in the fall. It helps a lot to have simpler testing and QA. And you have a lot simpler testing in QA.
when you're only supporting one family of OSs, not the previous ones. And it also reduces the number of bugs that get shipped out to customers because you don't have to worry, oh, in my change for 26, I broke this one behavior of this one control. for on ios 17 and i'm not going to necessarily know that if i don't do a very very deep testing on the old os's which let's be honest we don't always do that um so you know it also makes the test device situation simpler like you can kind of
cull your pool of test devices a little bit. And then finally, I worry that if I maintain compatibility with 18, I worry that that might hold back How aggressive of a design refresh I inherently do. Like it might hold me back from doing like a more pure iOS 26 redesign.
If I'm also trying to maintain the structure of the app to make it work well on 18 and before and look good on 18 and before. I think I can do my best work if I require 26. And that is a pretty big... hurdle for me to overcome with logic to say i should be responsible and maintain 18 sure and i suppose maybe the next thing for me to say is the way that i do
¶ An Unconventional UI Duplication Strategy
My iOS 26 – or expect to do my iOS 26 updates may help you a little bit here. So I – And I learned this from watchOS where watchOS is the version – like what I – it took 10 minutes for me to describe my strategy on iOS. On watchOS, it's like immeasurably more complicated because you have the iPhone version that's different from the watch version. And if the watch –
version is different you know like the watch app just disappears in that case from the person's watch they can't get the last compatible version because the version that they have is tied to their iphone version not the watch version and it gets really complicated So in there, what I've done in watchOS is I'm very conservative about dropping old versions of watchOS because the impact to the user is much more...
The second of my factors where existing users on watchOS, it's really difficult because they just lose the app. It just completely disappears. There's no way for them to get it. And so I'm taking something from an existing user, which is...
often something I try and avoid. And so what I've done on watchOS, and it's worked, it'll sound terrible, so let me explain my reasoning before you jump to conclusions as to whether this is a good idea, is... essentially for every major sort of time I'm redesigning or restructuring or doing compatibility work with the app, I, to some degree, create an entirely parallel.
copy of the view hierarchy of the app oh my god that has a new entry point and it's essentially just the a copied version of the old one and so you will have a lot of views that are like you know it's like workout view you know, it's like underscore 18 or 10 or like for watchOS, it would be like, you know, this one's for watchOS 7. This is the one for watchOS 10. Like when we did the watchOS 10 redesign, I have a lot of views that just end in a 10 now.
And there's a new entry point to the app that at the highest level of the app is basically like, which version of the app are we going to run? Okay, we're going to run the post-WatchOS 10 version. Oh, if we're on... a version that supports that. Otherwise, it runs the old version. And in some ways, what I'm doing is replicating the behavior that Apple is doing with their last compatible version of the app system.
where that code is very stable, doesn't change. And if I've done my work sort of neatly and cleanly with the underlying app logic... that those APIs are good and thoughtful and stable at this point. It should just continue to work. And generally that's been the case. And then... On the new version, so in this case, for iOS 26, my iOS 26 branch of the view out of that initial...
sort of view hierarchy, can require iOS 26 100%. I tend to intentionally add a bunch of add-available sort of modifiers to all of my new views to make it clear. sure that I'm not creating weird issues there. Like I'm intentionally trying to separate the views as much as I can. And a lot of it is literally, I will take a copy of the old version, you know, Make a new file, paste it in, add 26 to the top, and then go from there and completely ignore all of the...
The implications that I'm deleting code or changing things or adding modifiers, I can run freely in that view because it's not affecting the old version as well. The old version exists completely as it is, and the new version can be completely optimized. it is a little bit crazy it is a little bit cumbersome in the sense of i have two versions of a lot of the view logic of my app but the reality is like i find that it works
pretty well. And like in watchOS, it has not really bitten me at all in the last five years that I've been doing it this way. It seems to work pretty well. It works fairly stably. I have the advantage of being able to do bug fixes on old versions. I don't maintain or improve the old version of the app in this context. So like on iOS 18, they're getting essentially...
the last compatible version of the app that is the last thing that it shipped and that's all they should expect to get from there or like from my perspective. I could subsequently change it if I needed to or wanted to or for, you know, if there was some...
compelling reason for me to open up the ios 18 branch of the app you know the you know view branch not code branch like the in the view branch i could go in there and say oh i need to change something this say there was some some marketing reason or even i wanted to add a
Hey, you're running an old version, but on a device that could support an update, there'd be this great feature if you were updated to it. I could do those kinds of things and message to my users in that way because the version they're getting is still live and active. And that kind of works better for me because the alternative in SwiftUI, I find it so painful to have any code in SwiftUI that is...
designed to support two different versions of iOS. Like the way you have to do it with modifiers and there's like hacks you can do where you can use the backported. features to like do it for specific modifiers. But like, then you're dealing with this weird case where like, I never liked the fact that you have the same code that does two different radically different things on two different platforms.
that feels weird and brittle in a different way to me. And so for me, that never works. I don't like it. I would much rather just have, this is my iOS 26 version. And I mean, the reality is as much as like my apps are complicated, there's only like... I'm not talking about thousands of files that are duplicated. I'm talking about...
100 files that are duplicated. There's not this massive, which is a lot of files, but not an impossibly large to manage number of files. And so that's the way that I do it. And that's what keeps me sane when I'm supporting older. versions. And I've spent the last few days properly getting into a redesign for Pedometer++. That's the way that I'm doing it. And as a result, it feels really fast. It feels very fluid. It's essentially as though I've dropped support for iOS 18.
Um, cause from a technical perspective, I kind of have, but from a business perspective and from a marketing perspective and all those things, I haven't. And so that's the approach I take. And it kind of, it's weird. And I, I know it's weird. And there's probably people listening to me shouting.
at their um shouting at their podcast app right now being like what are you doing that is terrible and uh maybe it is but it kind of works for me somehow that's okay that like first of all this is the perfect
¶ Reactions and the DRY Principle
underscore solution to a problem it's like surprisingly like logical and clever and reasonable and something i would not have thought to do on my own because for whatever reason it just like it's like it's too straightforward Just copy everything. I feel like a lot of idiomatic development would be like, you're just going to copy all your files? What? You can't do that.
That's wrong. We've read books from the 90s that say don't do that. Yeah, no, exactly. But that actually – so I think I'm going to give that like one day of a try. Absolutely. Because I'm about to start my big UI work now. It's like, all right, let me try that. I'll give it one day and see how hard is this. Because that would... kind of give me everything like if i can do that you know it gives me a day one releasable update that doesn't cut me off from anything in in the app store hmm
And that is how I've done widgets. Obviously, I'm talking to Mr. Widgets, but widgets, as you know, they've changed a lot over the last few iOS releases. Trying to maintain a bunch of if available checks inside of a widget is ridiculously horrible. And so I have just had copies like, all right, this is the playlist widget underscore iOS 18. I have all those named too. But I think for the entire app, there is both...
On one hand, there are fewer views that will differ between the versions compared to a widget, but there's also just tons more total views. I have so many views in Overcast. It's such a complicated app. There's so many screens. There's so many little cells and little backgrounds. There's so much. that I worry that it might be too daunting, but I guess I won't know until I try. So...
All right, you've convinced me. I'm going to give it one day and see how I feel about it after that day. And I think the thing that there's two things that I think make this sort of work. And one of them is that all of the advice, like I always remember.
like when I was getting into web development and it was always like, keep your code dry, right? Don't repeat yourself. That was like the big, one of the big kind of ethoses. And I think the big... reason for that sort of philosophy is if you expect to maintain and actively work on both parts of the app, then that is
something that is a useful and desirable outcome. Because then every time you make a fix, you have to make the fix in both places. So if you can consolidate your logic into one location, that location will always benefit everyone else who depends on it. Like that is why I think that is the motivation for the don't repeat yourself philosophy. And like the reason it seems to have worked in the past for me to do this, take this approach.
is because I don't maintain the old version in many ways. Like sometimes that's come up and I will go back and fix a bug that I'm aware of. But by and large, that's not what I'm doing. Like I'm not trying to maintain. two paths at the same time. One of them is stable and you get the benefit of that iOS 18 code is never going to run on a machine running something other than iOS 18.
It's never going to get run in iOS 26, so you don't have the kind of unknown future compatibility issue. That future compatibility issue is only ever happening on the new branch, not on the old one. And then the other thing is... In SwiftUI, it incentivizes you to make your UI out of lots of small atoms within the app so that you have lots of small little views that tend to do one thing or focus in on one particular.
And many of the smallest leafs in your view tree, you can share between the old version and the new version because they're not... doing something complicated or nuanced or taking advantage of the new glass effect or all these kinds of things, that they're the part that you can share comfortably between two views or between both sides. And so you'll have this relatively big thing that is shared.
but the big kind of like hierarchical, the navigation stack, the big kind of chunky views are the things that you're going to repeat. And so... duplicating them is much less daunting than duplicating the entire app in that way. You're only typically having to duplicate, I find, these big structural views and then lots of the small detailed views you won't. But, you know, it's not for everyone.
¶ Final Thoughts and App Store Wish
And I'm not necessarily recommending this as a strategy that I think is best. I'm just saying it's worked really well for me. And if you know what you're getting into when you do this. it can have these big payoffs that you get these business benefits. You still get the developer benefit of really your new iOS 26 work is just as though you've dropped support for iOS 18, but you haven't actually. And so it's kind of like a best of both worlds.
But your mileage may vary, I suppose, is just fair to say. I wish Apple would just give us a checkbox to say, let people download the last compatible version from the App Store. That would be much simpler. Absolutely. But until that day, this is the best we can do. Thanks for listening, everybody, and we'll talk to you in two weeks. Bye.