2025 App ServicesAI & Machine Learning
WWDC25 · 18 min · App Services / AI & Machine Learning
Dive deeper into Writing Tools
With Writing Tools, people can proofread, rewrite, and transform text directly within your app. Learn advanced techniques to customize Writing Tools for your app. Explore formatting options and how they work with rich text editing. If you have a custom text engine, learn how to seamlessly integrate the complete Writing Tools experience, allowing edits directly within the text view.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 8 snippets
Attach a coordinator to the view (UIKit)
// Attach a coordinator to the view
// UIKit
func configureWritingTools() {
guard UIWritingToolsCoordinator.isWritingToolsAvailable else { return }
let coordinator = UIWritingToolsCoordinator(delegate: self)
addInteraction(coordinator)
} Attach a coordinator to the view (AppKit)
// Attach a coordinator to the view
// AppKit
func configureWritingTools() {
guard NSWritingToolsCoordinator.isWritingToolsAvailable else { return }
let coordinator = NSWritingToolsCoordinator(delegate: self)
coordinator.preferredBehavior = .complete
coordinator.preferredResultOptions = [.richText, .list]
writingToolsCoordinator = coordinator
} Prepare the context
// Prepare the context
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
requestsContextsFor scope: NSWritingToolsCoordinator.ContextScope,
completion: @escaping ([NSWritingToolsCoordinator.Context]) -> Void) {
var contexts = [NSWritingToolsCoordinator.Context]()
switch scope {
case .userSelection:
let context = getContextObjectForSelection()
contexts.append(context)
break
// other cases…
}
// Save references to the contexts for later delegate calls.
storeContexts(contexts)
completion(contexts)
} Respond to text changes from Writing Tools and update selected range
// Respond to text changes from Writing Tools
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
replace range: NSRange,
in context: NSWritingToolsCoordinator.Context,
proposedText replacementText: NSAttributedString,
reason: NSWritingToolsCoordinator.TextReplacementReason,
animationParameters: NSWritingToolsCoordinator.AnimationParameters?,
completion: @escaping (NSAttributedString?) -> Void) {
}
// Update selected range
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
select ranges: [NSValue],
in context: NSWritingToolsCoordinator.Context,
completion: @escaping () -> Void) {
} Generate preview for animation (AppKit)
// Generate preview for animation (macOS)
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
requestsPreviewFor textAnimation: NSWritingToolsCoordinator.TextAnimation,
of range: NSRange,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping ([NSTextPreview]?) -> Void) {
}
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
requestsPreviewFor rect: NSRect,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping (NSTextPreview?) -> Void) {
} Generate preview for animation (UIKit)
// Generate preview for animation (iOS)
func writingToolsCoordinator(_ writingToolsCoordinator: UIWritingToolsCoordinator,
requestsPreviewFor textAnimation: UIWritingToolsCoordinator.TextAnimation,
of range: NSRange,
in context: UIWritingToolsCoordinator.Context,
completion: @escaping (UITargetedPreview?) -> Void) {
} Delegate callbacks before and after animation
// Generate preview for animation
func writingToolsCoordinator(
_ writingToolsCoordinator: NSWritingToolsCoordinator,
prepareFor textAnimation: NSWritingToolsCoordinator.TextAnimation,
for range: NSRange,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping () -> Void) {
// Hide the specific range of text from the text view
}
func writingToolsCoordinator(
_ writingToolsCoordinator: NSWritingToolsCoordinator,
finish textAnimation: NSWritingToolsCoordinator.TextAnimation,
for range: NSRange,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping () -> Void) {
// Show the specific range of text again
} Delegate callbacks to show proofreading marks
// Create proofreading marks
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
requestsUnderlinePathsFor range: NSRange,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping ([NSBezierPath]) -> Void) {
}
func writingToolsCoordinator(_ writingToolsCoordinator: NSWritingToolsCoordinator,
requestsBoundingBezierPathsFor range: NSRange,
in context: NSWritingToolsCoordinator.Context,
completion: @escaping ([NSBezierPath]) -> Void) {
} Resources
Related sessions
-
12 min