iOS System Integration
Ios system integration

Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations.
# iOS System Integration Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations. ## Table of Contents 1. [Siri Integration](#siri-integration) 2. [Shortcuts App Integration](#shortcuts-app-integration) 3. [Handoff](#handoff) 4. [Drag and Drop](#drag-and-drop) 5. [Universal Links](#universal-links) 6. [Spotlight Search](#spotlight-search) 7. [Focus & Notifications](#focus-notifications) 8. [Quick Note Integration](#quick-note-integration) 9. [SharePlay](#shareplay) 10. [System Appearance](#system-appearance) 11. [Best Practices Summary](#best-practices-summary)
Overview
Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations.
Manual install (npx, ZIP)
npx skills add wondelai/skills --skill ios-system-integration -g -a claude-codeConnects with Agent Alley MCP · agentalley.io/mcp
Files included
system-integration.md9.3 KB
Read system-integration.md here
wondelai/
Show the full text429 lines
iOS System Integration
Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations.
Table of Contents
- Siri Integration
- Shortcuts App Integration
- Handoff
- Drag and Drop
- Universal Links
- Spotlight Search
- Focus & Notifications
- Quick Note Integration
- SharePlay
- System Appearance
- Best Practices Summary
Siri Integration
SiriKit Domains
Your app can integrate with Siri through predefined domains:
| Domain | Example Intents |
|---|---|
| Messaging | Send message, search messages |
| Lists & Notes | Create note, add to list |
| Payments | Send payment, request payment |
| Workouts | Start workout, end workout |
| Media | Play media, add to library |
| Ride booking | Request ride, get ride status |
| Car commands | Lock car, get car status |
| Visual codes | Look up barcode, QR code |
Designing for Voice
Confirmation dialogs:
Siri: "Send $50 to Sarah for dinner?"
User: "Yes" / "Change amount" / "Cancel"
Guidelines:
- Confirm significant actions
- Allow easy correction
- Provide visual feedback alongside voice
- Handle ambiguity gracefully
Custom Intents
For actions not in predefined domains:
// Define in Intents.intentdefinition
Intent: OrderCoffee
Parameters: coffeeType, size, location
Best practices:
- Use descriptive parameter names
- Provide good examples
- Support synonyms
- Test with various phrasings
Siri Shortcuts
Allow users to create custom voice triggers:
// Donate shortcut when user completes action
let activity = NSUserActivity(activityType: "com.app.order-favorite")
activity.title = "Order my usual coffee"
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
activity.suggestedInvocationPhrase = "Order my usual"
view.userActivity = activity
Guidelines:
- Donate shortcuts for repeated actions
- Suggest clear invocation phrases
- Provide relevant parameters
- Test in Shortcuts app
Shortcuts App Integration
App Shortcuts (iOS 16+)
Pre-built shortcuts that appear automatically:
struct MyAppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OrderCoffeeIntent(),
phrases: [
"Order coffee with \(.applicationName)",
"Get my usual from \(.applicationName)"
],
shortTitle: "Order Coffee",
systemImageName: "cup.and.saucer.fill"
)
}
}
Shortcut Actions
Expose app functionality as Shortcuts actions:
Good candidates:
- Actions users repeat frequently
- Actions that can run without UI
- Data that can be passed to other apps
- Automatable workflows
Design considerations:
- Clear action names (verb + object)
- Meaningful parameters with defaults
- Useful outputs for chaining
- Error messages that explain what went wrong
Handoff
Enabling Handoff
Allow users to continue activities across Apple devices:
let activity = NSUserActivity(activityType: "com.app.viewing-item")
activity.title = "Viewing Product: \(product.name)"
activity.userInfo = ["productID": product.id]
activity.isEligibleForHandoff = true
activity.webpageURL = URL(string: "https://myapp.com/product/\(product.id)")
userActivity = activity
Handoff Guidelines
Do:
- Continue at exactly where user left off
- Restore scroll position, form state, etc.
- Support universal links as fallback
- Update activity as context changes
Don't:
- Require re-authentication
- Lose user's work
- Show significantly different content
Web Fallback
If app isn't installed on receiving device:
activity.webpageURL = URL(string: "https://myapp.com/activity/\(id)")
Drag and Drop
Supporting Drag
.draggable(item) {
// Drag preview
ItemPreview(item: item)
}
Supporting Drop
.dropDestination(for: ItemType.self) { items, location in
// Handle dropped items
return true
}
Drag and Drop Guidelines
Visual feedback:
- Show clear drag preview
- Indicate valid drop targets
- Animate transitions smoothly
Multi-item:
- Support selecting multiple items
- Stack preview for multiple items
- Handle batch operations
Cross-app:
- Export standard data types (images, text, URLs)
- Accept common formats
- Maintain quality during transfer
Platform Considerations
| Platform | Drag Initiation |
|---|---|
| iPhone | Long press + drag (within app) |
| iPad | Long press or tap + drag |
| Mac (Catalyst) | Click + drag |
Universal Links
Setting Up
- Configure
apple-app-site-associationon your server:
{
"applinks": {
"apps": [],
"details": [{
"appID": "TEAMID.com.example.app",
"paths": ["/product/*", "/user/*"]
}]
}
}
- Add Associated Domains capability:
applinks:example.com
Handling Links
func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return false
}
return handleUniversalLink(url)
}
Best Practices
- Parse URLs robustly (handle malformed links)
- Navigate to appropriate screen
- Show content immediately (don't require login first)
- Fall back gracefully if content unavailable
Spotlight Search
Indexing Content
let attributeSet = CSSearchableItemAttributeSet(contentType: .text)
attributeSet.title = item.title
attributeSet.contentDescription = item.description
attributeSet.thumbnailData = item.thumbnailData
let searchableItem = CSSearchableItem(
uniqueIdentifier: item.id,
domainIdentifier: "com.app.items",
attributeSet: attributeSet
)
CSSearchableIndex.default().indexSearchableItems([searchableItem])
What to Index
Good candidates:
- User content (notes, documents)
- Saved items (favorites, history)
- Frequently accessed items
Avoid:
- Sensitive data
- Transient content
- Every possible item (be selective)
Search Result Design
Results appear in Spotlight:
┌─────────────────────────────────────────┐
│ 🔲 My Note Title │
│ Preview of note content... │
│ MyApp │
└─────────────────────────────────────────┘
Include:
- Clear title
- Helpful description
- Thumbnail if visual
- Accurate metadata
Focus & Notifications
Focus Awareness
Respect user's Focus mode:
UNUserNotificationCenter.current().getNotificationSettings { settings in
if settings.notificationCenterSetting == .disabled {
// User has notifications silenced
}
}
Time Sensitive Notifications
For truly urgent notifications:
let content = UNMutableNotificationContent()
content.title = "Your ride is here"
content.interruptionLevel = .timeSensitive
Use only when:
- Immediate action required
- User explicitly opted in
- Content is genuinely time-sensitive
Quick Note Integration
Adding Quick Note Capability
Allow highlighting content for Quick Note:
Text(content)
.contextMenu {
Button("Add to Quick Note") {
// System handles this
}
}
SharePlay
When to Use SharePlay
- Watching content together
- Collaborative activities
- Shared experiences
SharePlay Guidelines
Sync state:
- Keep all participants in sync
- Handle network latency gracefully
- Provide individual controls where appropriate
Visual design:
- Show who's in the session
- Indicate when others interact
- Provide easy leave option
System Appearance
Supporting Dark Mode
// Adaptive colors
Color.primary // Auto light/dark
Color.secondary // Auto light/dark
// Custom adaptive colors
extension Color {
static let background = Color("Background") // From asset catalog
}
Supporting Dynamic Type
Text("Title")
.font(.title) // Scales with Dynamic Type
// Custom scalable fonts
.font(.custom("MyFont", size: 17, relativeTo: .body))
Supporting Accessibility
Text("Content")
.accessibilityLabel("Detailed description")
.accessibilityHint("Tap to view details")
Best Practices Summary
| Integration | Key Consideration |
|---|---|
| Siri | Clear confirmation, handle ambiguity |
| Shortcuts | Expose repeatable, automatable actions |
| Handoff | Preserve exact state across devices |
| Drag & Drop | Clear previews, multi-item support |
| Universal Links | Deep link to specific content |
| Spotlight | Index valuable, non-sensitive content |
| Focus | Respect user's notification preferences |
Universal principle: System integrations should feel seamless—users shouldn't think about which device or app they're using.
| 1 | # iOS System Integration |
| 2 | |
| 3 | Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations. |
| 4 | |
| 5 | |
| 6 | ## Table of Contents |
| 7 | [Siri Integration] |
| 8 | [Shortcuts App Integration] |
| 9 | [Handoff] |
| 10 | [Drag and Drop] |
| 11 | [Universal Links] |
| 12 | [Spotlight Search] |
| 13 | [Focus & Notifications] |
| 14 | [Quick Note Integration] |
| 15 | [SharePlay] |
| 16 | [System Appearance] |
| 17 | [Best Practices Summary] |
| 18 | |
| 19 | |
| 20 | |
| 21 | ## Siri Integration |
| 22 | |
| 23 | ### SiriKit Domains |
| 24 | |
| 25 | Your app can integrate with Siri through predefined domains: |
| 26 | |
| 27 | | Domain | Example Intents | |
| 28 | |--------|-----------------| |
| 29 | | Messaging | Send message, search messages | |
| 30 | | Lists & Notes | Create note, add to list | |
| 31 | | Payments | Send payment, request payment | |
| 32 | | Workouts | Start workout, end workout | |
| 33 | | Media | Play media, add to library | |
| 34 | | Ride booking | Request ride, get ride status | |
| 35 | | Car commands | Lock car, get car status | |
| 36 | | Visual codes | Look up barcode, QR code | |
| 37 | |
| 38 | ### Designing for Voice |
| 39 | |
| 40 | **Confirmation dialogs:** |
| 41 | |
| 42 | Siri: "Send $50 to Sarah for dinner?" |
| 43 | User: "Yes" / "Change amount" / "Cancel" |
| 44 | |
| 45 | |
| 46 | **Guidelines:** |
| 47 | Confirm significant actions |
| 48 | Allow easy correction |
| 49 | Provide visual feedback alongside voice |
| 50 | Handle ambiguity gracefully |
| 51 | |
| 52 | ### Custom Intents |
| 53 | |
| 54 | For actions not in predefined domains: |
| 55 | |
| 56 | |
| 57 | // Define in Intents.intentdefinition |
| 58 | Intent: OrderCoffee |
| 59 | Parameters: coffeeType, size, location |
| 60 | |
| 61 | |
| 62 | **Best practices:** |
| 63 | Use descriptive parameter names |
| 64 | Provide good examples |
| 65 | Support synonyms |
| 66 | Test with various phrasings |
| 67 | |
| 68 | ### Siri Shortcuts |
| 69 | |
| 70 | Allow users to create custom voice triggers: |
| 71 | |
| 72 | |
| 73 | // Donate shortcut when user completes action |
| 74 | let activity = NSUserActivity(activityType: "com.app.order-favorite") |
| 75 | activity.title = "Order my usual coffee" |
| 76 | activity.isEligibleForSearch = true |
| 77 | activity.isEligibleForPrediction = true |
| 78 | activity.suggestedInvocationPhrase = "Order my usual" |
| 79 | |
| 80 | view.userActivity = activity |
| 81 | |
| 82 | |
| 83 | **Guidelines:** |
| 84 | Donate shortcuts for repeated actions |
| 85 | Suggest clear invocation phrases |
| 86 | Provide relevant parameters |
| 87 | Test in Shortcuts app |
| 88 | |
| 89 | |
| 90 | |
| 91 | ## Shortcuts App Integration |
| 92 | |
| 93 | ### App Shortcuts (iOS 16+) |
| 94 | |
| 95 | Pre-built shortcuts that appear automatically: |
| 96 | |
| 97 | |
| 98 | struct MyAppShortcuts: AppShortcutsProvider { |
| 99 | static var appShortcuts: [AppShortcut] { |
| 100 | AppShortcut( |
| 101 | intent: OrderCoffeeIntent(), |
| 102 | phrases: [ |
| 103 | "Order coffee with \(.applicationName)", |
| 104 | "Get my usual from \(.applicationName)" |
| 105 | ], |
| 106 | shortTitle: "Order Coffee", |
| 107 | systemImageName: "cup.and.saucer.fill" |
| 108 | ) |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | |
| 113 | ### Shortcut Actions |
| 114 | |
| 115 | Expose app functionality as Shortcuts actions: |
| 116 | |
| 117 | **Good candidates:** |
| 118 | Actions users repeat frequently |
| 119 | Actions that can run without UI |
| 120 | Data that can be passed to other apps |
| 121 | Automatable workflows |
| 122 | |
| 123 | **Design considerations:** |
| 124 | Clear action names (verb + object) |
| 125 | Meaningful parameters with defaults |
| 126 | Useful outputs for chaining |
| 127 | Error messages that explain what went wrong |
| 128 | |
| 129 | |
| 130 | |
| 131 | ## Handoff |
| 132 | |
| 133 | ### Enabling Handoff |
| 134 | |
| 135 | Allow users to continue activities across Apple devices: |
| 136 | |
| 137 | |
| 138 | let activity = NSUserActivity(activityType: "com.app.viewing-item") |
| 139 | activity.title = "Viewing Product: \(product.name)" |
| 140 | activity.userInfo = ["productID": product.id] |
| 141 | activity.isEligibleForHandoff = true |
| 142 | activity.webpageURL = URL(string: "https://myapp.com/product/\(product.id)") |
| 143 | |
| 144 | userActivity = activity |
| 145 | |
| 146 | |
| 147 | ### Handoff Guidelines |
| 148 | |
| 149 | **Do:** |
| 150 | Continue at exactly where user left off |
| 151 | Restore scroll position, form state, etc. |
| 152 | Support universal links as fallback |
| 153 | Update activity as context changes |
| 154 | |
| 155 | **Don't:** |
| 156 | Require re-authentication |
| 157 | Lose user's work |
| 158 | Show significantly different content |
| 159 | |
| 160 | ### Web Fallback |
| 161 | |
| 162 | If app isn't installed on receiving device: |
| 163 | |
| 164 | activity.webpageURL = URL(string: "https://myapp.com/activity/\(id)") |
| 165 | |
| 166 | |
| 167 | |
| 168 | |
| 169 | ## Drag and Drop |
| 170 | |
| 171 | ### Supporting Drag |
| 172 | |
| 173 | |
| 174 | .draggable(item) { |
| 175 | // Drag preview |
| 176 | ItemPreview(item: item) |
| 177 | } |
| 178 | |
| 179 | |
| 180 | ### Supporting Drop |
| 181 | |
| 182 | |
| 183 | .dropDestination(for: ItemType.self) { items, location in |
| 184 | // Handle dropped items |
| 185 | return true |
| 186 | } |
| 187 | |
| 188 | |
| 189 | ### Drag and Drop Guidelines |
| 190 | |
| 191 | **Visual feedback:** |
| 192 | Show clear drag preview |
| 193 | Indicate valid drop targets |
| 194 | Animate transitions smoothly |
| 195 | |
| 196 | **Multi-item:** |
| 197 | Support selecting multiple items |
| 198 | Stack preview for multiple items |
| 199 | Handle batch operations |
| 200 | |
| 201 | **Cross-app:** |
| 202 | Export standard data types (images, text, URLs) |
| 203 | Accept common formats |
| 204 | Maintain quality during transfer |
| 205 | |
| 206 | ### Platform Considerations |
| 207 | |
| 208 | | Platform | Drag Initiation | |
| 209 | |----------|-----------------| |
| 210 | | iPhone | Long press + drag (within app) | |
| 211 | | iPad | Long press or tap + drag | |
| 212 | | Mac (Catalyst) | Click + drag | |
| 213 | |
| 214 | |
| 215 | |
| 216 | ## Universal Links |
| 217 | |
| 218 | ### Setting Up |
| 219 | |
| 220 | Configure `apple-app-site-association` on your server: |
| 221 | |
| 222 | { |
| 223 | "applinks": { |
| 224 | "apps": [], |
| 225 | "details": [{ |
| 226 | "appID": "TEAMID.com.example.app", |
| 227 | "paths": ["/product/*", "/user/*"] |
| 228 | }] |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | |
| 233 | Add Associated Domains capability: |
| 234 | |
| 235 | applinks:example.com |
| 236 | |
| 237 | |
| 238 | ### Handling Links |
| 239 | |
| 240 | |
| 241 | func application(_ application: UIApplication, |
| 242 | continue userActivity: NSUserActivity, |
| 243 | restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { |
| 244 | guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, |
| 245 | let url = userActivity.webpageURL else { |
| 246 | return false |
| 247 | } |
| 248 | return handleUniversalLink(url) |
| 249 | } |
| 250 | |
| 251 | |
| 252 | ### Best Practices |
| 253 | |
| 254 | Parse URLs robustly (handle malformed links) |
| 255 | Navigate to appropriate screen |
| 256 | Show content immediately (don't require login first) |
| 257 | Fall back gracefully if content unavailable |
| 258 | |
| 259 | |
| 260 | |
| 261 | ## Spotlight Search |
| 262 | |
| 263 | ### Indexing Content |
| 264 | |
| 265 | |
| 266 | let attributeSet = CSSearchableItemAttributeSet(contentType: .text) |
| 267 | attributeSet.title = item.title |
| 268 | attributeSet.contentDescription = item.description |
| 269 | attributeSet.thumbnailData = item.thumbnailData |
| 270 | |
| 271 | let searchableItem = CSSearchableItem( |
| 272 | uniqueIdentifier: item.id, |
| 273 | domainIdentifier: "com.app.items", |
| 274 | attributeSet: attributeSet |
| 275 | ) |
| 276 | |
| 277 | CSSearchableIndex.default().indexSearchableItems([searchableItem]) |
| 278 | |
| 279 | |
| 280 | ### What to Index |
| 281 | |
| 282 | **Good candidates:** |
| 283 | User content (notes, documents) |
| 284 | Saved items (favorites, history) |
| 285 | Frequently accessed items |
| 286 | |
| 287 | **Avoid:** |
| 288 | Sensitive data |
| 289 | Transient content |
| 290 | Every possible item (be selective) |
| 291 | |
| 292 | ### Search Result Design |
| 293 | |
| 294 | Results appear in Spotlight: |
| 295 | |
| 296 | ┌─────────────────────────────────────────┐ |
| 297 | │ 🔲 My Note Title │ |
| 298 | │ Preview of note content... │ |
| 299 | │ MyApp │ |
| 300 | └─────────────────────────────────────────┘ |
| 301 | |
| 302 | |
| 303 | **Include:** |
| 304 | Clear title |
| 305 | Helpful description |
| 306 | Thumbnail if visual |
| 307 | Accurate metadata |
| 308 | |
| 309 | |
| 310 | |
| 311 | ## Focus & Notifications |
| 312 | |
| 313 | ### Focus Awareness |
| 314 | |
| 315 | Respect user's Focus mode: |
| 316 | |
| 317 | |
| 318 | UNUserNotificationCenter.current().getNotificationSettings { settings in |
| 319 | if settings.notificationCenterSetting == .disabled { |
| 320 | // User has notifications silenced |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | |
| 325 | ### Time Sensitive Notifications |
| 326 | |
| 327 | For truly urgent notifications: |
| 328 | |
| 329 | |
| 330 | let content = UNMutableNotificationContent() |
| 331 | content.title = "Your ride is here" |
| 332 | content.interruptionLevel = .timeSensitive |
| 333 | |
| 334 | |
| 335 | **Use only when:** |
| 336 | Immediate action required |
| 337 | User explicitly opted in |
| 338 | Content is genuinely time-sensitive |
| 339 | |
| 340 | |
| 341 | |
| 342 | ## Quick Note Integration |
| 343 | |
| 344 | ### Adding Quick Note Capability |
| 345 | |
| 346 | Allow highlighting content for Quick Note: |
| 347 | |
| 348 | |
| 349 | Text(content) |
| 350 | .contextMenu { |
| 351 | Button("Add to Quick Note") { |
| 352 | // System handles this |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | |
| 357 | |
| 358 | |
| 359 | ## SharePlay |
| 360 | |
| 361 | ### When to Use SharePlay |
| 362 | |
| 363 | Watching content together |
| 364 | Collaborative activities |
| 365 | Shared experiences |
| 366 | |
| 367 | ### SharePlay Guidelines |
| 368 | |
| 369 | **Sync state:** |
| 370 | Keep all participants in sync |
| 371 | Handle network latency gracefully |
| 372 | Provide individual controls where appropriate |
| 373 | |
| 374 | **Visual design:** |
| 375 | Show who's in the session |
| 376 | Indicate when others interact |
| 377 | Provide easy leave option |
| 378 | |
| 379 | |
| 380 | |
| 381 | ## System Appearance |
| 382 | |
| 383 | ### Supporting Dark Mode |
| 384 | |
| 385 | |
| 386 | // Adaptive colors |
| 387 | Color.primary // Auto light/dark |
| 388 | Color.secondary // Auto light/dark |
| 389 | |
| 390 | // Custom adaptive colors |
| 391 | extension Color { |
| 392 | static let background = Color("Background") // From asset catalog |
| 393 | } |
| 394 | |
| 395 | |
| 396 | ### Supporting Dynamic Type |
| 397 | |
| 398 | |
| 399 | Text("Title") |
| 400 | .font(.title) // Scales with Dynamic Type |
| 401 | |
| 402 | // Custom scalable fonts |
| 403 | .font(.custom("MyFont", size: 17, relativeTo: .body)) |
| 404 | |
| 405 | |
| 406 | ### Supporting Accessibility |
| 407 | |
| 408 | |
| 409 | Text("Content") |
| 410 | .accessibilityLabel("Detailed description") |
| 411 | .accessibilityHint("Tap to view details") |
| 412 | |
| 413 | |
| 414 | |
| 415 | |
| 416 | ## Best Practices Summary |
| 417 | |
| 418 | | Integration | Key Consideration | |
| 419 | |-------------|-------------------| |
| 420 | | Siri | Clear confirmation, handle ambiguity | |
| 421 | | Shortcuts | Expose repeatable, automatable actions | |
| 422 | | Handoff | Preserve exact state across devices | |
| 423 | | Drag & Drop | Clear previews, multi-item support | |
| 424 | | Universal Links | Deep link to specific content | |
| 425 | | Spotlight | Index valuable, non-sensitive content | |
| 426 | | Focus | Respect user's notification preferences | |
| 427 | |
| 428 | **Universal principle:** System integrations should feel seamless—users shouldn't think about which device or app they're using. |
| 429 |
Details
- Updated
- Sep 10, 2026
- License
- MIT
- Stars on the repo
- ★ 2,235
- Checked
- Source
- wondelai/skills ↗
- Creator
- wondelai · 319 listings
Similar skills
See all →
SkillCross-Platform Reverse Engineer
SkillBrainstorm Ideas
SkillCode Review Feedback Analyzer
SkillBug Diagnosis Framework
SkillImplement Spec
SkillPR Description WriterMore from wondelai
SkillSoftware Design Philosophy
SkillActionable Metrics Guide
SkillAdvertising Media
SkillAffordance Design
SkillLean UX in Agile Teams
SkillAMP Framework Practitioner