Files of Ios system integration
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 |
Discussion
Browse more free Claude skills.