flutter_app_intents

Counter App Intents Example

This example demonstrates action-based App Intents using a simple counter application. It shows how to execute specific app functions through Siri voice commands and iOS shortcuts.

Features Demonstrated

Action Intents

Key Concepts

Architecture

This example uses the hybrid approach with:

  1. Static Swift App Intents (ios/Runner/AppDelegate.swift)
  2. Flutter handlers (lib/main.dart)
  3. Bridge communication via the plugin

Screenshots

App Interface iOS Shortcuts
Counter App Interface iOS Shortcuts
Counter app iOS Shortcuts app

Quick Start

Prerequisites

Run the Example

cd counter
flutter pub get
flutter run

Test the App Intents

  1. Manual Testing: Use the floating action button to increment the counter

  2. iOS Shortcuts: Check the Shortcuts app for available actions

  3. Enable Siri: ⚠️ IMPORTANT - In Shortcuts app, tap “Counter Example Shortcuts” and toggle ON the Siri switch (it’s OFF by default)

  4. Siri Commands:
    • “Increment counter with Counter Example”
    • “Reset counter with Counter Example”
    • “Get counter from Counter Example”
  5. Settings: Go to Settings > Siri & Search > App Shortcuts

Implementation Details

Static Swift Intents

The iOS side defines static intents in AppDelegate.swift:

struct CounterIntent: AppIntent {
    static var title: LocalizedStringResource = "Increment Counter"
    static var description = IntentDescription("Increment the counter by one")
    static var isDiscoverable = true
    
    func perform() async throws -> some IntentResult & ReturnsValue<String> {
        let plugin = FlutterAppIntentsPlugin.shared
        let result = await plugin.handleIntentInvocation(
            identifier: "increment_counter",
            parameters: [:]
        )
        
        if let success = result["success"] as? Bool, success {
            let value = result["value"] as? String ?? "Counter incremented"
            return .result(value: value)
        } else {
            let errorMessage = result["error"] as? String ?? "Failed to increment counter"
            throw AppIntentError.executionFailed(errorMessage)
        }
    }
}

Flutter Handlers

The Flutter side handles the business logic:

Future<AppIntentResult> _handleIncrementIntent(Map<String, dynamic> parameters) async {
  final amount = parameters['amount'] as int? ?? 1;
  
  setState(() => _counter += amount);
  
  // Donate intent for Siri learning
  await _client.donateIntent('increment_counter', parameters);
  
  return AppIntentResult.successful(
    value: 'Counter incremented by $amount. New value: $_counter',
  );
}

App Shortcuts Provider

The static shortcuts are declared with an AppShortcutsProvider:

struct CounterAppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: CounterIntent(),
            phrases: [
                "Increment counter with \(.applicationName)",
                "Add one with \(.applicationName)",
                "Count up using \(.applicationName)"
            ],
            shortTitle: "Increment",
            systemImageName: "plus.circle"
        )
        // ... other shortcuts
    }
}

What You’ll Learn

Next Steps

Check out the navigation example to see how App Intents can handle app navigation and deep linking.