{"id":14989815,"url":"https://github.com/gregertw/actingweb_firstapp","last_synced_at":"2025-04-04T23:09:20.799Z","repository":{"id":37431161,"uuid":"172249266","full_name":"gregertw/actingweb_firstapp","owner":"gregertw","description":"Starter app for Flutter that includes many different production app features; some not typically included in demo apps.","archived":false,"fork":false,"pushed_at":"2024-01-27T16:04:47.000Z","size":9421,"stargazers_count":498,"open_issues_count":4,"forks_count":87,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T22:13:30.751Z","etag":null,"topics":["android","auth0","crashlytics","dart","firebase","flutter","flutter-examples","google","google-maps","internationalization","ios","location","messaging","provider"],"latest_commit_sha":null,"homepage":"https://medium.com/flutter-community/why-and-how-you-should-use-a-flutter-starter-app-even-if-you-are-not-a-beginner-78bd901dea5a","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gregertw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-23T18:31:06.000Z","updated_at":"2025-03-10T11:43:24.000Z","dependencies_parsed_at":"2023-01-31T07:15:47.752Z","dependency_job_id":"e84de928-916d-47ab-85aa-86fd8bb9aee4","html_url":"https://github.com/gregertw/actingweb_firstapp","commit_stats":{"total_commits":241,"total_committers":3,"mean_commits":80.33333333333333,"dds":"0.14937759336099588","last_synced_commit":"24a86dc508cd6a0fc0154e65a40ee0f97f3a713e"},"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gregertw%2Factingweb_firstapp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gregertw%2Factingweb_firstapp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gregertw%2Factingweb_firstapp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gregertw%2Factingweb_firstapp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gregertw","download_url":"https://codeload.github.com/gregertw/actingweb_firstapp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247261612,"owners_count":20910108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","auth0","crashlytics","dart","firebase","flutter","flutter-examples","google","google-maps","internationalization","ios","location","messaging","provider"],"created_at":"2024-09-24T14:18:57.580Z","updated_at":"2025-04-04T23:09:20.793Z","avatar_url":"https://github.com/gregertw.png","language":"Dart","readme":"# first_app: Starter app for a Flutter production app\n\n**Maintainer**: Greger Wedel, \u003chttps://github.com/gregertw\u003e\n\nListed on: [![Awesome Flutter](https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true\u0026style=flat-square)](https://github.com/Solido/awesome-flutter)\n\n**Latest build and artifacts**: [![Codemagic build status](https://api.codemagic.io/apps/5e23f3b4c5faa6a356815277/5e23f3b4c5faa6a356815276/status_badge.svg)](https://codemagic.io/apps/5e23f3b4c5faa6a356815277/5e23f3b4c5faa6a356815276/latest_build)\n\n**Latest update:** Support for Flutter 3.29.2\n\nThere are lots of simple Flutter app examples out there, but very few show how to tie together the elements\nyou need to put an app into production. In my process of evaluating Flutter maturity and readiness for\nproduction apps, I started to put together the various elements into a single app. It evolved over time to\na starter app (and template on Github) that has been updated and following best practices and sound engineering\npractices.\n\nThe focus of this starter app is thus not on the UI or functionality, but rather to show how a set of typical\napp functionalities can be developed and supported in a sound code structure. The app structure has also been\ndesigned to support a development team through separation of concerns and sound abstractions, as well as support\nfor all layers of testing (unit, widget, and integration).\n\nThis app has the following elements:\n\n- Support for iOS, Android, and web\n- Separation of business logic in models and providers, and UI in a separate folder structure\n- Use of provider for app state management\n- Authentication and authorization using OAuth2\n- State management of login and login token including permanent storage for restarts\n- Simple widget framework for handling logged-in, expired, and logged-out states\n- Basic UI with sliding drawer menu and menu options\n- Testing using unit test framework and mocking\n- Integration tests\n- Localization using i18n and the built-in Flutter support for generating boilerplate\n- Use of a global UI theme\n- Custom icons for both iOS and Android\n- Use of Firebase Analytics for usage tracking\n- Use of Firebase Crashlytics for crash reporting\n- Use of Firebase Cloud Messaging for push notifications\n- Use of a OS native capability (location tracking) using a published plugin (geolocator)\n- Use of Google Maps to present a map of the current location\n- Use of an independently defined new widget type called AnchoredOverlay to overlay a map widget\n\nHere is a blog post about the value of using a starter app: \u003chttps://stuff.greger.io/2021/08/why-and-how-you-should-use-a-flutter-starter-app.html\u003e\n\nAlso, see my blog post for a more detailed introduction to the various features: \u003chttps://stuff.greger.io/2019/07/production-quality-flutter-starter-app.html\u003e.\n\n## Known issues\n\n- firebase_crashlytics does not support web\n\n## Suggested improvements\n\nI'm happy to accept pull requests for any improvements that will make this starter app even more complete from\na production app point of view. Here are some possible improvements:\n\n- How to use Oauth2 to grant access to a service like Firebase database (very close now with Google login)\n- How to do A/B testing\n- How to use deep links\n- ...\n\n## CHANGELOG\n\nSee CHANGELOG.md\n\n## QUICKSTART\n\nThe easiest way to get started with this app is to get it running in your own browser locally. To do that, you need to\nconfigure a Google OAuth2 application at \u003chttps://console.cloud.google.com/apis/credentials\u003e. You need to define\nyour own application so you can use Google to log in, and you need to make sure that the app knows about the URL it is\nrunning from (i.e. localhost:port), so that it can present the URL to Google and the Google app is configured with the\nsame URL as an allowed redirect URL. In addition, the app needs to present the secret for the Google app you have configured.\nIf there is a mismatch in the URL your app is running under, what is configured in the app, and what is configured for the\nGoogle app, the login process will fail.\n\nHere are the steps:\n\n- Go to Google console as above and create a new OAuth client ID. Choose Web Application as type.\n- Add an Authorized redirect URI to \u003chttp://localhost:50000/\u003e\n- Copy the client id and update `clientIdGoogleApp` in lib/environment.dart\n- Copy the client secret and `secretGoogleWeb`in the same file\n- Start debugging with: `flutter run --debug --web-port=50000` (this will allow the app to present the right redirect URL)\n\nIn Visual Studio Code, you can add an entry to launch.json in .vscode:\n\n```json\n{\n            \"name\": \"Flutter: Debug web\",\n            \"type\": \"dart\",\n            \"request\": \"launch\",\n            \"args\": [\n                \"--web-port=50000\"\n            ],\n            \"flutterMode\": \"debug\",\n            \"program\": \"lib/main.dart\"\n        },\n```\n\n## How to get started\n\nThe app uses a Google Firebase project (though this  is not a requirement if you drop analytics, messaging, and crashlytics).\nThe currently configured test project is available for your testing, but obviously you will not be able to log into these\nprojects, so the value of that is just that you can test the app without doing any code changes. To start tinkering, you\nwill want to create your own Firebase project.\n\nBut, first of all, check out the actingweb_firstapp code base (it's a template!). You can use any editor.\n\nMake sure you have available a device to run the app on, either a physical device or an emulator, then just\nrun it on an emulator. You should be able to log into the app with your Google account (only on emulator, not web,\nsee later). Github is not supported for web, and requires a secret that Google does not require, so it will not work\nuntil you register your own Github OAuth2 client.\n\nlib/environment.dart contains the client values for Github and Google, here you can add your own client id and secrets\nwhen you register your app for authentication with each of these.\n\nSee further below for introductions on specific areas of the app's functionality.\n\n## Steps to make this your own app\n\nEven if this app comes out of the box functionally working, you need to make it your own to build on it.\nAs a minimum, you need to do the following:\n\n- Replace io.actingweb.firstapp with your own URI scheme/bundle id in android/, ios/, and lib/\n- Replace firebase_options.dart with configurations for your own Firebase project, see\n  \u003chttps://firebase.flutter.dev/docs/overview/\u003e\n- Edit lib/environment.dart with your own Google and Github client ids (or supply them in env variables)\n- Supply environment variables for the secrets in environment.dart. In Visual Studio Code, you can edit your launch.json\n  and add the \"env\": {} section\n- You need to edit `android/app/src/main/AndroidManifest.xml` and `ios/Runner/AppDelegate.swift` to update your API\n  key for Google Maps (see \u003chttps://cloud.google.com/maps-platform/\u003e)\n\nThat's all you need! The below sections give you more details on how each of the services have been integrated in the\ncode base.\n\n## Integration pattern with various services\n\nThere are two integration needs in a Flutter app: integrate towards the underlying platform and integrating towards\nthe various external services you may want to use. Examples of the first is location, mobile messaging services (which\nhas support built into the iOS and Android platforms), persistence of data (i.e. shared_preferences), and registration\nof  URI schemes for your application, so that your application can receive the authentication code necessary as part\nof authentication.\nThe second category is how to use Google Firebase services (analytics,  messaging, and crash reports), authentication using\nOAuth2 towards e.g. Github and Google, or Google Maps to show the map of where you are.\n\nThe most difficult is typically the integration towards the underlying platforms, but as Flutter has evolved with support\nfor web and matured on iOS and Android, more and more of integration necessary can be done in the Dart code and the platform\nspecific configuration has been reduced.\n\nBut still, you will need API keys or client ids or URLs for where to connect, and this must be configured somewhere. In\n/lib/environment.dart you will find a class that pickes configuration variables from the environment (which can be set\nin your CI/CD pipeline) and where you can set defaults. However, these can only be used in the Dart code, so where there\nare needs for underlying platform integration (in ios, android, and web directories), you will have to go in and\nedit the code and configs there directly. How is documented in the sections below.\n\n## Support for Web\n\n**NOTE!!** This is only for the web version of the app\n\nTo build the web version, use `flutter build web --base-href=\"/\u003csome_path\u003e/\"` or use just `/`if you deploy to the root of\nthe domain. The web app should be deployed to `https://my.domain.com/some_path/`.\n\nAs of Flutter 2, web is supported on stable release, \u003chttps://flutter.dev/web\u003e and a web version of app is available\nat \u003chttps://gregertw.github.io/actingweb_firstapp_web\u003e. The support for packagaes has increased, and most of the\nfunctionality is now supported in the web version.\n\n See \u003chttps://flutter.dev/docs/get-started/web\u003e. If you get errors, do `flutter clean`.\n\nFirebase has now better web support as well, but there are two areas where you need to configure in the web/\nfolder: for Firebase messaging to work and for Google Maps.\n\nFor Google Maps, see \u003chttps://pub.dev/packages/google_maps_flutter_web\u003e. You need an API key and add a script to\nindex.html.\n\nYour Firebase project (google.com) must be configured with a web app (under General settings).\nThe config script snippet you get from setting up the web must replace the Firebase app config\nin web/firebase-messaging-sw.js:\n\n```js\n  var firebaseConfig = {\n    apiKey: \"AIzaSyDjVjlcUKYUBb62x4K8WUGI47mXXlfKTtI\",\n    authDomain: \"actingweb-firstapp.firebaseapp.com\",\n    databaseURL: \"https://actingweb-firstapp.firebaseio.com\",\n    projectId: \"actingweb-firstapp\",\n    storageBucket: \"actingweb-firstapp.appspot.com\",\n    messagingSenderId: \"748007732162\",\n    appId: \"1:748007732162:web:ff42373829ce3137785c5b\",\n    measurementId: \"G-M7F2YR6FNW\"\n  };\n```\n\nIf you have used the Firebase CLI tool to create a firebase_options.dart, you will find your Firebase web API key in\napiKey attribute. Add it also in lib/environment.dart (you don't need manual configuration in index.html anymore). This\nis according to the documentation as it should be used in the getToken() method.\n\nYou can find all the details at \u003chttps://firebase.flutter.dev/docs/messaging/overview\u003e, and you can find more details\non Firebase and messaging below.\n\nThe kIsWeb global variable is used to detect if the app is running on web and made available in appstate.dart\nas a isWeb bool that can be used across the app. The variable is also used in appstate.dart to do the correct\nFirebase Messaging initialisation.\n\nIf you are doing debugging of the app on web, use Google login, you need to edit environment.dart with the client id\nand secret, and then (for local debugging) edit auth.dart and oauth.js with the localhost redirect URL with port number.\nIn addition, the Google web app (credentials) also need the ```http://localhost:\u003cportnumber\u003e/``` configured as a legal redirect URL. Configure Google web app at \u003chttps://console.cloud.google.com/apis/credentials\u003e.\n\n**Note on Github!** Github only supports clientid and secret, and does explicitly not support retrieving an access token\nfrom a web applications (it is blocked with no CORS headers). This is because it is not considered safe. This means that\nGithub auth is disabled on web.\n\n## Authentication and Authorization\n\n### Evolution of auth in first_app\n\nThe authentication in first_app has been refactored three times. This last time, a package called oauth2_client has been\nused as it has support for iOS, Android, and web. Previously, flutter_appauth was used, but the maintainer chose to stick\nto the platforms where appauth.io library was supported, so it was not useful as a generic purpose auth library to demonstrate\nsupport for auth also in browsers. Oauth2_client is missing Open ID Connect, a protocol based on OAuth2 that allows you to\nuniquely identify a user logging in. With OAuth2, you need to call a non-standard user profile endpoint to retrieve profile\ninformation. This is shown through how differently Github and Google support the user profile.\n\n### About Authentication and Authorization\n\nThis app uses Github and Google as two alternative login flows. Once logged in, you can go to the drawer menu to retrieve user\ninformation, as well as refresh the token and look at the details of the token and expiry.\n\nGithub supports only a variant of client credentials flow with\na clientid and a secret, which means that Github does not allow web-based login (as the secret will then be exposed in the\ncode loaded into the browser). However, Google supports both app authorization code exchange flow (use iOS for both iOS and\n Android), as well as a (non-standard) web flow with both clientid and secret, but where both the origin of the requests and\n the redirect URLs must be registered with the credentials.\n\nTo register new iOS and web app credentials for Google, go to \u003chttps://console.cloud.google.com/apis/credentials\u003e.\n\nTo register an iOS/Android app for Github, go to \u003chttps://github.com/settings/developers\u003e.\n\nThe auth.dart provider users oauth2_client to set up support for any number of identity providers. You should easily be\nable to extend with Facebook and others. The AuthClient class can be extended to parse results after authentication and\nretrieval of user profile. For how to use oauth2_client with other identity providers, see\n\u003chttps://pub.dev/packages/oauth2_client\u003e.\n\n### Setup of auth\n\nThe oauth2_client package relies on flutter_web_auth to get a code that can be used to retrieve a token. This flow requires\nthat the mobile OS knows which application should pick up a return message, which is specified with the URI scheme aka your\napp's bundle id. For first_app, this is io.actingweb.firstapp and callback must be registered in\nandroid/app/src/main/AndroidManifest.xml. iOS does not additional config for handling the callback as long as the URI scheme\nis the same as the bundle id.\n\nTo extend with new identity providers in AuthClient class, each OAuth2 client needs redirect URIs using the custom URI\nscheme for mobile or the URI deployment location of the flutter app if on the web. Also, you need to configure scopes and\nthe user profile URL.\nAlso, each of the methods with logic based on the identity provider needs to be extended.\n\n## Setup of Firebase Analytics\n\nGo to \u003chttps://console.firebase.google.com\u003e to add a project and set up Firebase for Flutter for your own app. The procedure\nin its simplest form is to register the app identifier for iOS and Android (may be same or different, but it is recommended to\nuse the same as in this app). In the project, use Add App (+) and choose platform.\n\nAt \u003chttps://firebase.flutter.dev\u003e the CLI tool is described. This is the simplest way to generatethe firebase_options.dart file,\nor you can pull out the details for each app.\n\nFor Analytics, MaterialApp() in app.dart has this extra code to record navigation from screen to screen:\n\n```dart\n      navigatorObservers: [\n        FirebaseAnalyticsObserver(analytics: analytics),\n```\n\nHowever, if you want to customize the names of the screens in the analytics reports, you should set the screen\nname and class explicitly in each widget using:\n\n```dart\nawait analytics.setCurrentScreen(\n      screenName: 'Analytics Demo',\n      screenClassOverride: 'AnalyticsDemo',\n    );\n```\n\nNOTE!! Also, if you deploy to web, you need to update web/index.html and web/firebase-messaging-sw.js with the\nFirebase web app config (see the web section).\n\n## Setup of Firebase Cloud Messaging\n\nThis project also has set up Firebase Cloud Messaging, allowing you to send\npush notifications to the app. You need to turn on Cloud Messaging in the Firebase Console.\n\nFor iOS, you also need to generate a key and upload that to Firebase, see \u003chttps://firebase.flutter.dev/docs/messaging/overview/\u003e.\n\n**Note!!** This app can receive notifications while in the background or terminated through the onMessage() and\nonBackgroundMessage() events (in appstate.date). You should only use so-called \"notification\" messages and not \"data\" messages\nfor this (though you can have extra key/value pairs in the \"data\" section). For both Android and iOS, the notification will appear in the system tray and the app is launched.\n\n**Note2!!** It is also possible to make the app react directly from the background to\n notifications. However, this requires custom logic for Android and iOS and is not straightforward, so be warned. There was\n also a bug related to background handling: \u003chttps://github.com/FirebaseExtended/flutterfire/issues/1763\u003e This is now\nfixed. Also see \u003chttps://firebase.flutter.dev/docs/messaging/apple-integration\u003e for more details on Apple integration.\n\n**Note3!!** The iOS simulator does not support background notifications, a real device is needed.\n\nThe app will write the FCM token to console, but you can also go into the drawer menu and click on the menu header area\ndisplaying name and email to view all details, including the Firebase messaging token.\n\nThe notification console to send a notification (once configured) is a bit tricky to find, but has this URL:\n ```https://console.firebase.google.com/u/0/project/\u003cyour_project\u003e/notification/compose```. In the drawer menu, there is\n a menu option to show the last notification received. Only the title and body is shown.\n\nOr you can use the command line. In order to send a notification, you need to construct a payload like this (this is for\nshell and you need to replace the `\u003ctoken\u003e` with the app's token):\n\n```bash\nexport DATA='{\"notification\": {\"body\": \"this is a body\",\"title\": \"this is a title\"}, \"priority\": \"high\", \"data\": {\"click_action\": \"FLUTTER_NOTIFICATION_CLICK\", \"id\": \"1\", \"status\": \"done\"}, \"to\": \"\u003ctoken\u003e\"}'\n```\n\nThe \"notification\" part will be delivered either to system tray (background or not running) or directly if the app is open.\nThe click_action is required for Android only and for background notifications to work (i.e. it will not have an impact when\nthe Android app is in the foreground). For iOS, the extra click_action will be included, but does no harm.\n\nThe \"id\" and \"status\" elements in \"data\" are just example data payload that can be used by the app. Here you can send a URL\nor any other data.\n\n**Note** On iOS, these keys will appear on the root level of the message json and not within the \"data\" element.\n\nTo send the above payload, you can use curl:\n\n```bash\ncurl https://fcm.googleapis.com/fcm/send -H \"Content-Type:application/json\" -X POST -d \"$DATA\" -H \"Authorization: key=\u003ckey\u003e\"\n```\n\nHere `\u003ckey\u003e` must be replaced with the Firebase Cloud Messaging API server key (found in the Settings of the Firebase app\nunder Cloud Messaging).\n\n**So, in sum: Use \"notification\" to send a title and a message and the \"data\" element to send extra data. Except that all the \"data\" elements will appear on the root level of the message json in iOS, the behaviour will be similar for both Android and iOS.**\n\n**Note, advanced!!** Turning swizzling off (in Info.plist) like below will prevent the Firebase Messaging plugin from\nworking:\n\n```xml\n \u003ckey\u003eFirebaseAppDelegateProxyEnabled\u003c/key\u003e\n \u003cfalse/\u003e\n```\n\n## Set up Google Maps\n\nA new AnchoredOverlay widget type has been added in `lib/ui/widgets/anchored_overlay.dart` to overlay a Google\nmap with current location and to add a button to toggle the overlay.\nYou need to edit `android/app/src/main/AndroidManifest.xml`, `ios/Runner/AppDelegate.swift`, and `web/ìndex.html` to update\nyour API key for Google Maps (see \u003chttps://cloud.google.com/maps-platform/\u003e).\n\n**IMPORTANT!!!! The keys being used are under a very low daily quota and has been added to git to make sure this app\nruns out of the box. PLEASE change this as soon as possible and before you do your own development!**\n\nA new map UI page has been added to lib/ui/pages, and the OverlayMapPage() widget is loaded in\nlib/ui/pages/index.dart:\n\n```dart\nchildren: \u003cWidget\u003e[\n            LocationStreamWidget(),\n            OverlayMapPage(),\n          ],\n```\n\nYou can remove the overlay simply by removing the widget reference here. The OverlayMapPage widget relies on\nthe locstate to pick up the location.\n\n## Tests\n\nTesting is important in all production applications. This application includes unit testing (in the test/ folder),\nwidget testing (same folder) with mocks using mockito, and integration testing (with flutter_driver).\n\nTo run the unit and widget tests, run `flutter test`.\n\n### Integration Tests - As of Flutter 2\n\nAs part of Flutter 2 releases, the integration testing support moved into the SDK. The approach to testing also\nchanged. Previously, there were two separate processes (see below) where you had to communicate between the process\nrunning the tests outside and the actual app running on a device (emulated or physical). There is now more fully\nintegrated support. See \u003chttps://flutter.dev/docs/testing/integration-tests\u003e for more details.\n\nTo run the integration tests, start the emulator or connect a device and run:\n`flutter drive --driver test_driver/driver.dart --target integration_test/app_test.dart`\n\nCurrently, there is limited support for splitting up integration tests into separate files, so all tests should be\nin the same file. However, you can use several testWidgets() calls. For demonstration purposes and due to the need\nto log in, the current integration tests are all within the same testWidgets().\n\n**This used to work, but support was removed when integration testing was changed. Not yet verified to work!**\nYou can also install chromedriver and run the tests in the browser. Make sure chromedriver is in your path and run:\n`chromedriver --port=4444 \u0026; flutter drive --driver test_driver/driver.dart --target integration_test/app_test.dart -d web-server`\n\n### Mocking in Integration Tests\n\nTo simplify and make mocking dynamic, I have introduced mocks into the application state by adding a mocks object\nto the state (see `model/appstate.dart`). The mocks object is a map of objects that can be used throughout the application\n(i.e. dependency injection through app state). See in `integration_test/app_test.dart`\nfor an example where geolocation mock is enabled through setting mock: true. Note that care should be taken to avoid that\nmocks can be triggered in the a production app as authentication can be bypassed this way.\n\n## Some thoughts on state management\n\nIn investigating the various state management approaches, Brian Egan's \u003chttp://fluttersamples.com/\u003e was very\nhelpful. I tried out a few approaches and in an early version of first_app ended up on scoped_model as an approach\nthat is intuitive, plays well with the Flutter principles of app design, and that is powerful enough to support a production app.\nState management is a matter of taste, but I was trying to find the set of app architectural approaches that\nfit with Flutter and that can support a bigger team of developers.\n\nThis choice turned out to be a pretty good one as the developer behind scoped_model also worked on the provider package\nwhich in 2019 became the recommended way to provide widget trees with state updates. Provider is not entirely a\nreplacement of scoped_model, quoted from the provider home: \"A mixture between dependency injection (DI) and\nstate management, built with widgets for widgets.\"\nIn the process of replacing scoped_model with provider, I chose not to add a more powerful state management\npackage (like MobX), but rather use simple classes with the ChangeNotifier mixin. This is all that is needed for\nprovider to pick up notifyListeners() calls. In a bigger application, you probably want to choose a state management\npackaged like MobX to better handle more complex states.\n\nThe developer of provider has later developed \u003chttps://pub.dev/packages/flutter_riverpod\u003e, which is a total rewrite\nof state management (not using InheritedWidget). It is positioned as a \"better\" provider, however, I have chosen\nnot to rewrite the starter app with riverpod as provider is powerful enough for many real-life scenarios and the\ncurrent introduction to riverpod is harder to understand until you are deeper into Flutter. Also, there have been\nintroduced more state management packages and frameworks and choosing one that fits your project must be\nevaluated on a case by case basis.\n","funding_links":[],"categories":["模板","Templates [🔝](#readme)","Templates"],"sub_categories":["赚钱","推广和盈利","Monetization"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgregertw%2Factingweb_firstapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgregertw%2Factingweb_firstapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgregertw%2Factingweb_firstapp/lists"}