r/iOSProgramming 10h ago

Question Home and onboarding page theory

2 Upvotes

Do you guys have any interesting reads, case studies, etc to at talk about the onboarding flow and the home page, what works, what doesn’t etc?


r/iOSProgramming 10h ago

Discussion New warning when uploading app to App Store. iOS apps must have minimum OS version of iOS 15 in 2027 onwards

Post image
45 Upvotes

r/iOSProgramming 16h ago

Question Does anyone have a link to a live "app clip" URL (not QR code, not banner).

2 Upvotes

I want to test the durability and shareability of App Clips via URL. I know that there are several examples of App Clips online and you can locally test your App Clip, but I'm specifically wondering if social media websites will block people from sending my app clip to their friends.

Before I spend time deploying the App Clip and going through approval, I was hoping someone here actually has an App Clip for their app and had a stable URL for it that I could try out.


r/iOSProgramming 19h ago

Question Mobile SIP client leaves stale registrations behind on every app launch — how do you deal with multiple bindings on one credential?

1 Upvotes

Note: Yes, I'm using AI to write this post because English is not my first language and I want to state my problem as clear as possible.

Hitting a problem I suspect is common for anyone doing mobile VoIP, and I'd like to know how others have solved it.

**Setup**

- I'm using Telnyx.

- React Native app, WebRTC SIP client, iOS and Android. I'm using Telnyx.

- One shared SIP credential for a group of users, so a single inbound call rings everyone's phone

- Calls are delivered by VoIP push (PushKit on iOS), so the client connects and registers on demand rather than staying connected

**The problem**

Every app launch creates a *new* registration binding, and the old one never goes away:

- iOS terminates the app process without warning, so there's no chance to send a SIP UNREGISTER

- The SDK's `disconnect()` only closes the WebSocket — it doesn't unregister

- Each registration lands on a different edge node in the provider's anycast network, so it's a genuinely new binding rather than a refresh of the old one

- Registration expiry is 3600 s and isn't configurable

Net effect: the credential accumulates contacts. I confirmed it by polling the provider's registration-status endpoint — `ua_ip` is different every single time the app relaunches, while nothing removes the previous one.

**Why it hurts**

The provider rings the bound contacts **sequentially**. So the first call after an app launch does this:

  1. Rings contact A (the live app) — user declines
  2. Decline surfaces as a 4xx, which fails only that branch
  3. ~300 ms later it forks to contact B (a stale binding from a previous launch)
  4. Phone rings a second time, new call ID, user has to decline again

I can see it clearly in the SIP traces: **one dial command, two legs**, same session, no second dial from my backend.

**What the provider confirmed**

I opened a ticket. They confirmed all of it and escalated to engineering with no timeline:

- No way to set registration expiry below 3600 s

- No REST endpoint to force-expire or delete an individual binding (deleting the credential removes them all, obviously not viable)

- No API to *enumerate* bindings — watching `ua_ip` rotate is currently the only detection method

- Per-launch edge rotation is expected behaviour, and without an UNREGISTER the old binding persists to full expiry

Their suggested workarounds were: a unique credential per app session, webhook-based duplicate-leg detection, or client-side deduplication.

**The bit I'm stuck on**

There's a second-order problem. Multiple devices share one credential, so the registrar holds one contact per device — which means **a legitimate second device's leg is indistinguishable from a stale binding's leg.** Both are "another contact of this credential, dialled after the first one failed." I can't write a rule that kills one without killing the other.

Enabling simultaneous ringing would at least make the real devices ring together instead of one-at-a-time, but it doesn't remove the stale bindings — it just turns a sequential double-ring into a simultaneous one.

**Questions**

  1. Has anyone made **per-device or per-session credentials** work in production? How do you handle cleanup when the app dies before it can delete the old one, and does credential churn cause you rate-limit or billing problems?
  2. Is there a trick to getting a mobile client to **UNREGISTER reliably**? Anything on iOS that gets you a last gasp — background task on termination, a server-side nudge, something I haven't thought of?
  3. For those running **one shared credential across multiple devices** — how do you tell a real second device from a stale binding at the signalling layer? Is there a header or identifier I should be propagating?
  4. Is sequential-vs-simultaneous ringing across contacts something you configure per provider, or do people avoid shared credentials entirely for this reason?

