I was rewatching the September 9 event late at night on the iMac at home. I stopped on a single line: iOS 27 ships on September 14.
What came to mind was not the new Siri. It was the handful of places in my own apps where I call the Gemini API.
Will those stop working next week?
They will not. But it took me a while to be able to say clearly why they will not, and I would rather write down the order in which I checked things than the tidy conclusion alone.
The short answer: nothing breaks on September 14
Let me start with what is on the record.
iOS 27 was announced at WWDC on June 8, 2026, and Apple set the release date at the September 9 event: September 14. The headline feature is a rebuilt Siri, and both Apple and Google have said publicly that it is built on Google's Gemini.
That is the news. The developer meaning sits one layer below it.
The requests your app sends to generativelanguage.googleapis.com travel a completely separate path from Apple's update. The endpoint, the API key, the model ID — none of them change because the operating system moved forward. There is, in principle, no code you need to check in a panic on the morning of the 14th.
What gets smarter inside the device and what I pay to call are two different ledgers. Putting that line down first makes sorting the next few weeks of announcements much easier.
Separating three layers at the call site
For a while I lumped all of this together as "AI on the iPhone." That did not serve me well. Every time a spec detail surfaced, I could not immediately say which part of my own code it touched, and one afternoon disappeared into checking.
These days I split it like this.
| Layer | Who runs it | How a developer touches it | Who pays |
|---|---|---|---|
| Siri AI (built into the OS) | Apple | You offer your app's capabilities through App Intents | No cost |
| Foundation Models framework | On device, or Private Cloud Compute | You call it from Swift | Free tier under certain conditions |
| Gemini API | Your app, or your own server | HTTPS and an API key | Your own usage billing |
App Intents is how you say to Siri AI, "here is what my app can do." In iOS 27 the framework connects your app's actions to Siri AI capabilities such as personal context, app actions, and onscreen awareness. You are offering, not calling — and that is what separates it cleanly from the third row.
I mirror the same split in code. Every text-generation entry point in my apps goes through one protocol, so the implementation behind it can be swapped without touching anything else.
import Foundation
protocol TextGenerator {
func generate(prompt: String) async throws -> String
}
enum GeneratorError: Error {
case http(status: Int, body: String)
case emptyResponse
}
struct GeminiGenerator: TextGenerator {
let apiKey: String // read from Keychain; never hardcode it in source
let model: String
func generate(prompt: String) async throws -> String {
let url = URL(string: "https://generativelanguage.googleapis.com/v1beta/models/\(model):generateContent")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue(apiKey, forHTTPHeaderField: "x-goog-api-key")
request.httpBody = try JSONSerialization.data(withJSONObject: [
"contents": [["parts": [["text": prompt]]]]
])
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse else {
throw GeneratorError.emptyResponse
}
guard (200..<300).contains(http.statusCode) else {
throw GeneratorError.http(
status: http.statusCode,
body: String(data: data, encoding: .utf8) ?? ""
)
}
let decoded = try JSONDecoder().decode(GeminiResponse.self, from: data)
guard let text = decoded.candidates?.first?.content?.parts?.compactMap(\.text).first,
text.isEmpty == false else {
throw GeneratorError.emptyResponse
}
return text
}
}
struct GeminiResponse: Decodable {
struct Candidate: Decodable {
struct Content: Decodable {
struct Part: Decodable { let text: String? }
let parts: [Part]?
}
let content: Content?
}
let candidates: [Candidate]?
}The caller knows nothing about the implementation.
let generator: TextGenerator = GeminiGenerator(
apiKey: ProcessInfo.processInfo.environment["YOUR_API_KEY"] ?? "",
model: "gemini-3.8-flash"
)
let caption = try await generator.generate(prompt: "Write one short sentence describing this wallpaper.")The reason I write it this way is narrow and practical. If I decide to add a second implementation after September 14, the change is one new type conforming to TextGenerator. The view code stays untouched, and so does the persistence layer. Draw the boundary early and outside changes stop short of the inside of your app.
What it means that Foundation Models now accepts any provider
This was the part of the June announcements I kept coming back to.
The Foundation Models framework supports multimodal prompts and any provider that conforms to the Language Model protocol — not only Apple's own models. Custom skills and server-side model execution came along with it.
So for features that live inside an app, the question is no longer simply "Apple's model or Gemini." You can put the entry point inside Apple's framework and decide separately which model sits behind it.
That said, this applies to what runs inside the app. Several places where I use Gemini are not inside an app at all. Sorting image categories in bulk, or shaping store copy across languages, runs from scripts on my own machine rather than on a phone. Those stay outside Apple's framework — and I think they should.
The free tier, and why I am keeping the Gemini API anyway
There is one condition an indie developer should not skim past.
If you are enrolled in the App Store Small Business Program and your app has fewer than 2 million total first-time downloads, you can use the next generation of Apple Foundation Models on Private Cloud Compute with no cloud API cost. Whether your own app qualifies is worth checking against your actual numbers.
"Free" is tempting. I briefly wanted to move everything. Then I wrote down three reasons to keep the Gemini API, and the decision stopped being simple.
The first is shipping the same feature on platforms other than Apple's. Build one side on a different mechanism and the outputs drift apart, and you spend later releases reconciling them.
The second is choosing and pinning the model myself. The habit of checking which model is GA and which is preview before committing only works when that choice belongs to me. I wrote about how I make that call in the strongest model is in preview while the cheap one is GA.
The third is batch work that never touches a device. Jobs that run overnight simply have no home inside an app.
So my answer was not one or the other. Decide placement feature by feature, and keep both. When you estimate cost, look at how call volume grows rather than the unit price alone — I covered that in Gemini 3.8 Flash can raise your bill even with the price held flat.
The four things I finish before September 14
Four days are left, so nothing ambitious. I narrowed it to these.
- Inventory the model IDs. Collect every string starting with
gemini-into one configuration point. How much work a future swap costs is decided right here. - Check the failure path. Networks get busy right after a release. I only want to know that a failed generation does not leave a screen blank and stuck.
- Do not raise the minimum iOS version. New APIs are tempting, but narrowing your supported range days after a release strands the people who have not updated. This can wait.
- Draft the support reply. Reviews and questions spike after an OS update. "Siri changed — why hasn't this app?" is a question I assume will arrive, so I write the reply before it does.
The fourth one is not a technical task, and it is the one that consumed the most time on past release days. Writing it once in advance changes how the day feels.
What is still unconfirmed
Let me draw the line honestly.
Which Gemini model runs behind Siri, where inference happens, and whether any of it is visible to developers — none of that is settled in what has been published. Reporting has also run ahead of confirmation on the size of the agreement.
So in articles and in my own notes, I stop at "has been reported" for anything I cannot verify. A single overstatement makes the accurate sentences around it look doubtful too. The more urgent a topic feels, the thicker I want that line drawn.
Start by collecting the scattered model ID strings into one place. That is the only item I plan to finish before September 14 myself.
Thank you for reading.