title: Missing plugin Amplifydatastore in Flutter using web
body: <p><a href="https://docs.amplify.aws/start/getting-started/integrate/q/integration/flutter/#querying-for-todos-and-observing-updates-in-real-time" rel="nofollow noreferrer">https://docs.amplify.aws/start/getting-started/integrate/q/integration/flutter/#querying-for-todos-and-observing-updates-in-real-time</a></p>
  <p>So I am following this tutorial up to <strong>Updating a Todo</strong> to use Flutter with AWS. Where I get the following. I am also getting a platform error with Windows.</p>
  <pre><code>Uncaught (in promise) Error: Unsupported operation: This platform is not supported yet
      at Object.throw_ [as throw] (errors.dart:251:49)
      at AmplifyClass.new (amplify_impl.dart:40:7)
      at get instance (amplify_impl.dart:133:34)
      at desc.get [as instance] (operations.dart:839:8)
      at get Amplify [as Amplify] (amplify_flutter.dart:26:42)
      at main._TodosPageState.new._initializeApp (main.dart:78:10)
      at _initializeApp.next (&lt;anonymous&gt;)
      at async_patch.dart:45:50
      at _RootZone.runUnary (zone.dart:1685:54)
      at _FutureListener.thenAwait.handleValue (future_impl.dart:147:18)
      at handleValueCallback (future_impl.dart:766:44)
      at _Future._propagateToListeners (future_impl.dart:795:13)
      at [_completeWithValue] (future_impl.dart:566:5)
      at async._AsyncCallbackEntry.new.callback (future_impl.dart:639:7)
      at Object._microtaskLoop (schedule_microtask.dart:40:11)
      at _startMicrotaskLoop (schedule_microtask.dart:49:5)
      at async_patch.dart:166:15
  </code></pre>
  <p>I'm assuming it's something to do with <strong>_dataStorePlugin</strong></p>
  <p>Traceback:</p>
  <pre><code>PS C:\users\arund\desktop\aws-projects\amplified_todo&gt; flutter run
  Multiple devices found:
  Chrome (web) • chrome • web-javascript • Google Chrome 102.0.5005.115
  Edge (web)   • edge   • web-javascript • Microsoft Edge 103.0.1264.37
  [1]: Chrome (chrome)
  [2]: Edge (edge)
  Please choose one (To quit, press &quot;q/Q&quot;): 1
  Launching lib\main.dart on Chrome in debug mode...
  Waiting for connection from debug service on Chrome...             51.6s
  This app is linked to the debug service: ws://127.0.0.1:49346/mk_K-qpY2-s=/ws
  Debug service listening on ws://127.0.0.1:49346/mk_K-qpY2-s=/ws
  
   Running with sound null safety 
  
    To hot restart changes while running, press &quot;r&quot; or &quot;R&quot;.
  For a more detailed help message, press &quot;h&quot;. To quit, press &quot;q&quot;.
  
  An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:49346/mk_K-qpY2-s=
  Flutter Web Bootstrap: Auto
  ══╡ EXCEPTION CAUGHT BY SERVICES LIBRARY ╞══════════════════════════════════════════════════════════
  The following MissingPluginException was thrown while activating platform stream on channel
  com.amazonaws.amplify/datastore_hub_events:
  MissingPluginException(No implementation found for method listen on channel
  com.amazonaws.amplify/datastore_hub_events)
  
  When the exception was thrown, this was the stack:
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
  251:49  throw_
  packages/flutter/src/services/platform_channel.dart 165:7
  _invokeMethod
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 45:50
  &lt;fn&gt;
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/zone.dart 1685:54
  runUnary
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 147:18
  handleValue
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 766:44
  handleValueCallback
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 795:13
  _propagateToListeners
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 566:5
  [_completeWithValue]
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/future_impl.dart 639:7
  callback
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 40:11
  _microtaskLoop
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 49:5
  _startMicrotaskLoop
  C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15
  &lt;fn&gt;
  ════════════════════════════════════════════════════════════════════════════════════════════════════
  Amplify plugin was not added
  An error occurred while configuring Amplify: AmplifyException(message: Amplify plugin AmplifyDataStore was not added
  successfully., recoverySuggestion: We currently don't have a recovery suggestion for this exception.,
  underlyingException: MissingPluginException(No implementation found for method configureDataStore on channel
  com.amazonaws.amplify/datastore))
  Error: AmplifyException(message: DataStore plugin has not been added to Amplify, recoverySuggestion: Add DataStore
  plugin to Amplify and call configure before calling DataStore related APIs, underlyingException: null)
      at Object.throw_ [as throw] (http://localhost:49308/dart_sdk.js:5080:11)
      at DataStoreCategory.observeQuery
      (http://localhost:49308/packages/amplify_flutter/src/categories/amplify_categories.dart.lib.js:612:236)
      at main._TodosPageState.new._initializeApp (http://localhost:49308/packages/amplified_todo/main.dart.lib.js:983:65)
      at http://localhost:49308/dart_sdk.js:40641:33
      at _RootZone.runUnary (http://localhost:49308/dart_sdk.js:40511:59)
      at handleValueCallback (http://localhost:49308/dart_sdk.js:35999:49)
      at _Future._propagateToListeners (http://localhost:49308/dart_sdk.js:36037:17)
      at [_completeError] (http://localhost:49308/dart_sdk.js:35878:23)
      at handleError (http://localhost:49308/dart_sdk.js:35058:38)
      at _RootZone.runBinary (http://localhost:49308/dart_sdk.js:40515:59)
      at _FutureListener.then.handleError (http://localhost:49308/dart_sdk.js:35449:33)
      at handleError (http://localhost:49308/dart_sdk.js:36015:51)
      at _Future._propagateToListeners (http://localhost:49308/dart_sdk.js:36041:17)
      at [_completeWithValue] (http://localhost:49308/dart_sdk.js:35872:23)
      at async._AsyncCallbackEntry.new.callback (http://localhost:49308/dart_sdk.js:35906:35)
      at Object._microtaskLoop (http://localhost:49308/dart_sdk.js:40778:13)
      at _startMicrotaskLoop (http://localhost:49308/dart_sdk.js:40784:13)
      at http://localhost:49308/dart_sdk.js:36261:9
  The Flutter DevTools debugger and profiler on Chrome is available at:
  http://127.0.0.1:9102?uri=http://127.0.0.1:49346/mk_K-qpY2-s=
  An error occurred while saving Todo: AmplifyException(message: DataStore plugin has not been added to Amplify,
  recoverySuggestion: Add DataStore plugin to Amplify and call configure before calling DataStore related APIs,
  underlyingException: null)
  </code></pre>
  <p>My code is the same as the tutorial.</p>
  <p>main</p>
  <pre><code>// dart async library we will refer to when setting up real time updates
  import 'dart:async';
  
  // flutter and ui libraries
  import 'package:flutter/material.dart';
  
  // amplify packages we will need to use
  import 'package:amplify_flutter/amplify_flutter.dart';
  import 'package:amplify_datastore/amplify_datastore.dart';
  
  // amplify configuration and models that should have been generated for you
  import 'amplifyconfiguration.dart';
  import 'models/ModelProvider.dart';
  import 'models/Todo.dart';
  
  void main() {
    runApp(const MyApp());
  }
  
  class MyApp extends StatelessWidget {
    const MyApp({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return const MaterialApp(
        title: 'Amplified Todo',
        home: TodosPage(),
      );
    }
  }
  
  class TodosPage extends StatefulWidget {
    const TodosPage({Key? key}) : super(key: key);
  
    @override
    State&lt;TodosPage&gt; createState() =&gt; _TodosPageState();
  }
  
  class _TodosPageState extends State&lt;TodosPage&gt; {
    // subscription of Todo QuerySnapshots - to be initialized at runtime
    late StreamSubscription&lt;QuerySnapshot&lt;Todo&gt;&gt; _subscription;
    // loading ui state - initially set to a loading state
    bool _isLoading = true;
  
    // list of Todos - initially empty
    List&lt;Todo&gt; _todos = [];
  
    // amplify plugins
    final _dataStorePlugin = AmplifyDataStore(modelProvider: ModelProvider.instance);
    @override
    void initState() {
      // to be filled in a later step
      // kick off app initialization
      _initializeApp();
  
      super.initState();
    }
  
    @override
    void dispose() {
      // to be filled in a later step
      super.dispose();
    }
  
    Future&lt;void&gt; _initializeApp() async {
      // to be filled in a later step
      // configure Amplify
      await _configureAmplify();
  
      // Query and Observe updates to Todo models. DataStore.observeQuery() will
      // emit an initial QuerySnapshot with a list of Todo models in the local store,
      // and will emit subsequent snapshots as updates are made
      //
      // each time a snapshot is received, the following will happen:
      // _isLoading is set to false if it is not already false
      // _todos is set to the value in the latest snapshot
      _subscription = Amplify.DataStore.observeQuery(Todo.classType)
          .listen((QuerySnapshot&lt;Todo&gt; snapshot) {
        setState(() {
          if (_isLoading) _isLoading = false;
          _todos = snapshot.items;
        });
      });
   
    }
  
    Future&lt;void&gt; _configureAmplify() async {
      // to be filled in a later step
      try {
  
        // add Amplify plugins
        await Amplify.addPlugins([_dataStorePlugin]);
  
        // configure Amplify
        //
        // note that Amplify cannot be configured more than once!
        await Amplify.configure(amplifyconfig);
      } catch (e) {
  
        // error handling can be improved for sure!
        // but this will be sufficient for the purposes of this tutorial
        print('An error occurred while configuring Amplify: $e');
      }
    
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('My Todo List'),
        ),
        //body: const Center(child: CircularProgressIndicator()),
        body: _isLoading
             ? Center(child: CircularProgressIndicator())
             : TodosList(todos: _todos),
        floatingActionButton: FloatingActionButton.extended(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) =&gt; const AddTodoForm()),
            );
          },
          tooltip: 'Add Todo',
          label: Row(
            children: const [Icon(Icons.add), Text('Add todo')],
          ),
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      );
    }
  }
  
  class TodosList extends StatelessWidget {
    const TodosList({
      required this.todos,
      Key? key,
    }) : super(key: key);
  
    final List&lt;Todo&gt; todos;
  
    @override
    Widget build(BuildContext context) {
      return todos.isNotEmpty
          ? ListView(
              padding: const EdgeInsets.all(8),
              children: todos.map((todo) =&gt; TodoItem(todo: todo)).toList())
          : const Center(
              child: Text('Tap button below to add a todo!'),
            );
    }
  }
  
  class TodoItem extends StatelessWidget {
    const TodoItem({
      required this.todo,
      Key? key,
    }) : super(key: key);
  
    final double iconSize = 24.0;
    final Todo todo;
  
    void _deleteTodo(BuildContext context) async {
      // to be filled in a later step
    }
  
    Future&lt;void&gt; _toggleIsComplete() async {
      // to be filled in a later step
    }
  
    @override
    Widget build(BuildContext context) {
      return Card(
        child: InkWell(
          onTap: () {
            _toggleIsComplete();
          },
          onLongPress: () {
            _deleteTodo(context);
          },
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(children: [
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      todo.name,
                      style: const TextStyle(
                          fontSize: 20, fontWeight: FontWeight.bold),
                    ),
                    Text(todo.description ?? 'No description'),
                  ],
                ),
              ),
              Icon(
                  todo.isComplete
                      ? Icons.check_box
                      : Icons.check_box_outline_blank,
                  size: iconSize),
            ]),
          ),
        ),
      );
    }
  }
  
  class AddTodoForm extends StatefulWidget {
    const AddTodoForm({Key? key}) : super(key: key);
  
    @override
    State&lt;AddTodoForm&gt; createState() =&gt; _AddTodoFormState();
  }
  
  class _AddTodoFormState extends State&lt;AddTodoForm&gt; {
    final _nameController = TextEditingController();
    final _descriptionController = TextEditingController();
  
    Future&lt;void&gt; _saveTodo() async {
      // to be filled in a later step
      // get the current text field contents
      final name = _nameController.text;
      final description = _descriptionController.text;
  
      // create a new Todo from the form values
      // `isComplete` is also required, but should start false in a new Todo
      final newTodo = Todo(
          name: name,
          description: description.isNotEmpty ? description : null,
          isComplete: false,
      );
  
      try {
        // to write data to DataStore, we simply pass an instance of a model to
        // Amplify.DataStore.save()
        await Amplify.DataStore.save(newTodo);
  
        // after creating a new Todo, close the form
        Navigator.of(context).pop();
      } catch (e) {
        print('An error occurred while saving Todo: $e');
      }
    }
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Add Todo'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                TextFormField(
                  controller: _nameController,
                  decoration:
                      const InputDecoration(filled: true, labelText: 'Name'),
                ),
                TextFormField(
                  controller: _descriptionController,
                  decoration: const InputDecoration(
                      filled: true, labelText: 'Description'),
                ),
                ElevatedButton(
                  onPressed: _saveTodo,
                  child: const Text('Save'),
                )
              ],
            ),
          ),
        ),
      );
    }
  }
  </code></pre>