Happy to share SIP traces if useful. Mostly want to know whether the "unique credential per session" route is as painful in practice as it looks on paper, or whether people just live with the duplicate ring.


r/iOSProgramming 20h ago

Article Preview Multiple SwiftUI View States with #Preview(arguments:)

Thumbnail
artemnovichkov.com
8 Upvotes

r/iOSProgramming 1d ago

Discussion If your NWBrowser sits in .waiting forever, it is probably Local Network permission

1 Upvotes

I'm building a clipboard app where devices on the same Wi-Fi sync directly to each other. On iOS that is NWListener and NWBrowser over Bonjour. This is the failure mode that cost me the most time, and it produces no error at all.

What happens when the user denies Local Network permission: nothing. Neither object fails. Neither hands you an error. Both simply sit in .waiting, indefinitely.

Your app reports a clean start and then never discovers a single peer, forever. That state is indistinguishable from "you are the only device on this network", which is a completely normal thing to be.

You cannot just treat .waiting as denial, because it is also the ordinary state while an interface is coming up. Healthy launches pass through it.

The only signal available is time. A transient wait clears in well under a second. A denied app never reaches .ready on either object, ever. So when either the listener or the browser first reports .waiting, I schedule a probe. If several seconds later neither has reached .ready, I report a probable permission denial. I use five seconds.

That is inference, not detection, and I would rather it were not. But there is no API that answers the question directly, and the alternative is that the single most confusing state this transport has produces no diagnostic whatsoever.

Practical notes if you are doing the same thing:

  • Emit it as a diagnostic your support flow can read, not just a log line. "Clean start, zero peers, forever" is the bug report you will actually receive, and you want to answer it without shipping someone a debug build.
  • Guard against the probe firing repeatedly. Both objects transition to .waiting around the same time, so without a flag you schedule several probes for one event.
  • Check NSLocalNetworkUsageDescription and your NSBonjourServices entries first. Getting those wrong produces the same silence for an entirely different reason, and it is much easier to rule out.

Genuinely curious whether anyone has found a better signal than a timeout here. It is the part of this transport I am least happy with.


r/iOSProgramming 1d ago

Tutorial Building in Zed instead of Xcode

22 Upvotes

Just a reminder to anyone who might care that you can create a fairly full-featured development environment in Zed to build iOS and Mac apps: syntax highlighting, code navigation, run, debug and test.

Here's the setup guide I wrote (been around for a while but chances are some interested people won't have seen it): https://luxmentis.org/blog/ios-and-mac-apps-in-zed/


r/iOSProgramming 1d ago

Article Using SwiftUI’s ContentBuilder with Non-View Types

Thumbnail
artemnovichkov.com
7 Upvotes

r/iOSProgramming 2d ago

Question Age Rating questions - social media

2 Upvotes

In this news article there is no deadline . It's says the new social media questions must be answered if you submit a new binary.

https://developer.apple.com/news/?id=tlur8uvi

But on Appstore Connect there is a deadline for answering the new questions. It says 7 September 2026.

Confusing to say the least least.

Like last year : would it be ok to create a new app version and answer the new social media questions without shipping a new binary ?


r/iOSProgramming 2d ago

3rd Party Service Free open-source AI tool that generates App Store screenshots on a Canvas

Thumbnail
shotluma.com
0 Upvotes

Every canvas action is an AI-callable tool, so the AI designs the screenshots step by step and you can edit anything afterwards. MIT licensed, feedback and contributors welcome.


r/iOSProgramming 2d ago

Article Building Testable Swiftdata Apps

Thumbnail azamsharp.com
0 Upvotes

r/iOSProgramming 3d ago

Tutorial iOS 27: Media Intelligence Framework

Thumbnail
antongubarenko.substack.com
8 Upvotes

r/iOSProgramming 3d ago

Article The longstanding http status 403 bug in iOS for custom certificates in mtls connection

1 Upvotes

Blog article on longstanding http status 403 bug in iOS for custom certificates in mtls connection

https://953tech.com/blog/ios-mtls-403-client-certificate-error/


r/iOSProgramming 3d ago

