A Flutter plugin for enhanced clipboard functionality with iOS UIPasteboard support.
Starting with iOS 14, Apple introduced a privacy feature that shows a notification banner whenever an app reads from the clipboard:
"App would like to paste from Other App"
This notification appears every time your app calls Clipboard.getData(), even if you just want to check if the clipboard contains a URL. This creates a poor user experience:
- Users see the paste notification even when the clipboard contains irrelevant content (like plain text when your app only cares about URLs)
- Users may become suspicious or annoyed by frequent clipboard access notifications
- There's no way to silently check clipboard content type before reading
iOS provides UIPasteboard properties that check content types without triggering the paste notification:
| Property | Description |
|---|---|
hasURLs |
Check if clipboard contains URLs |
hasStrings |
Check if clipboard contains text |
hasImages |
Check if clipboard contains images |
hasColors |
Check if clipboard contains colors |
detectPatterns(for:) |
Check if clipboard text looks like a URL (iOS 14+) |
hasURLs alone is only true for URL-typed items (e.g. Safari's "Copy Link").
A link copied as plain text — navigator.clipboard.writeText, most "Copy"
buttons, typed text — has no URL type, so hasUrls() also runs
detectPatterns for probableWebURL, which inspects the text without
reading it.
This plugin exposes these APIs to Flutter, allowing you to:
- Silently check if the clipboard has content your app cares about
- Only request access when relevant content is present
- Provide a better UX by avoiding unnecessary permission dialogs
dependencies:
clipboard_plus: ^1.0.4Or run:
flutter pub add clipboard_plusimport 'package:clipboard_plus/clipboard_plus.dart';
// Check for URLs - NO permission dialog on iOS
final hasUrls = await ClipboardPlus.hasUrls();
// Check for strings - NO permission dialog on iOS
final hasStrings = await ClipboardPlus.hasStrings();
// Check for images - NO permission dialog on iOS
final hasImages = await ClipboardPlus.hasImages();
// Check for colors - NO permission dialog on iOS
final hasColors = await ClipboardPlus.hasColors();
// Or get all types at once
final types = await ClipboardPlus.getContentTypes();
if (types.hasUrls) {
// Clipboard has a URL
}// Get URL
final url = await ClipboardPlus.getUrl();
// Get text
final text = await ClipboardPlus.getText();
// Get image as PNG bytes
final Uint8List? imageBytes = await ClipboardPlus.getImage();// Set text
await ClipboardPlus.setText("Hello, World!");
// Clear clipboard
await ClipboardPlus.clear();Future<void> checkForCopiedUrl() async {
// Step 1: Silently check if clipboard has a URL (no dialog)
final hasUrl = await ClipboardPlus.hasUrls();
if (!hasUrl) {
// Clipboard doesn't have a URL - do nothing
// User never sees any permission dialog!
return;
}
// Step 2: Clipboard has a URL, now read it (shows permission dialog)
final url = await ClipboardPlus.getUrl();
if (url != null) {
// Step 3: Ask user if they want to use the URL
showSaveUrlDialog(url);
}
}| Platform | Silent Check (hasX) | Read Content |
|---|---|---|
| iOS | Native UIPasteboard APIs | Shows permission dialog |
| Android | ClipboardManager | No permission dialog |
Note: On Android, there are no clipboard permission dialogs like iOS, but
Android 12+ shows a "pasted from your clipboard" notice whenever an app reads
the clip. On Android 12+ hasUrls() uses the system's text classification of
the clip (no read, no notice) when it is available, and only falls back to
reading the text when the system has not classified it.
| Method | Returns | Description |
|---|---|---|
hasUrls() |
Future<bool> |
Check if clipboard has URLs |
hasStrings() |
Future<bool> |
Check if clipboard has text |
hasImages() |
Future<bool> |
Check if clipboard has images |
hasColors() |
Future<bool> |
Check if clipboard has colors |
getContentTypes() |
Future<ClipboardContentType> |
Check all types at once |
| Method | Returns | Description |
|---|---|---|
getUrl() |
Future<String?> |
Get URL from clipboard |
getText() |
Future<String?> |
Get text from clipboard |
getImage() |
Future<Uint8List?> |
Get image as PNG bytes |
| Method | Returns | Description |
|---|---|---|
setText(String) |
Future<void> |
Set text to clipboard |
clear() |
Future<void> |
Clear the clipboard |
hasStrings(),getText(), andsetText()delegate to Flutter's built-inClipboardclasshasUrls(),hasImages(),hasColors(),getUrl(), andgetImage()use native platform channels- This provides a unified API while avoiding code duplication
MIT
Maintained by Abdelrahman Saed — more Flutter packages & case studies.
