MobilePro #226: When iOS Understands the Conversation
Latest Mobile Dev Insights: iOS, Android, Cross-Platform
The best AI feature might be the one your users never notice.
The AI conversation often revolves around bigger models, better prompts, and smarter assistants. But increasingly, the most useful experiences come from intelligence that’s quietly woven into the platform itself. Instead of asking users to interact with AI directly, the operating system simply understands enough context to make the next step easier.
That’s exactly what this week’s article explores with iOS 27’s new Suggested Actions framework. By turning conversations into context-aware system actions, like creating calendar events or opening locations, Apple is showing a different direction for AI in mobile apps. It comes at an interesting time, with iOS 26.6 preparing developers for the transition to iOS 27, Claude Code bringing live iOS Simulator testing into the development workflow, and Android moving toward a more open AI ecosystem. The future of mobile development isn’t just about adding AI—it’s about knowing when the platform can do the heavy lifting for you.
TL;DR
Suggested Actions lets iOS 27 detect useful actions directly from message context.
All analysis happens on-device, helping preserve user privacy.
Developers provide conversation context while the system decides which actions are relevant.
The framework integrates naturally with SwiftUI and can also be embedded into UIKit apps.
Stable message identifiers enable action caching for a smoother experience.
This approach shifts AI from prompt-driven interactions to intelligent platform capabilities that feel native to users.
This week’s news corner
iOS 26.6 arrives with security fixes and iOS 27 readiness improvements: Apple has officially released iOS 26.6, delivering bug fixes, security updates, and an optimized Spotlight index to prepare devices for the transition to iOS 27. For iOS developers, this is the recommended build for final compatibility testing on the iOS 26 lifecycle before the platform shifts to iOS 27, making it an important milestone for validating app stability and performance.
Claude Code adds live iOS Simulator testing inside Desktop app: Anthropic has introduced an iOS Simulator pane in Claude Code Desktop (public beta), allowing developers to build, launch, inspect, and interact with iOS apps directly alongside their coding session. Claude can observe the live simulator, test UI flows, iterate on code changes, and developers can take over the simulator at any time, making the debugging and validation loop much faster.
EU orders Google to open Android AI features and search data to rivals: The European Union has issued new rules requiring Google to open key Android AI capabilities to competing assistants and share portions of its search data with rival search providers. For Android developers, the changes could create a more open ecosystem by enabling third-party AI assistants to integrate more deeply with Android and reducing Google’s control over core platform services.
A glimpse of BuildWithAI newsletter
Building with AI is quickly becoming part of every developer’s workflow. Each week, Build with AI explores practical AI engineering, agentic development, LLMs, MCP, coding tools, and the techniques shaping modern software development. Here’s a glimpse into a recent featured article:
10x value, not 10x volume: Where the real gains come from
As individual developers adopt AI assistants, we frequently hear reports of incredible velocity gains. “Copilot made me 3x faster.” “I built a whole MVP in a weekend that would have normally taken a month.”
The Factory era is not a forecast. Large engineering organizations already run in-house agent platforms against their production codebases at a scale no individual could match. That’s the organizational footprint of a practice that has moved well beyond one engineer typing faster.
While individual velocity spikes are very real, they often create a localized illusion of productivity that fails to materialize at the organizational level. Individual speed is a false summit. You feel like you have reached the top because your own keyboard is faster, but cycle time and the team’s DORA numbers stay flat until the system around the agent changes. The climb that matters has barely started.
Why does the gain vanish? Because of the Theory of Constraints.
In any system, improving the throughput of a non-bottleneck step does not improve the throughput of the whole system; it just moves the bottleneck somewhere else. If you make code generation ten times faster, but your code review processes, security audits, QA testing cycles, and deployment pipelines remain manual, you haven’t delivered value to the user ten times faster. You have merely stockpiled a 10x backlog of unverified code waiting to pass through the human bottleneck downstream.
This is why the obsession with 10x volume, with raw output or hyper-productive individual vibe coders, misses the broader goal. The real gains of the AI transformation do not come from individuals typing faster. They come from 10x value: delivered, verified work that reaches the user. And that value comes from designing the team and the system around the agent, not from speeding up the individual at the keyboard.
Agentic engineering looks at the entire software development lifecycle (SDLC) holistically. It measures success not by how many lines of code a single individual produces in an hour, but by how dependably the organization ships verified solutions. To track this, agentic teams align closely with the DORA metrics. Originally designed to measure human operational excellence, these metrics become the ultimate lifeline when scaling autonomous agents.
Building Smarter Messaging Apps with Suggested Actions, Not Custom Prompts
Anton Gubarenko is an Independent iOS Consultant, Mentor, and Startup Advisor with 16+ years of experience building mobile products. He has worked with companies around the world, from the United States to New Zealand, helping teams design scalable architectures and deliver high-quality iOS applications. Anton continuously follows the latest developments in the Apple ecosystem by exploring Swift and iOS conferences, and shares his knowledge with the global developer community through writing, mentoring, and speaking.
Apple added a small framework in iOS 27 that can turn message content into useful actions without requiring a custom language-model prompt.
SuggestedActionsView analyzes the message context you provide and displays relevant actions directly below a message. A conversation about watching a movie, for example, can produce an action for adding the agreed cinema time to Calendar.
The analysis happens on-device, and the framework does not send the message content to Apple servers.
This feature is still in beta and might change before the final release.
What Suggested Actions can detect
The framework looks for actionable information inside a conversation. Apple currently highlights examples such as:
creating a Calendar event from a proposed time
adding an item to Reminders
opening a shared place in Maps
You do not define the buttons yourself. You provide the current message and some previous messages, and the system decides whether an action is appropriate.
If no action is available, SuggestedActionsView has zero size and does not add an empty gap to the layout. This means it can safely be added below every message cell.
MessageKit or SwiftUI?
MessageKit does not provide native SwiftUI message cells. It is a UIKit-based library built around MessagesViewController, MessagesCollectionView, and MessageContentCell.
For this example, a small custom SwiftUI chat works better. It also lets us place SuggestedActionsView directly below each message without wrapping it in UIKit.
A production UIKit chat can still use the framework by hosting SuggestedActionsView inside a UIHostingController or UIHostingConfiguration.
Chat model
The visual message model contains an optional image, but SuggestedActionsMessage receives the textual message context only:
import Foundation
import SwiftUI
import SuggestedActions
struct ChatMessage: Identifiable {
let id: UUID
let sender: Participant
let text: String
let imageName: String?
let date: Date
struct Participant: Hashable {
let name: String
let handle: String
let isCurrentUser: Bool
}
var suggestedActionsMessage: SuggestedActionsMessage {
SuggestedActionsMessage(
id: id,
date: date,
subject: nil,
body: AttributedString(text),
sender: .init(
name: sender.name,
handle: sender.handle,
isUser: sender.isCurrentUser
),
recipients: []
)
}
}The id matters because the framework uses it when caching generated actions.
For a real one-to-one conversation, populate recipients with the other participant instead of leaving it empty.
Demo conversation
The sample conversation has two friends choosing a movie and agreeing to meet at the cinema:
extension ChatMessage {
static let anton = Participant(
name: “Anton”,
handle: “anton@example.com”,
isCurrentUser: true
)
static let maya = Participant(
name: “Maya”,
handle: “maya@example.com”,
isCurrentUser: false
)
static let demo: [ChatMessage] = [
ChatMessage(
id: UUID(),
sender: maya,
text: “These are the movies showing this weekend.”,
imageName: “movie-posters”,
date: .now.addingTimeInterval(-300)
),
ChatMessage(
id: UUID(),
sender: anton,
text: “Let’s watch The Last Horizon on Saturday.”,
imageName: nil,
date: .now.addingTimeInterval(-240)
),
ChatMessage(
id: UUID(),
sender: maya,
text: “The 19:30 screening at Central Cinema works for me.”,
imageName: nil,
date: .now.addingTimeInterval(-180)
),
ChatMessage(
id: UUID(),
sender: anton,
text: “Great. Let’s meet there. Will add to notes to bring your favourite popcorn!”,
imageName: nil,
cinemaLocation: nil,
date: .now.addingTimeInterval(-120)
)
]
}The last two messages give the framework enough context to recognize a date, time, and cinema-related plan.
SwiftUI message cell
The cell displays an optional image, a message bubble, and the system-provided actions underneath:
struct MessageCell: View {
let message: ChatMessage
let previousMessages: [ChatMessage]
var body: some View {
VStack(
alignment: message.sender.isCurrentUser
? .trailing
: .leading,
spacing: 8
) {
if let imageName = message.imageName {
Image(imageName)
.resizable()
.scaledToFill()
.frame(width: 240, height: 150)
.clipShape(
RoundedRectangle(cornerRadius: 18)
)
}
Text(message.text)
.padding(.horizontal, 14)
.padding(.vertical, 10)
.background(
message.sender.isCurrentUser
? Color.accentColor
: Color.secondary.opacity(0.15)
)
.foregroundStyle(
message.sender.isCurrentUser
? .white
: .primary
)
.clipShape(
RoundedRectangle(cornerRadius: 18)
)
SuggestedActionsView(
message: message.suggestedActionsMessage,
previousMessages: previousMessages
.suffix(
SuggestedActionsMessage
.previousMessagesLimit
)
.map(\.suggestedActionsMessage)
)
.buttonBorderShape(.capsule)
.tint(.blue)
.font(.callout)
}
.frame(
maxWidth: .infinity,
alignment: message.sender.isCurrentUser
? .trailing
: .leading
)
}
}There is no conditional around SuggestedActionsView. When the system has nothing useful to show, the view collapses to zero size.
Complete chat screen
struct MovieChatView: View {
private let messages = ChatMessage.demo
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(
Array(messages.enumerated()),
id: \.element.id
) { index, message in
MessageCell(
message: message,
previousMessages: Array(
messages.prefix(index)
)
)
}
}
.padding()
}
.navigationTitle(”Movie Night”)
}
}Each cell receives only the messages that appeared before it. This prevents a future reply from influencing an earlier suggestion.
The framework also limits how much previous context it accepts. Applying previousMessagesLimit keeps the input within the supported range.
This is how a generated actions are looking in Simulator. Location and Calendar are linked to the corresponding cells. Amazing!
Pre-generating Actions
SuggestedActionsView can generate actions when it appears, but that may briefly show a loading state.
You can generate and cache the result earlier:
private func prepareActions(
for message: ChatMessage,
previousMessages: [ChatMessage]
) async {
await SuggestedActionsView.generate(
message: message.suggestedActionsMessage,
previousMessages: previousMessages
.suffix(
SuggestedActionsMessage
.previousMessagesLimit
)
.map(\.suggestedActionsMessage)
)
}Required entitlement
The framework requires the Suggested Actions entitlement:
com.apple.developer.suggested-actionsAdd the Suggested Actions capability to the app target before testing the view.
The entitlement defaults to false, so importing the framework and adding the view is not enough by itself.
What the App controls
The application provides:
the current message
a limited amount of previous context
participant names and handles
the surrounding layout and visual modifiers
The system controls:
whether an action is relevant
which action appears
the button content
the action’s system behavior
This is different from Foundation Models. There is no prompt, LanguageModelSession, custom schema, or tool implementation. Suggested Actions is a focused system feature for messaging interfaces.
Where it fits
The framework is useful for chat, email, support, collaboration, and marketplace apps where messages regularly contain dates, reminders, or locations.
It should not be treated as a replacement for app-specific actions. If a cinema app needs a guaranteed Buy Tickets button, that action still belongs to the application. Suggested Actions is better for contextual system tasks that may or may not apply to a particular message.
💭 Let’s Talk
What’s one repetitive task in your app you’d love the platform to handle automatically?
Reply and let us know.
Advertise with us
Interested in sponsoring this newsletter and reaching a highly engaged audience of tech professionals? Simply reply to this email and our team will get in touch with next steps.