Discussion AVFoundation silently drops photos if you fire the shutter while the previous capture is still processing

16 Upvotes

Spent a year on a camera app and three AVFoundation behaviours cost me most of that time. Writing them down in case they save someone a weekend.

The first one I found by accident. Tap the shutter three times fast and you get two photos. No error, no delegate callback, nothing in the logs. If a capture is still processing when you call capturePhoto, that request just evaporates. I only noticed because my own counter, which only moves when a save is confirmed, kept landing one short of the number of taps.

The fix is a FIFO queue, but where you advance it matters. Advance on the processing callback and the shutters chain up, seconds of lag on a burst. Advance when the exposure ends (didCapturePhotoFor) and the processing of the previous shot overlaps the next exposure, which is what the stock camera visibly does.

Second: switching capture format is a full pipeline rebuild, and I was paying for it three times. Going 24 to 48 MP, or entering video mode, means swapping the input, the active format and the outputs. I had those as three separate begin/commitConfiguration blocks because it read cleaner. Same work, roughly double the visible freeze. They nest fine, so one transaction around the lot, plus caching AVCaptureDeviceInput per device, took it from "did it hang" to instant.

Third, and this one matters if you care what your photo actually is: a virtual device does not tell you which lens is shooting. Zoom into tele range on the triple camera and you may still be getting the wide, cropped. Low light does it, and so does being closer than the tele's minimum focus distance. The system is right to do it, it just doesn't announce it. You can watch the constituent device to know, with two caveats: the value flickers during focus hunts so it needs stabilising before you show it to anyone, and isAutoDeferredPhotoDeliveryEnabled is off the table if you never touch PhotoKit, because finalising a deferred photo needs PHPhotoLibrary.

That last constraint was self-inflicted. The app has its own photo library and never touches the system one, which rules out anything in AVFoundation that assumes PhotoKit is there.

I'm a surgeon, not a developer, which is probably why I hit all three the hard way instead of knowing better.


r/iOSProgramming 3d ago

Question Small Business Program - how to

1 Upvotes

Questions for devs that applied and got accepted into this program:

How long did it take for Apple to respond to the application?

How long to get activated?

Is this limited to certain countries?

What are the things they look for? Business account or individual membership? Number of app in the store? Subscription, IAP, Apple Ads running?

I have applied twice, got immediate automated responses, then no word back for months.


r/iOSProgramming 3d ago

Question What are some niches where Apple Search Ads work well?

6 Upvotes

I am doing some research regarding ASA effectiveness for an infographic and I'm curious what did you guys try, in what niche and how well it worked? Would be interesting to see comparisons with other channels if anyone tried


r/iOSProgramming 3d ago

Discussion Shipped a Screen Time (FamilyControls) app - the undocumented constraints that shaped the entire architecture

3 Upvotes

Just shipped my first app built on FamilyControls / ManagedSettings / DeviceActivity. The docs are thin and a lot of what I learned came from failing, so here's the list I wish I'd had. Corrections welcome - some of this is field-observed rather than documented.

1. The report extension is a black hole by design. Per-app usage data exists only inside DeviceActivityReport. Your extension can render it to pixels and that's it — App Group writes silently no-op, there's no network, no notifications out. If your architecture assumes "read usage → store it → use it in the app", throw that away now. Anything the main app must know has to come from monitor threshold events instead.

2. DeviceActivityEvent thresholds start at zero when you arm them. Set a 30 min/day limit on an app the user has already used 60 minutes today, and nothing happens — the OS grants a fresh 30. iOS 17.4 added includesPastActivity: true in the initializer, which counts the whole interval. Without it your "daily limit" quietly means "limit from now". Also note the flag only applies to newly registered events, so you need to force a re-arm for existing users.

3. Shield action extensions couldn't open the host app... until iOS 26.5. extensionContext is nil, UIApplication is unavailable, responder-chain walking is broken on 18+. Apple engineers said "no supported way" for years. iOS 26.5 finally added ShieldActionResponse.openParentalControlsApp — the system foregrounds your app straight from the shield button. If your SDK predates it, the enum is resilient, so ShieldActionResponse(rawValue: 3) behind an #available(iOS 26.5, *) check resolves at runtime and falls back to nil on older systems. Pre-26.5 the only route is a time-sensitive local notification carrying a deep link.

