{"id":25615208,"url":"https://github.com/wednesday-solutions/flutter_template","last_synced_at":"2025-04-05T20:08:17.963Z","repository":{"id":38785011,"uuid":"281422409","full_name":"wednesday-solutions/flutter_template","owner":"wednesday-solutions","description":"A Flutter template application showcasing - Clean architecture, Responsive design, State management, Decoupled widgets using the connector pattern, Dependency Injection, Widget, Unit, Golden and E2E testing, Navigation, Localization, Material 3 dynamic theming, Continuous Integration and Continuous Deployment.","archived":false,"fork":false,"pushed_at":"2024-06-28T12:27:50.000Z","size":2119,"stargazers_count":366,"open_issues_count":2,"forks_count":67,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-29T19:06:06.990Z","etag":null,"topics":["autoroute","clean-architecture","dart","dio","e2e-tests","flutter","flutter-boilerplate","flutter-starter","flutter-template","getit","github-actions","golden-tests","material-design","material-you","responsive-design","riverpod","template","testing"],"latest_commit_sha":null,"homepage":"https://wednesday.is/building-products/?utm_source=github\u0026utm_medium=flutter_template","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wednesday-solutions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2020-07-21T14:36:46.000Z","updated_at":"2025-03-26T19:43:59.000Z","dependencies_parsed_at":"2024-04-12T12:26:48.619Z","dependency_job_id":"923f8e20-dd72-448b-9acd-41809d0628eb","html_url":"https://github.com/wednesday-solutions/flutter_template","commit_stats":null,"previous_names":[],"tags_count":22,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fflutter_template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fflutter_template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fflutter_template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wednesday-solutions%2Fflutter_template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wednesday-solutions","download_url":"https://codeload.github.com/wednesday-solutions/flutter_template/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393570,"owners_count":20931813,"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":["autoroute","clean-architecture","dart","dio","e2e-tests","flutter","flutter-boilerplate","flutter-starter","flutter-template","getit","github-actions","golden-tests","material-design","material-you","responsive-design","riverpod","template","testing"],"created_at":"2025-02-22T03:18:54.612Z","updated_at":"2025-04-05T20:08:17.938Z","avatar_url":"https://github.com/wednesday-solutions.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n\u003cimg align=\"left\" src=\"flutter_template_github.svg\" width=\"480\" height=\"440\" /\u003e\n\n\u003cdiv\u003e\n  \u003ca href=\"https://www.wednesday.is/?utm_source=github\u0026utm_medium=flutter_template\" align=\"left\"\u003e\u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f5879492fafecdb3e5b0e75_wednesday_logo.svg\"\u003e\u003c/a\u003e\n  \u003cp\u003e\n    \u003ch1 align=\"left\"\u003eFlutter Template\u003c/h1\u003e\n  \u003c/p\u003e\n  \u003cp\u003e\n  A Flutter template application showcasing - Clean architecture, Responsive design, State management, Decoupled widgets using the connector pattern, Dependency Injection, Widget and Unit testing, Navigation, Localization, Material 3 dynamic theming, Continuous Integration and Continuous Deployment.\n  \u003c/p\u003e\n\n  ___\n\n\n  \u003cp\u003e\n    \u003ch4\u003e\n      Expert teams of digital product strategists, developers, and designers.\n    \u003c/h4\u003e\n  \u003c/p\u003e\n\n  \u003cdiv\u003e\n    \u003ca href=\"https://www.wednesday.is/contact-us/?utm_source=github\u0026utm_medium=flutter_template\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f6ae88b9005f9ed382fb2a5_button_get_in_touch.svg\" width=\"121\" height=\"34\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/wednesday-solutions/\" target=\"_blank\"\u003e\n      \u003cimg src=\"https://uploads-ssl.webflow.com/5ee36ce1473112550f1e1739/5f6ae88bb1958c3253756c39_button_follow_on_github.svg\" width=\"168\" height=\"34\"\u003e\n    \u003c/a\u003e\n  \u003c/div\u003e\n\n  ___\n\n\u003cspan\u003eWe’re always looking for people who value their work, so come and join us. \u003ca href=\"https://www.wednesday.is/hiring/?utm_source=github\u0026utm_medium=flutter_template\"\u003eWe are hiring!\u003c/a\u003e\u003c/span\u003e\n\u003c/div\u003e\n\n![CI](https://github.com/wednesday-solutions/flutter_template/actions/workflows/ci.yml/badge.svg)\n \n## Getting Started\nClone the repo and follow these steps to setup the project.\n\n#### Environment\nThe template was build using dart null safety. Dart 2.19.2 or greater and Flutter 3 or greater is required. \n\n[Follow this guide to setup your flutter environment](https://docs.flutter.dev/get-started/install) based on your platform.\n\n#### Flutter\nFirst and foremost make sure you have Flutter 3 setup on your system. \nYou can check the version by running\n```bash\nflutter --version\n```\nYou should see output similar to this. Check if the version is `3.x.x`.\n```bash\nFlutter 3.7.7 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 2ad6cd72c0 (13 days ago) • 2023-03-08 09:41:59 -0800\nEngine • revision 1837b5be5f\nTools • Dart 2.19.4 • DevTools 2.20.1\n```\nIf not run this command to update flutter to the latest version\n```bash\nflutter upgrade\n```\n\n#### Derry\nThis template uses [`derry`](https://pub.dev/packages/derry) as it's script manager.\nRun this command to setup derry\n```bash\ndart pub global activate derry\n```\nMost of the scripts we will use are abstracted away by derry. If you want to know more about the scirpts, read the [scripts documentation](scripts/README.md).\n#### Get Dependencies\n```shell\nflutter pub get\n```\n#### Run Code Generation\n```shell\nderry generate all\n```\n\n#### API Key\n\n\u003e #####  You can skip this step if you just want to get the template running. If you skip this step, the weather search will not give you any results.\n\nSensitive information like api keys, credentials, etc should not be checked into git repos, especially public ones. To keep such data safe the template uses `.env` files. Each [Flavor](#flavors) uses it's own `.env` file.\n\nThe tempalte uses weather api from `openweathermap.org`. \nYou can get your Open Weather API key from [here](https://openweathermap.org/appid#start).\n\nOnce you have the key, update the `.env` files with your api key. Replace `YOUR_API_KEY` with the key that you got from open weather api.\n```\nOPEN_WEATHER_API_KEY=YOUR_API_KEY  \nOPEN_WEATHER_BASE_URL=https://api.openweathermap.org/\n```\n\n## Running the app\nWith the setup done, we can get the app running.\n\n#### Flavors\nThe template comes with built-in support for 3 flavors. Each flavor has it's own `.env` file.\n- dev - [`.env.dev`](.env.dev)\n- qa - [`.env.qa`](.env.qa)\n- prod - [`.env`](.env)\n\nYou can setup any environment specific values in the respective `.env` files.\n\n#### Launch \nTo launch the app run the following command and specify the flavor name.\n```shell\n derry launch dev\n```\n#### Android Studio\nOn android studio, you will find pre defined run configurations.\n- Select a flavor from the dropdown\n\u003cimg width=\"596\" alt=\"Screenshot 2023-03-21 at 11 24 35 AM\" src=\"https://user-images.githubusercontent.com/58199625/226533162-0f12665f-ee39-4b85-b35c-06f7b8d55d88.png\"\u003e\n\n- Select a device to launch on\n\u003cimg width=\"413\" alt=\"Screenshot 2023-03-21 at 11 24 25 AM\" src=\"https://user-images.githubusercontent.com/58199625/226533186-9d61675a-7871-4a1e-a2b3-3dac3d8f16cc.png\"\u003e\n\n- Click `Run` to launch the app\n\n\u003cimg width=\"423\" alt=\"Screenshot 2023-03-21 at 11 24 45 AM\" src=\"https://user-images.githubusercontent.com/58199625/226533216-0cc430f1-08f5-4c94-95ef-70a853aa2da4.png\"\u003e\n\n## Architecture\nThe architecture of the template facilitates separation of concerns and avoids tight coupling between it's various layers. The goal is to have the ability to make changes to individual layers without affecting the entire app. This architecture is an adaptation of concepts from [`The Clean Architecture`](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).\n\n### Layers\nThe architecture is separated into the following layers\n- [`lib/presentation`](lib/presentation): All UI and state management elements like widgets, pages and view models.\n- [`lib/navigation`](lib/navigation): navigators to navigate between destinations.\n- [`lib/interactor`](lib/interactor): provides feature specific functionality.\n- [`lib/domain`](lib/domain): use cases for individual pieces of work.\n- [`lib/repository`](lib/repository): repositories to manage various data sources.\n- [`lib/services`](lib/services): services provide access to external elements such as databases, apis, etc.\n\nEach layer has a `di` directory to manage Dependency Injection for that layer.\n\n### Entities\nThe layers `presentation`, `domain` and `services` each have an `entity` directory.\n- [`lib/presentation/entity`](lib/presentation/entity): Classes that model the visual elements used by the widgets.\n- [`lib/domain/entity`](lib/domain/entity): Model classes for performing business logic manipulations. They act as an abstraction to hide the local and remote data models.\n- [`lib/services/entity`](lib/services/entity): Contains local models (data classes for the database) and remote models (data classes for the api).\n\n#### Entity Naming Convention\n- Presentation entities are prefixed with `UI` (eg: UICity).\n- Domain entities do not have any prefix. (eg: City).\n- Service entities are of 2 types:\n  - Local / Database entities are prefixed with `Local` (eg: LocalCity).\n  - Remote / API entities are prefixed with `Remote` (eg: RemoteCity).\n\n### Other Directories\nApart from the main layers, the template has\n- [`lib/foundation`](lib/foundation): Extensions on primitive data types, loggers, global type alias etc.\n- [`lib/flavors`](lib/flavors): Flavor i.e. Environment related classes.\n- [`lib/app.dart`](lib/app.dart): App initialization code.\n\n## Understanding the Presentation Layer\nThe presentation layer houses all the visual components and state management logic.\n\nThe [`base`](lib/presentation/base) directory has all the reusable and common elements used as building blocks for the UI like common widgets, app theme data, exceptions, base view models etc.\n\n### View Model\nState Management is done using the [`riverpod`](https://riverpod.dev/) along with [`state_notifier`](https://pub.dev/packages/state_notifier). The class that manages state is called the `View Model`. \n\nEach `View Model` is a subclass of the `BaseViewModel`. The [`BaseViewModel`](lib/presentation/base/view_model_provider/base_view_model.dart) is a `StateNotifier` of [`ScreenState`](#screen-state). Along with the ScreenState it also exposes a stream of [`Effect`](#effect). \n\nImplementations of the BaseViewModel can also choose to handle [`Intents`](#intent).\n\n### Screen State\n[`ScreenState`](lib/presentation/entity/screen/screen_state.dart) encapsulates all the state required by a [`Page`](#page). State is any data that represents the current situation of a Page.\n\nFor example, the [`HomeScreenState`](lib/presentation/destinations/weather/home/home_screen_state.dart) holds the state required by the [`HomePage`](lib/presentation/destinations/weather/home/home_page.dart).\n\n### Effect\n[`Effects`](lib/presentation/entity/effect/effect.dart) are events that take place on a page that are not part of the state of the screen. These usually deal with UI elements that are not part of the widget tree.\n\nShowing a snackbar or hiding the keyboard are examples of an effect.\n\n\n### Intent\nIntent is any action that takes place on a page. It may or may not be user initiated. \n\n[`SearchScreenIntent`](lib/presentation/destinations/weather/search/search_screen_intent.dart) has the actions that can happen on the [`SearchPage`](lib/presentation/destinations/weather/search/search_page.dart).\n\n### Page\nA page is a widget that the navigator can navigate to. It should return the [`BasePage`](lib/presentation/base/page/base_page.dart) widget. \n\nThe `BasePage` creates the structure for the page, initialises the [`ViewModel`](#view-model) and provides the view model in the widget tree so that all the children have access to it. It also listens to the effects from the view model and notifies the page about it.\n\nEach page accepts the [`Screen`](#screen) object as input.\n\n### Widgets\nEach destination has a `widgets` directory. It holds all the widgets that appear on a [`Page`](#page) excluding the page itself. \n\nEach widget the requires access to data from the view model it split into two dart files. The `connector widget` communicates with the view model, and the `content widget` has the actual UI. The connector widget passes all the required data to the content widget. Thus the content widget never depends on the state managent solution used. This helps in easy replacement of state management solution if needed and also makes it easier to test widgets.\n\n### Screen\nA [`Screen`](lib/presentation/entity/screen/screen.dart) is a class that represents a `Page` in the context of navigation. It holds the `path` used by the navigator to navigate to a `Page` and also holds any arguments required to navigate to that `Page`.\n\n## Templating\nAs you can read from the [Architecture](#architecture) section, adding a new page in the app can require a lot of files to be created. The template uses [`mason`](https://pub.dev/packages/mason_cli) as it's templating engine to automate some of this work.\n\nTo get started with mason, first activate mason globally\n```bash\ndart pub global activate mason_cli\n```\n\nSimilar to using `pub get` we need to run `mason get` to setup the `bricks` (templates are called brick in mason).\n```bash\nmason get\n```\nYou can learn more about `mason` [here](https://docs.brickhub.dev/).\n\n#### Destination Brick\nThe template comes with a pre setup brick called `destination`.\nRun the `destination` brick using the following command.\n```bash\nmason make destination -o lib/presentation/destinations/notes --name notesList \n```\n`-o` flag sets the output directory for the `brick` and `--name` is the name used for the files and classes. This brick generates the required file structure and runs `build_runner` (via mason hooks) to trigger code generation. After running the command, this is what you should see:\n\n\u003cimg width=\"408\" alt=\"Screenshot 2023-03-21 at 2 55 45 PM\" src=\"https://user-images.githubusercontent.com/58199625/226564828-3172bc70-5324-486c-a31d-6ce7f19aa8bb.png\"\u003e\n\n## Testing\n\nThe template also includes a testing setup for\n- [`Unit Tests`](test/repository).\n- [`Widget Tests`](test/presentation/integration)\n- [`Golden Tests`](test/presentation/goldens)\n- [`Integration / E2E tests`](integration_test) using [Patrol](https://patrol.leancode.co/)\n\nThe test coverage and code quality reporting is done using [`sonarqube`](https://docs.sonarqube.org/latest/).\nYou can read the documentation about integrating `sonarqube` in you CI workflow [here](https://docs.sonarqube.org/latest/devops-platform-integration/github-integration/#analyzing-projects-with-github-actions).\n\n## Content\nThe Flutter Template contains:\n- A [`Flutter`](https://flutter.dev/) application.\n- Built-in support for 3 [`flavors`](https://docs.flutter.dev/deployment/flavors) - `dev`, `qa` and `prod`.\n- A [`reactive base architecture`](#architecture) for your application.\n- [`Riverpod`](https://riverpod.dev/) along with [`state_notifier`](https://pub.dev/packages/state_notifier) for state management.\n- [`Drift`](https://drift.simonbinder.eu/) as local database for storage.\n- [`Dio`](https://github.com/flutterchina/dio) for making API calls.\n- [`Freezed`](https://pub.dev/packages/freezed) for data class functionality.\n- [`Get It`](https://pub.dev/packages/get_it) for dependency injection.\n- [`Flutter Lints`](https://pub.dev/packages/flutter_lints) for linting.\n- [`derry`](https://pub.dev/packages/derry) for script management.\n- [`mason`](https://pub.dev/packages/mason_cli) for templating.\n- [`sonarqube`](https://docs.sonarqube.org/latest/) for code inspection.\n\nThe template contains an example (displaying weather data) with responsive widgets, reactive state management, offline storage and api calls.\n\n## Continuous Integration and Deployment\nThe Flutter template comes with built-in support for CI/CD using Github Actions.\n\n### CI\nThe [`CI`](.github/workflows/ci.yml) workflow performs the following checks on every pull request:\n- Lints the code with `flutter analyze`.\n- Check formatting with `dart format`\n- Runs tests using `flutter test`.\n- Run golden test.\n- Report code coverage and code quality using `sonarqube`.\n- Build the android app.\n- Build the ios app.\n\nYou can read the documentation about integrating `sonarqube` in you CI workflow [here](https://docs.sonarqube.org/latest/devops-platform-integration/github-integration/#analyzing-projects-with-github-actions).\n\n### CD\nThe [`CD`](.github/workflows/cd.yml) workflow performs the following actions:\n- Bump the build number by 1.\n- Build a signed release apk.\n- Upload apk to the app center.\n- Upload apk as artifact to release tag.\n- Build a signed iOS app.\n- Upload ipa to testflight.\n- Upload the ipa as an artifact to release the tag.\n- Commit the updated version to git.\n\n### .env files on CD\nThe CI and CD workflows grab the `.env` files from github secrets. The secrets are name `ENV_` followed by environment name.\nSo for dev the secret name is `ENV_DEV`, qa is `ENV_QA` and prod is `ENV_PROD`.\nConvert your `.env` files with all the api keys populated to base64 strings and set them as secrets on github with the appropriate secret name.\nYou can learn more about github actions secrets [here](https://docs.github.com/en/actions/security-guides/encrypted-secrets).\n\n### Android CD setup\nFor the android CD workflow to run, we need to perform the following setup steps:\n- Follow these instructions to [generate an upload keystore](https://developer.android.com/studio/publish/app-signing#generate-key). Note down the `store password`, `key alias` and `key password`. You will need these in later steps.\n- Use `openssl` to convert the `jks` file to `Base64`.\n```shell\nopenssl base64 \u003c flutter_template_keystore.jks | tr -d '\\n' | tee flutter_template_keystore_encoded.txt\n```\n- Store the `base64` output on [`Github Secrets`](https://docs.github.com/en/actions/security-guides/encrypted-secrets) with the key name `KEYSTORE`.\n- Save the `store password` in github secrets with the key name `RELEASE_STORE_PASSWORD`.\n- Save the `key alias` in github secrets with the key name `RELEASE_KEY_ALIAS`.\n- Save the `key password` in github secrets with the key name `RELEASE_KEY_PASSWORD`.\n- [Create a distribution on app center](https://docs.microsoft.com/en-us/appcenter/distribution/) and get the upload key. You can get it from appcenter.ms/settings.\n- Save the app center upload key on github secrets with key name `APP_CENTER_TOKEN`.\n\n\n### IOS CD Setup\nFor the IOS job in the `cd.yml` to run, you first need to have a valid [Apple Developer Account](https://developer.apple.com/).If you don't have it yet, please create one before proceeding further\n\nWe will divide the guide into steps so that it is easier to understand\n\n#### Step 1: Setup on the AppStore\n- Register your `Bundle ID`. You can view the official Flutter guide [here](https://docs.flutter.dev/deployment/ios#register-a-bundle-id)\n\u003e CAUTION: Apple doesn't allow underscore in the bundle identifier. Read about valid identifiers [here](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleidentifier)\n- Create an application on the AppStore Connect Portal. Check out the official guide [here](https://docs.flutter.dev/deployment/ios#create-an-application-record-on-app-store-connect)\n\n#### Step 2: Getting a Distribution Certificate and Provisioning Profile\n- Create a `Distribution Certificate` for your machine locally once. You can refer to [this](https://support.magplus.com/hc/en-us/articles/203808748-iOS-Creating-a-Distribution-Certificate-and-p12-File) guide. Download the `.p12` file for use later. Remember the password used to create this certificate as we will need this later\n- Create a `Provisioning Profile` for your `Bundle ID` you registered above. You can refer to [this](https://support.staffbase.com/hc/en-us/articles/115003598691-Creating-the-iOS-Provisioning-Profiles) guide. Download the profile for use later.\n\n#### Step 3: Getting the options.plist\n- In the following template\n   - Replace `BUNDLE ID` with your `Bundle Identifier` (You got that already from Step 1)\n   - Replace `PROVISIONING PROFILE NAME` with your Provisioning Profile Name (You already created one in Step 2, use that)\n   - Replace `TEAM_ID` with your team id. Look at [this](https://stackoverflow.com/a/18727947) answer on \"How to find your Team ID\"\n\u003cdetails\u003e\n\u003csummary\u003e\u003ci\u003eClick to View Template\u003c/i\u003e\u003c/summary\u003e\n\n```\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n\u003cplist version=\"1.0\"\u003e\n\u003cdict\u003e\n\t\u003ckey\u003egenerateAppStoreInformation\u003c/key\u003e\n\t\u003cfalse/\u003e\n\t\u003ckey\u003emanageAppVersionAndBuildNumber\u003c/key\u003e\n\t\u003ctrue/\u003e\n\t\u003ckey\u003emethod\u003c/key\u003e\n\t\u003cstring\u003eapp-store\u003c/string\u003e\n\t\u003ckey\u003eprovisioningProfiles\u003c/key\u003e\n\t\u003cdict\u003e\n\t\t\u003ckey\u003eBUNDLE-ID\u003c/key\u003e\n\t\t\u003cstring\u003ePROVISION PROFILE NAME\u003c/string\u003e\n\t\u003c/dict\u003e\n\t\u003ckey\u003esigningCertificate\u003c/key\u003e\n\t\u003cstring\u003eApple Distribution\u003c/string\u003e\n\t\u003ckey\u003esigningStyle\u003c/key\u003e\n\t\u003cstring\u003emanual\u003c/string\u003e\n\t\u003ckey\u003estripSwiftSymbols\u003c/key\u003e\n\t\u003ctrue/\u003e\n\t\u003ckey\u003eteamID\u003c/key\u003e\n\t\u003cstring\u003eTEAM_ID\u003c/string\u003e\n\t\u003ckey\u003euploadBitcode\u003c/key\u003e\n\t\u003cfalse/\u003e\n\t\u003ckey\u003euploadSymbols\u003c/key\u003e\n\t\u003ctrue/\u003e\n\u003c/dict\u003e\n\u003c/plist\u003e\n```\n\u003c/details\u003e\n\n- Create a new file called `options.plist` and save the above contents in that file\n\n#### Step 4: Making an app specific password\n- Read the [official guide](https://support.apple.com/en-us/HT204397) to create an app specific password and remember it(;P)\n- The pipeline uses this password to upload an ipa to testflight\n\n#### Step 5: Bringing it all together\n- Add the following keys to [Github Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)\n  - `BUILD_CERTIFICATE_BASE64` : The base64 of the p12 file we generated(Step 2)\n  - `P12_PASSWORD`: The password of the p12 certificate generated above in Step 2\n  - `BUILD_PROVISION_PROFILE_BASE64`: The provisioning profile in base64(Step 2)\n  - `KEYCHAIN_PASSWORD` : The password used to store the keychain in the local keystore of the Github Runner(Any random value)\n  - `IOS_PLIST`: The options.plist file needed to make an ipa out of the xcarchive generated by flutter(Step 3)\n  - `APPSTORE_PASSWORD`: The password passed to altool to upload the ipa to the store(Step 4)\n- To generate a base64 string, use the following command, replacing `FILENAME` with your filename\n\n```shell\nopenssl base64 \u003c FILENAME | tr -d '\\n' | tee ENCODED_FILENAME.txt\n```\n\n### Pushing to protected branches\n- If the branches that you will be running CD on are protected, you will need to use a [`Personal Access Token (PAT)`](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to commit the version changes.\n- After creating the `PAT`, exclude the account that the token belongs to from the [`branch protection rules`](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule#creating-a-branch-protection-rule).\n- Save the token in github secrets and update the key name in the `cd.yml` file under each `checkout` action.\n- Since our `CD` workflow is triggered on a push, and we create a new commit in the workflow itself, the commit message created by the `CD` workflow includes `[skip ci]` tag so that the workflow does not end up in an infinite loop. Read more about this [here](https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs)\n\n**If you do not plan to use the CD workflow on protected branches, you can remove the token part from the checkout actions.**\n\n## Gotchas\n\n#### Refresh Rate\nFlutter apps might have issues on some android devices with variable refresh rate where the app is locked at 60fps instead of running at the highest refresh rate. This might make your app look like it is running slower than other apps on the device. To fix this the template uses the [`flutter_displaymode`](https://pub.dev/packages/flutter_displaymode) package. The template sets the highest refresh rate available. If you don't want this behaviour you can remove the lines 40 to 46 in [`app.dart`](lib/app.dart#L40). [`Link to frame rate issue on flutter`](https://github.com/flutter/flutter/issues/35162).\n\n#### Golden Tests\nGolden test screenshots (goldens) are rendered using the rendering mechanisms on the os that you are running the tests on. Because of the slight differences in each os, the goldens generated on each os differ slightly from each other. Goldens generated on macos won't match exactly to the goldens generated on windows or linux and your tests will fail.\nTo work around this, make sure to generate goldens and run golden tests on a single os. This template uses macos as it's os of choice to deal with goldens. You will find that on [CI](.github/workflows/ci.yml), the golden tests are run on a macos host.\n\n- `What if your team members use different operating systems for development?` - In that case, the devs not using your os of choice should have a way to generate goldens on your os of choice. This template has a [`update_goldens`](.github/workflows/update_goldens.yml) workflow that can be manually triggered on any branch. It will generate the golden files on macos and commit the changes to the same branch.\n\n## License\nFlutter Template is licensed under the MIT license. Check the [LICENSE](LICENSE) file for details.\n\n## Other Versions\n##### Check out the [multi-package branch](https://github.com/wednesday-solutions/flutter_template/tree/multi-package) for a multi package flutter architecture.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwednesday-solutions%2Fflutter_template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwednesday-solutions%2Fflutter_template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwednesday-solutions%2Fflutter_template/lists"}