2025 App Services
WWDC25 · 12 min · App Services
Meet PaperKit
Discover how to bring PaperKit to your iOS, iPadOS, macOS, and visionOS apps. We’ll cover how to seamlessly integrate PencilKit drawing with markup features like shapes and images, and how to customize the user interface. Learn best practices for forward compatibility, and discover advanced customization options to create truly unique markup experiences in your apps.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 6 snippets
Adopt PaperKit in iOS
// Adopt PaperKit in iOS
override func viewDidLoad() {
super.viewDidLoad()
let markupModel = PaperMarkup(bounds: view.bounds)
let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
view.addSubview(paperViewController.view)
addChild(paperViewController)
paperViewController.didMove(toParent: self)
becomeFirstResponder()
let toolPicker = PKToolPicker()
toolPicker.addObserver(paperViewController)
pencilKitResponderState.activeToolPicker = toolPicker
pencilKitResponderState.toolPickerVisibility = .visible
toolPicker.accessoryItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(plusButtonPressed(_:)))
}
@objc func plusButtonPressed(_ button: UIBarButtonItem) {
let markupEditViewController = MarkupEditViewController(supportedFeatureSet: .latest)
markupEditViewController.delegate = paperViewController
markupEditViewController.modalPresentationStyle = .popover
markupEditViewController.popoverPresentationController?.barButtonItem = button
present(markupEditViewController, animated: true)
} Adopt PaperKit in macOS
// Adopt PaperKit in macOS
override func viewDidLoad() {
super.viewDidLoad()
let markupModel = PaperMarkup(bounds: view.bounds)
let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
view.addSubview(paperViewController.view)
addChild(paperViewController)
// Create toolbar for macOS
let toolbarViewController = MarkupToolbarViewController(supportedFeatureSet: .latest)
toolbarViewController.delegate = paperViewController
view.addSubview(toolbarViewController.view)
// Set layout
setupLayoutConstraints()
} Auto-save markup changes
// Auto-save markup changes
func paperMarkupViewControllerDidChangeMarkup(_ paperMarkupViewController: PaperMarkupViewController) {
let markupModel = paperMarkupViewController.markup
Task {
// Create a data blob and save it
let data = try await markupModel.dataRepresentation()
try data.write(toFile: paperKitDataURL)
}
} Thumbnail for forward compatibility
// Thumbnail for forward compatibility
func updateThumbnail(_ markupModel: PaperMarkup) async throws {
// Set up CGContext to render thumbnail in
let thumbnailSize = CGSize(width: 200, height: 200)
let context = makeCGContext(size: thumbnailSize)
context.setFillColor(gray: 1, alpha: 1)
context.fill(renderer.format.bounds)
// Render the PaperKit markup
await markupModel.draw(in: context, frame: CGRect(origin: .zero, size: thumbnailSize))
thumbnail = context.makeImage()
} Customized markup FeatureSet
// Customized markup FeatureSet
var featureSet: FeatureSet = .latest
featureSet.remove(.text)
featureSet.insert(.stickers)
// HDR support
featureSet.colorMaximumLinearExposure = 4
toolPicker.colorMaximumLinearExposure = 4
let paperViewController = PaperMarkupViewController(supportedFeatureSet: featureSet)
let markupEditViewController = MarkupEditViewController(supportedFeatureSet: featureSet) Custom background on markup controller
// Custom background on markup controller
let template = UIImage(named: "MyTemplate.jpg")
let templateView = UIImageView(image: template)
paperViewController.contentView = templateView Resources
Related sessions
-
15 min -
10 min -
28 min