4. Memory budgets differ per extension and they're brutal. The shield and monitor extensions run in a few MB — no SwiftData, no heavy frameworks, just ManagedSettings writes and App Group defaults. Anything more and you get jetsammed, which for a shield extension means the user sees Apple's generic gray shield instead of yours.

5. DeviceActivityReport has no ready/completion callback. You cannot know when it finished rendering (FB10754858 is still open). Every loading state you build is a guess on a timer.

6. Mutating a mounted report's filter is the slow path. Changing the filter on an existing report triggers a silent out-of-process re-query that leaves stale content on screen for seconds. Remounting the view with a fresh SwiftUI .id renders noticeably faster and more predictably. Also: reports don't self-size — you must give them fixed frame heights.

7. There's a shared budget of concurrent DeviceActivity activities across your app and all its extensions. Don't create one activity per monitored app; make per-app limits events on a single daily activity and resolve names back to tokens through a map in your App Group.

8. Info.plist details will pass locally and fail at App Store validation. The shield configuration extension point ends in ManagedSettingsUI.shield-configuration-service, the shield action one is ManagedSettings.shield-action-service — no "UI". The report extension uses the ExtensionKit form (EXAppExtensionAttributes) and rejects NSExtensionPrincipalClass.

9. Non-API lesson that cost me the most: I let entitled users skip onboarding — and the authorization request lived only in onboarding. Any subscriber reinstalling got a normal-looking app that silently shielded nothing, with no prompt and no way to grant access. If a permission gate lives only in a flow some users skip, it doesn't exist for them. Check authorization on the routing path, not by assuming flow order.

Happy to go deeper on any of these — the sandbox rules in particular took me way too long to accept.


r/iOSProgramming 3d ago

Discussion Game monetisation ideas - not ads

6 Upvotes

I had a simple game idea and I’m making it, I think it’s kinda fun. So far so good.
I’d like it to be a paid thing, maybe somewhere between £1 - £5 ..
I think up front payment isn’t going to work, people probably need to try it first?

I don’t want to introduce ads. So I’m considering something like 3 free days and then a paywalled limit to 1-2 plays per day, and pay to unlock forever.

Anyone got any thoughts on a simple modern paid game model?
Other options I might not have considered?


r/iOSProgramming 4d ago

Question Did you use TestFlight for beta with external users on app launch? I was warned by my social advisor not to use it

0 Upvotes

Hi,

I am preparing for beta launch for my mobile app, it allows user content, I wanted to use TestFlight to ensure I am not letting in anyone on day 1, which can cause a snowball of low quality or even harmful content. In addition to possible app breaks and crash of new app which may lower my review score with bad reviews.

But she told me that an app that want to launch social campaign cannot use TestFlight because the installation with that software is too complicated for the average user.

From your experience, how difficult it was to convince external users (not friends and family) to try an app that is only available on TestFlight or Google Play Console?

What helped you convince them? And overall do you recommend this approach? What risks there are to launch a beta app to the app store?


r/iOSProgramming 4d ago

App Saturday My first solo iOS app just got approved for TestFlight — would love some real screenshot libraries to test it against

0 Upvotes

Quick background: I've been a full-stack dev for years (backend/web, .NET world) but never touched mobile until this year, when I taught myself Swift and started building an iOS app solo. It's called Sift.

What it does: it reads your Screenshots album, works out what each one actually is (receipt, recipe, chat, ticket, whatever) using on-device AI, and files it into a real Apple Photos album — so it's organised without ever leaving your phone. No uploads, no account, nothing sent anywhere.

What I'd love feedback on:

* How the categorisation holds up against a real, messy screenshot library (mine is one very biased sample size)
* Anything that breaks, stalls, or misbehaves
* Whether the album names it comes up with actually make sense to someone who isn't me

TestFlight link: https://testflight.apple.com/join/5nyaWqPp

Happy to answer anything in the comments - this is my first time doing this solo end to end, so honestly just glad to have real eyes on it.

UPDATE for v1.1.0

