meta
소스 코드를 정적 분석하여 추론할 수 없는 개발자의 의도를 표현하는 데 사용되는 주석입니다.
클린 아키텍처, 반응형 디자인, 상태 관리, 커넥터 패턴을 사용한 위젯 분리, 의존성 주입, 위젯, 단위, 골든 및 E2E 테스트, 네비게이션, 로컬라이제이션, Material 3 동적 테마, 지속적인 통합 및 지속적인 배포를 보여주는 플러터 템플릿 애플리케이션.
소스 코드를 정적 분석하여 추론할 수 없는 개발자의 의도를 표현하는 데 사용되는 주석입니다.
반응형 캐싱 및 데이터 바인딩 프레임워크입니다. Riverpod은 비동기 코드 작업을 쉽게 만듭니다.
v0.7.0Flutter 그리드 레이아웃(스태거드, 메이슨리, 큐일티드, 웨븐 등)의 컬렉션을 제공합니다.
Drift는 Dart 및 Flutter 애플리케이션에서 관계형 데이터를 저장하기 위한 반응형 라이브러리입니다.
drift 사용자를 위한 개발용 종속성입니다. 생성기 및 개발 도구를 포함합니다.
v4.0.0패키지는 Flutter 프로젝트에 샤이머 효과를 쉽게 추가할 수 있는 방법을 제공합니다
AutoRoute는 선언형 라우팅 솔루션으로, 네비게이션에 필요한 모든 것이 자동으로 생성됩니다.
AutoRoute는 선언형 라우팅 솔루션으로, 네비게이션에 필요한 모든 것이 자동으로 생성됩니다.
Flutter 앱을 위한 강력한 다중 플랫폼 E2E UI 테스트 프레임워크로, integration_test의 한계를 극복하고 네이티브 상호작용을 처리합니다.
팀이 파일을 빠르고 일관되게 생성하는 데 도움이 되는 Dart 템플릿 생성기입니다.
Flutter 앱의 국제화 및 현지화를 간편하고 빠르게 수행할 수 있습니다. 이 패키지는 국제화 프로세스를 단순화합니다.
null 안전성 지원과 수동 모크 또는 코드 생성 없이 모킹을 단순화하는 Dart 모크 라이브러리입니다.
^8.0.3^1.17.1^1.0.5^5.0.3^2.5.0^3.0.1{"sdk":"flutter"}^0.6.0^0.20.0^2.3.2^0.7.0^1.0.0^2.2.0^7.2.0^2.3.2^4.8.1^6.6.1^2.0.1^1.8.2^0.27.7^2.0.18^3.0.0^0.5.20^2.0.1^4.3.3^6.2.1^0.0.2^2.0.13^1.6.6^2.1.0^3.2.3^5.0.2^2.0.5^8.0.0^2.3.3^2.5.2^3.0.1{"sdk":"flutter"}^2.3.2^0.15.0^1.11.0^1.0.3^0.1.0-dev.47^3.6.1아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.
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.
We’re always looking for people who value their work, so come and join us. We are hiring!
CI
Clone the repo and follow these steps to setup the project.
The template was build using dart null safety. Dart 2.19.2 or greater and Flutter 3 or greater is required.
Follow this guide to setup your flutter environment based on your platform.
First and foremost make sure you have Flutter 3 setup on your system. You can check the version by running
flutter --version
You should see output similar to this. Check if the version is 3.x.x.
Flutter 3.7.7 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 2ad6cd72c0 (13 days ago) • 2023-03-08 09:41:59 -0800
Engine • revision 1837b5be5f
Tools • Dart 2.19.4 • DevTools 2.20.1
If not run this command to update flutter to the latest version
flutter upgrade
This template uses derry as it's script manager.
Run this command to setup derry
dart pub global activate derry
Most of the scripts we will use are abstracted away by derry. If you want to know more about the scirpts, read the scripts documentation.
flutter pub get
derry generate all
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.
Sensitive 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 uses it's own .env file.
The tempalte uses weather api from openweathermap.org.
You can get your Open Weather API key from here.
Once 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.
OPEN_WEATHER_API_KEY=YOUR_API_KEY
OPEN_WEATHER_BASE_URL=https://api.openweathermap.org/
With the setup done, we can get the app running.
The template comes with built-in support for 3 flavors. Each flavor has it's own .env file.
You can setup any environment specific values in the respective .env files.
To launch the app run the following command and specify the flavor name.
derry launch dev
On android studio, you will find pre defined run configurations.
Select a flavor from the dropdown Screenshot 2023-03-21 at 11 24 35 AM
Select a device to launch on Screenshot 2023-03-21 at 11 24 25 AM
Click Run to launch the app
The 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.
The architecture is separated into the following layers
lib/presentation: All UI and state management elements like widgets, pages and view models.lib/navigation: navigators to navigate between destinations.lib/interactor: provides feature specific functionality.lib/domain: use cases for individual pieces of work.lib/repository: repositories to manage various data sources.lib/services: services provide access to external elements such as databases, apis, etc.Each layer has a di directory to manage Dependency Injection for that layer.
The layers presentation, domain and services each have an entity directory.
lib/presentation/entity: Classes that model the visual elements used by the widgets.lib/domain/entity: Model classes for performing business logic manipulations. They act as an abstraction to hide the local and remote data models.lib/services/entity: Contains local models (data classes for the database) and remote models (data classes for the api).UI (eg: UICity).Local (eg: LocalCity).Remote (eg: RemoteCity).Apart from the main layers, the template has
lib/foundation: Extensions on primitive data types, loggers, global type alias etc.lib/flavors: Flavor i.e. Environment related classes.lib/app.dart: App initialization code.The presentation layer houses all the visual components and state management logic.
The 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.
State Management is done using the riverpod along with state_notifier. The class that manages state is called the View Model.
Each View Model is a subclass of the BaseViewModel. The BaseViewModel is a StateNotifier of ScreenState. Along with the ScreenState it also exposes a stream of Effect.
Implementations of the BaseViewModel can also choose to handle Intents.
ScreenState encapsulates all the state required by a Page. State is any data that represents the current situation of a Page.
For example, the HomeScreenState holds the state required by the HomePage.
Effects 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.
Showing a snackbar or hiding the keyboard are examples of an effect.
Intent is any action that takes place on a page. It may or may not be user initiated.
SearchScreenIntent has the actions that can happen on the SearchPage.
A page is a widget that the navigator can navigate to. It should return the BasePage widget.
The BasePage creates the structure for the page, initialises the ViewModel 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.
Each page accepts the Screen object as input.
Each destination has a widgets directory. It holds all the widgets that appear on a Page excluding the page itself.
Each 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.
A Screen 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.
As you can read from the Architecture section, adding a new page in the app can require a lot of files to be created. The template uses mason as it's templating engine to automate some of this work.
To get started with mason, first activate mason globally
dart pub global activate mason_cli
Similar to using pub get we need to run mason get to setup the bricks (templates are called brick in mason).
mason get
You can learn more about mason here.
The template comes with a pre setup brick called destination.
Run the destination brick using the following command.
mason make destination -o lib/presentation/destinations/notes --name notesList
-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:
The template also includes a testing setup for
The test coverage and code quality reporting is done using sonarqube.
You can read the documentation about integrating sonarqube in you CI workflow here.
The Flutter Template contains:
Flutter application.flavors - dev, qa and prod.reactive base architecture for your application.Riverpod along with state_notifier for state management.Drift as local database for storage.Dio for making API calls.Freezed for data class functionality.Get It for dependency injection.Flutter Lints for linting.derry for script management.mason for templating.sonarqube for code inspection.The template contains an example (displaying weather data) with responsive widgets, reactive state management, offline storage and api calls.
The Flutter template comes with built-in support for CI/CD using Github Actions.
The CI workflow performs the following checks on every pull request:
flutter analyze.dart formatflutter test.sonarqube.You can read the documentation about integrating sonarqube in you CI workflow here.
The CD workflow performs the following actions:
The CI and CD workflows grab the .env files from github secrets. The secrets are name ENV_ followed by environment name.
So for dev the secret name is ENV_DEV, qa is ENV_QA and prod is ENV_PROD.
Convert your .env files with all the api keys populated to base64 strings and set them as secrets on github with the appropriate secret name.
You can learn more about github actions secrets here.
For the android CD workflow to run, we need to perform the following setup steps:
store password, key alias and key password. You will need these in later steps.openssl to convert the jks file to Base64.openssl base64 < flutter_template_keystore.jks | tr -d '\n' | tee flutter_template_keystore_encoded.txt
base64 output on Github Secrets with the key name KEYSTORE.store password in github secrets with the key name RELEASE_STORE_PASSWORD.key alias in github secrets with the key name RELEASE_KEY_ALIAS.key password in github secrets with the key name RELEASE_KEY_PASSWORD.APP_CENTER_TOKEN.For the IOS job in the cd.yml to run, you first need to have a valid Apple Developer Account.If you don't have it yet, please create one before proceeding further
We will divide the guide into steps so that it is easier to understand
Bundle ID. You can view the official Flutter guide hereCAUTION: Apple doesn't allow underscore in the bundle identifier. Read about valid identifiers here
Distribution Certificate for your machine locally once. You can refer to this guide. Download the .p12 file for use later. Remember the password used to create this certificate as we will need this laterProvisioning Profile for your Bundle ID you registered above. You can refer to this guide. Download the profile for use later.BUNDLE ID with your Bundle Identifier (You got that already from Step 1)PROVISIONING PROFILE NAME with your Provisioning Profile Name (You already created one in Step 2, use that)TEAM_ID with your team id. Look at this answer on "How to find your Team ID"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>generateAppStoreInformation</key>
<false/>
<key>manageAppVersionAndBuildNumber</key>
<true/>
<key>method</key>
<string>app-store</string>
<key>provisioningProfiles</key>
<dict>
<key>BUNDLE-ID</key>
<string>PROVISION PROFILE NAME</string>
</dict>
<key>signingCertificate</key>
<string>Apple Distribution</string>
<key>signingStyle</key>
<string>manual</string>
<key>stripSwiftSymbols</key>
<true/>
<key>teamID</key>
<string>TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>uploadSymbols</key>
<true/>
</dict>
</plist>
options.plist and save the above contents in that fileBUILD_CERTIFICATE_BASE64 : The base64 of the p12 file we generated(Step 2)P12_PASSWORD: The password of the p12 certificate generated above in Step 2BUILD_PROVISION_PROFILE_BASE64: The provisioning profile in base64(Step 2)KEYCHAIN_PASSWORD : The password used to store the keychain in the local keystore of the Github Runner(Any random value)IOS_PLIST: The options.plist file needed to make an ipa out of the xcarchive generated by flutter(Step 3)APPSTORE_PASSWORD: The password passed to altool to upload the ipa to the store(Step 4)FILENAME with your filenameopenssl base64 < FILENAME | tr -d '\n' | tee ENCODED_FILENAME.txt
Personal Access Token (PAT) to commit the version changes.PAT, exclude the account that the token belongs to from the branch protection rules.cd.yml file under each checkout action.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 hereIf you do not plan to use the CD workflow on protected branches, you can remove the token part from the checkout actions.
Flutter 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 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. Link to frame rate issue on flutter.
Golden 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. To 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, the golden tests are run on a macos host.
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 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.Flutter Template is licensed under the MIT license. Check the LICENSE file for details.