Using UIPasteControl in a UIMenu in iOS 16

In iOS 15, Apple took a step in the direction of user privacy by introducing small toast notifications every time an app accessed a users clipboard. You would all be familiar with them, they looked like this:


In iOS 16, Apple took it one further by removing the ability for apps to read the clipboard at will, instead throwing up a permission dialog every time an app attempted to read from UIPasteboard.

An example from Penbook

Introducing UIPasteControl

Apple’s answer to this was a new UIKit control called UIPasteControl, it works simply enough, you assign it a configuration and a target, and it’ll paste into your target when the button is tapped, all without user confirmation. That’s all well and good, but what if you read from the clipboard in a UIMenu?

Pestle supports creating recipes from links pasted from the clipboard.

Given that UIPasteControl is a component from UIKit, we can’t use it in UIMenu

Those identifiers we ignored

Apple’s documentation states that when instantiating a UIAction, we can pass nil to the identifier argument for the method to create a unique identifier for us.

identifier
The unique identifier for the action. Specify nil to let this method create a unique identifier for you.

Apple Documentation

And so for the most part, we ignore that identifier field. But it’s actually very useful! While you’ll need to give-up come control (like using your own SFSymbol or using a custom tile), we can pass a static variable from UIAction.Identifier to signal to iOS what we want our action to do.

Paste Identifiers

When it comes to paste controls, Apple defines 4 types:

  • paste
  • pasteAndGo
  • pasteAndMatchStyle
  • pasteAndSearch

By using one of these identifiers for your UIAction, iOS will let you access the pasteboard without additional user consent, as this system action is considered consensual.

Example

let menu = UIMenu(children: [     
    UIAction(identifier: UIAction.Identifier.paste, handler: { _ in     
        print(UIPasteboard.general.url) //Despite accessing the UIPasteboard here, no additional warning is given.     
    })
])

I’m using this in Pestle in iOS 16 and it works great 🙂

Remember, you can still query the UIPasteboard without reading the contents of it, combining a query with the above code ensures Paste is never shown to the user unless a relevant item is already on the clipboard.