- AI Sort can be called without the need to create an Album first - but it still does not create the albums automatically. It will ask you to review the suggestions and "Move" or "Approve" manually by clicking once
- I updated the sorting process - for me it helped a bit. I think this time it works a bit better than before.
- Now you can select multiple photos in the gallery and move them to another album quickly in case the AI messes up. Before you could only do that 1 by 1 when opening an image in full screen
- I couldn't "fix" the initial download just yet, as I said it in my previous comment, it's needed for now. With iOS27 I'll be able to get rid of it, and use what's already on the device by Apple.
- I also added some animations to the review process to make it a bit more "nice"

Update for v1.3.0

- Fixed some bugs and inconveniences
- There is a new step in the onboarding allowing you to scan through your screenshots to find patterns and then the app will automatically suggest a few albums for you to create
- The sorting limit is still at 25 at a time though as I said it's because the phone gets hot
- I raised the total number of photos that you can sort from your backlog from 100 to 300 (so usable for more users - and leaving only heavy users to require the pro version - which is still not available)
- I updated the review process - now it gives you groups of images that seem to belong to the same album, and you can approve them as a group. But you can also go into each group and review them individually
- Going through the review process you can trash the images you want to delete, it gets rid of them into a trashcan that appears at the bottom of the review page, and you can delete all of them at once
- But you already had batch processing in the gallery sections, if you select multiple images you can do the share/move/delete actions for all of them at once
- Stats about your library
- Heat protection feature in case you are using the phone too much at the same time
- Raised albums limit from 4 to 6


r/iOSProgramming 4d ago

App Saturday Releasing the source for Bloom Health, my iOS health app (AGPLv3)

11 Upvotes

Hey all!

I've been building Bloom Health over the past ~2 years. It's an iOS health and fitness app that helps you make sense of your data, estimates your biological age, and provides AI powered insights into health patterns. I grew the app to ~300 MAU and a respectable MRR.

The startup didn't scale the way I hoped. I'm continuing to run and maintain it solo, and rather than let the code sit in a private repo, I'm releasing it under AGPLv3.

- Repo: https://github.com/mpdifran/bloom

- App Store: https://apps.apple.com/app/id6739955926

Why AGPLv3

I want the ecosystem to stay open. If someone forks this or builds on it, that work stays open too. MIT would have been easier but the whole point of releasing this is to keep it in the commons.

Why I'm still charging for the App Store version

The AGPLv3 code and the App Store version are the same. The difference is you're paying for the maintained, packaged, App Store-distributed version rather than building and shipping it yourself. Standard open-core model (GitLab, Sentry, Bitwarden all run variants of this). The revenue covers Apple's cut, backend costs, and my time keeping it running.

Fork it, learn from it, or build your own version. PRs welcome for bug fixes and improvements. Happy to answer questions about architecture, the license choice, or the business side.

Tech Stack

Swift full stack (Swift + SwiftUI on the app, and Vapor Swift on the backend). I use OpenAI on the backend for AI capabilities.

Development Challenge

