Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2024 AI & Machine LearningSwiftUI & UI Frameworks

WWDC24 · 12 min · AI & Machine Learning / SwiftUI & UI Frameworks

Get started with Writing Tools

Learn how Writing Tools help users proofread, rewrite, and transform text in your app. Get the details on how Writing Tools interact with your app so users can refine what they have written in any text view. Understand how text is retrieved and processed, and how to support Writing Tools in custom text views.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 8 snippets

Text view delegate methods for Writing Tools swift · at 5:28 ↗
func textViewWritingToolsWillBegin(_ textView: UITextView) {
    // Take necessary steps to prepare. For example, disable iCloud sync.
}

func textViewWritingToolsDidEnd(_ textView: UITextView) {
    // Take necessary steps to recover. For example, reenable iCloud sync.
}

if !textView.isWritingToolsActive {
    // Do work that needs to be avoided when Writing Tools is interacting with text view
    // For example, in the textViewDidChange callback, app may want to avoid certain things
       when Writing Tools is active
}
Opt-out of the full experience swift · at 7:11 ↗
textView.writingToolsBehavior = .limited

textView.writingToolsBehavior = .none
Specify accepted text formats swift · at 7:31 ↗
textView.writingToolsAllowedInputOptions = [.plainText]

textView.writingToolsAllowedInputOptions = [.plainText, .richText, .table]
WKWebView swift · at 7:55 ↗
// For `WKWebView`, the `default` behavior is equivalent to `.limited`

extension WKWebViewConfiguration {
    @available(iOS 18.0, *)
    open var writingToolsBehavior: UIWritingToolsBehavior { get set }
}

extension WKWebViewConfiguration {
    @available(macOS 15.0, *)
    open var writingToolsBehavior: NSWritingToolsBehavior { get set }
}

extension WKWebView {
    /// @discussion If the Writing Tools behavior on the configuration is `.limited`, this will always be `false`.
    @available(iOS 18.0, macOS 15.0, *)
    open var isWritingToolsActive: Bool { get }
}
Protecting ranges swift · at 8:48 ↗
// Returned `NSRange`s are relative to the substring of the textView’s textStorage from `enclosingRange`
func textView(_ textView: UITextView, writingToolsIgnoredRangesIn
        enclosingRange: NSRange) -> [NSRange] {
    let text = textView.textStorage.attributedSubstring(from: enclosingRange)
    return rangesInappropriateForWritingTools(in: text)
}
Indicate your text view supports editing swift · at 9:58 ↗
protocol UITextInput {
    @available(iOS 18.0, macOS 15.0, *)
    optional var isEditable: Bool { get }
}
Simple view that supports Copy swift · at 10:58 ↗
class CustomTextView: NSView, NSServicesMenuRequestor {
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        
        self.menu = NSMenu()
        self.menu?.addItem(NSMenuItem(title: "Custom Text View", action: nil,
            keyEquivalent: ""))
        self.menu?.addItem(NSMenuItem(title: "Copy", action: #selector(copy(_:)), 
            keyEquivalent: ""))
    }
  
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
        
        // Custom text drawing code...
    }
}
View extension to support Writing Tools swift · at 11:05 ↗
class CustomTextView: NSView, NSServicesMenuRequestor {
    override func validRequestor(forSendType sendType: NSPasteboard.PasteboardType?, 
                                 returnType: NSPasteboard.PasteboardType?) -> Any? {
        if sendType == .string || sendType == .rtf {
            return self
        }
        return super.validRequestor(forSendType: sendType, returnType: returnType)
    }
    
    nonisolated func writeSelection(to pboard: NSPasteboard,
                                    types: [NSPasteboard.PasteboardType]) -> Bool {
        // Write plain text and/or rich text to pasteboard
        return true
    }

    // Implement readSelection(from pboard: NSPasteboard)
       as well for editable view
}

Resources