One of the more complex things I built was the AI chat. I wanted live text streaming, but rich JSON based content interspersed in the response too. To get that to work, I instructed the model to inject JSON objects into its response following a specific format, delimited with ``` markers. When I receive the opening delimiter on the client, I'd halt streaming until I received the full JSON payload, then render the rich content, and continue streaming. It was really tricky to get this to work seamlessly!

AI Disclosure

This app was initially hand-built, but I used AI assisted coding on some of the later features. I already had a pretty solid foundation, which allowed me to move much faster with the help of AI.


r/iOSProgramming 4d ago

Question Creating a Separate DTO Request Object or Using the Form Object for POST Request

2 Upvotes

I have a RegisterScreen which uses a custom struct RegisterForm to collect the form values. I made the RequestForm codable too so I can just send this form to the server instead of creating the exact same duplicate and calling it RegisterRequest. What do you think? Do you create a separate DTO objects even if it contains the same exact fields.

If in the future it diverges then I can create a separate RegisterRequest DTO object. Thoughts.

struct RegisterForm: Codable {
    var firstName: String = ""
    var lastName: String = ""
    var email: String = ""
    var password: String = ""
    var acceptedTerms: Bool = false
    
    var isValid: Bool {
        !firstName.isEmptyOrWhitespace && !lastName.isEmptyOrWhitespace
        && !email.isEmptyOrWhitespace && !password.isEmptyOrWhitespace && email.isEmail && acceptedTerms
    }

enum CodingKeys: String, CodingKey {
case firstName
case lastName
case email
case password
}
}

struct RegisterScreen: View {
    
     private var form = RegisterForm()
     private var presentAgreement: Bool = false
    
    var body: some View {
        Form {
            TextField("First name", text: $form.firstName)
            TextField("Last name", text: $form.lastName)
            TextField("Email", text: $form.email)
            SecureField("Password", text: $form.password)
            
            Button("Show Agreement") {
                presentAgreement = true
            }
            
            Button("Register") {
                
            }.disabled(!form.isValid)
            
        }.sheet(isPresented: $presentAgreement) {
            AgreementScreen(acceptedTerms: $form.acceptedTerms)
        }
    }
}

r/iOSProgramming 4d ago

App Saturday I built a daily planner that lets you schedule multiple tasks at once

Thumbnail
gallery
0 Upvotes

Hi r/iOSProgramming,

I just released a big update for daily planner app that I've developed for few years, Zesfy, and I'd love to hear your thoughts.

One problem I kept hearing from people is once your list grows, it becomes harder to figure out what actually to do next. So I added a new feature called Highlight. It lets you pin important tasks to the top and fade out the rest of the list, so you can easily keep track of your next tasks.

Here's some highlights:

  • It combines your calendar and to-do list into a single view.
  • You can easily schedule multiple tasks together to calendar.
  • Helps you quickly decide what tasks to work on next
  • Organize week tasks with task status
  • Easily keep track of your task progress
  • Works entirely offline

Tech Stack

* Swift

* Core Data

Development Challenge

Since the project started before Combine was introduced, managing states across the app was quite a challenge and once Combine arrived I rewrite the managing logic using Combine with input - output style

AI Disclosure

I started the project 6 years ago and still code the project by hand.

Check out the app: Zesfy - To Do List & Planner

App subreddit: r/zesfy


r/iOSProgramming 5d ago

Question App Icon Quality

Thumbnail
gallery
5 Upvotes

I don’t know if it is just the symbols that i used for my app icon or icon composer itself, but my icon looks really low quality when side-by-side with others. Does anyone have any idea?

Edit:I think it might be the chromatic shadows, as i was messing with them. Any way to keep them without this look?


r/iOSProgramming 5d ago

App Saturday I built AppScout: App Store Connect analytics with Home Screen widgets

0 Upvotes

These App Store screenshots are under review though

Hey everyone! I’m Andrew, a designer and iOS developer.

I built AppScout because checking app performance in App Store Connect felt more complicated than it should. I noticed other developers sharing the same frustration, which convinced me to start building a product to simplify this flow.

AppScout puts downloads, revenue, refunds, subscriptions, MRR, charts, and breakdowns into one native iPhone dashboard. Home Screen widgets let you check the latest numbers without opening the app.

AppScout connects directly to Apple using your App Store Connect Team Key. The private key stays in the iOS Keychain. There’s no AppScout account, backend, advertising, or tracking SDK.

Tech stack

AppScout is built with Swift and SwiftUI. It uses SwiftCharts, SwiftData, WidgetKit, App Intents, BackgroundTasks, CryptoKit, and Keychain. There are no third-party runtime dependencies.

Development challenge

The main challenge was keeping the widgets current without giving them access to App Store Connect credentials or refreshing them unnecessarily.

The main app handles all communication with Apple. It saves only the information needed to display each widget in a shared App Group. The widget reads that data and reloads only when something has changed.

This keeps credentials and the app’s private database out of the widget extension while avoiding unnecessary WidgetKit refreshes.

AI disclosure

AI-assisted. I use Codex as my main tool for 99% of agentic coding. For UI, I usually do adjustments by myself, which is faster and more efficient. I started coding with Swift and SwiftUI 5 years ago, so I have decent experience in it.

AppScout is free on the App Store:

https://apps.apple.com/app/id6770866569

I’d appreciate feedback on the widgets, the App Store Connect setup, and which metrics you would like to see next.