Merge branch 'master' of https://github.com/flutter/samples into pr/1437

pull/1437/head
Brett Morgan 3 years ago
commit 4211056a38

@ -37,6 +37,18 @@ updates:
directory: "animations/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "code_sharing/client/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "code_sharing/server/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "code_sharing/shared/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "desktop_photo_search/fluent_ui/"
schedule:
@ -45,6 +57,10 @@ updates:
directory: "desktop_photo_search/material/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "experimental/context_menus/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "experimental/federated_plugin/federated_plugin/"
schedule:
@ -73,6 +89,14 @@ updates:
directory: "experimental/linting_tool/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "experimental/material_3_demo/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "experimental/varfont_shader_puzzle/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "experimental/web_dashboard/"
schedule:
@ -85,6 +109,10 @@ updates:
directory: "form_app/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "game_template/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "infinite_list/"
schedule:
@ -109,14 +137,6 @@ updates:
directory: "navigation_and_routing/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "null_safety/null_safe_app/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "null_safety/null_unsafe_app/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "place_tracker/"
schedule:
@ -158,22 +178,10 @@ updates:
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "web/charts/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "web/github_dataviz/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "web/particle_background/"
directory: "web/_tool/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "web/samples_index/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "web/_tool/"
schedule:
interval: "daily"

@ -26,12 +26,12 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: beta
- run: ./tool/flutter_ci_script_stable.sh
@ -41,12 +41,12 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'flutter/samples'
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: beta
- run: ./tool/android_ci_script.sh
@ -56,12 +56,12 @@ jobs:
runs-on: macos-latest
if: github.repository == 'flutter/samples'
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: beta
- run: ./tool/ios_ci_script.sh

@ -16,23 +16,23 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
submodules: true
fetch-depth: 0
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
- name: Init scripts
run: dart pub get
working-directory: web/_tool
- name: Build
run: dart _tool/build_ci.dart
run: dart run _tool/build_ci.dart
working-directory: web
- name: Deploy
uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305
uses: peaceiris/actions-gh-pages@bd8c6b06eba6b3d25d72b7a1767993c0aeee42e7
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: web/samples_index/public

@ -27,12 +27,12 @@ jobs:
flutter_version: [stable, beta, master]
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: ${{ matrix.flutter_version }}
- run: ./tool/flutter_ci_script_${{ matrix.flutter_version }}.sh
@ -40,12 +40,12 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'flutter/samples'
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: stable
- run: ./tool/android_ci_script.sh
@ -53,12 +53,12 @@ jobs:
runs-on: macos-latest
if: github.repository == 'flutter/samples'
steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
- uses: actions/setup-java@d854b6da19cdadd9a010605529e522c2393ebd38
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
- uses: actions/setup-java@1df8dbefe2a8cbc99770194893dd902763bee34b
with:
distribution: 'zulu'
java-version: '12.x'
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: stable
- run: ./tool/ios_ci_script.sh

@ -22,12 +22,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@865b4092859256271290c77adbd10a43f4779972
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86
with:
results_file: results.sarif
results_format: sarif
@ -42,7 +42,7 @@ jobs:
# Upload the results as artifacts (optional).
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
with:
name: SARIF file
path: results.sarif
@ -50,6 +50,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@904260d7d935dff982205cbdb42025ce30b7a34f
uses: github/codeql-action/upload-sarif@3ebbd71c74ef574dbc558c82f70e52732c8b44fe
with:
sarif_file: results.sarif

@ -17,19 +17,20 @@ jobs:
matrix:
flutter_version:
- stable
- beta
# TODO(johnpryan): https://github.com/flutter/samples/issues/1469
# - beta
steps:
- name: Checkout
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
with:
submodules: true
fetch-depth: 0
- uses: subosito/flutter-action@1e6ee87cb840500837bcd50a667fb28815d8e310
- uses: subosito/flutter-action@dbf1fa04f4d2e52c33185153d06cdb5443aa189d
with:
channel: ${{ matrix.flutter_version }}
- name: Init scripts
run: dart pub get
working-directory: web/_tool
- name: Verify packages
run: dart _tool/verify_packages.dart
run: dart run _tool/verify_packages.dart
working-directory: web

@ -66,15 +66,18 @@ Each app should:
* Be designed to build against the current
[stable](https://github.com/flutter/flutter/wiki/Flutter-build-release-channels)
release of the Flutter SDK.
* Include the same
[`analysis_options.yaml`](https://github.com/flutter/samples/blob/main/animations/analysis_options.yaml)
file used throughout the repo. These files include a base set of analyzer
* Include the top level
[`analysis_options.yaml`](analysis_options.yaml)
file used throughout the repo. This file include a base set of analyzer
conventions and lints.
* Have no analyzer errors or warnings.
* Be formatted with `flutter format`.
* Include at least one working test in its `test` folder.
* Be wired into the list of projects in [the CI script](tool/travis_flutter_script.sh), which
runs the analyzer, the formatter, and `flutter test`.
* Be wired into the list of projects in the CI scripts for [stable](tool/flutter_ci_script_stable.sh),
[beta](tool/flutter_ci_script_beta.sh), and [master](tool/flutter_ci_script_master.sh),
which runs the analyzer, the formatter, and `flutter test`.
* Add the new project directory to the [dependabot](.github/dependabot.yaml) configuration
to keep dependencies updated in an on-going basis.
* Avoid adding an onerous amount of blobs (typically images or other assets) to
the repo.
@ -102,7 +105,7 @@ primary maintainers, though, are:
* [@RedBrogdon](https://github.com/RedBrogdon)
* [@johnpryan](https://github.com/johnpryan)
* [@domesticmouse](https://github.com/domesticmouse)
* [@theacodes](https://github.com/theacodes)
* [@ericwindmill](https://github.com/ericwindmill)
You are free to add one of these folks (particularly @RedBrogdon) as a reviewer
to any PR sent to this repo. We're happy to comment, answer (or ask) questions,
@ -123,7 +126,7 @@ reviewer.
All files in the project must start with the following header.
```
// Copyright 2021 The Flutter team. All rights reserved.
// Copyright 2023 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
```

@ -43,3 +43,4 @@ techniques for one of your own apps, try one of these resources:
If you run into a bug in one of the samples, please file an issue in the
[`flutter/samples` issue tracker](https://github.com/flutter/samples/issues).

@ -4,11 +4,13 @@
package dev.flutter.example.androidView
import android.app.Activity
import android.content.Intent
import androidx.activity.ComponentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import io.flutter.embedding.android.ExclusiveAppComponent
import io.flutter.embedding.android.FlutterView
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.platform.PlatformPlugin
@ -40,7 +42,7 @@ import io.flutter.plugin.platform.PlatformPlugin
* what the appropriate intersection between the [FlutterView], the [FlutterEngine] and your
* `Activity` should be for your own application.
*/
class FlutterViewEngine(val engine: FlutterEngine) : LifecycleObserver{
class FlutterViewEngine(val engine: FlutterEngine) : LifecycleObserver, ExclusiveAppComponent<Activity>{
private var flutterView: FlutterView? = null
private var activity: ComponentActivity? = null
private var platformPlugin: PlatformPlugin? = null
@ -55,7 +57,7 @@ class FlutterViewEngine(val engine: FlutterEngine) : LifecycleObserver{
flutterView!!.let { flutterView ->
platformPlugin = PlatformPlugin(activity, engine.platformChannel)
engine.activityControlSurface.attachToActivity(activity, activity.lifecycle)
engine.activityControlSurface.attachToActivity(this, activity.lifecycle)
flutterView.attachToFlutterEngine(engine)
activity.lifecycle.addObserver(this)
}
@ -217,4 +219,25 @@ class FlutterViewEngine(val engine: FlutterEngine) : LifecycleObserver{
engine.activityControlSurface.onUserLeaveHint();
}
}
/**
* Called when another App Component is about to become attached to the [ ] this App Component
* is currently attached to.
*
*
* This App Component's connections to the [io.flutter.embedding.engine.FlutterEngine]
* are still valid at the moment of this call.
*/
override fun detachFromFlutterEngine() {
// Do nothing here
}
/**
* Retrieve the App Component behind this exclusive App Component.
*
* @return The app component.
*/
override fun getAppComponent(): Activity {
return activity!!;
}
}

@ -76,6 +76,10 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Module Title',
theme: ThemeData(
colorSchemeSeed: Colors.blue,
useMaterial3: true,
),
routes: {
'/': (context) => const FullScreenView(),
'/mini': (context) => const Contents(),
@ -155,13 +159,13 @@ class Contents extends StatelessWidget {
const SizedBox(height: 16),
Consumer<CounterModel>(
builder: (context, model, child) {
return ElevatedButton(
return FilledButton(
onPressed: () => model.increment(),
child: const Text('Tap me!'),
);
},
),
ElevatedButton(
FilledButton(
onPressed: () async {
// Use the url_launcher plugin to open the Flutter docs in
// a browser.
@ -174,7 +178,7 @@ class Contents extends StatelessWidget {
),
if (showExit) ...[
const SizedBox(height: 16),
ElevatedButton(
FilledButton(
onPressed: () => SystemNavigator.pop(),
child: const Text('Exit this screen'),
),

@ -13,7 +13,7 @@ dependencies:
sdk: flutter
dev_dependencies:
pigeon: ">=2.0.2 <5.0.0"
pigeon: ">=2.0.2 <8.0.0"
flutter_test:
sdk: flutter
flutter_lints: ^2.0.1

@ -1,9 +1,9 @@
include: package:flutter_lints/flutter.yaml
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
language:
strict-casts: true
strict-inference: true
linter:
rules:

@ -30,6 +30,7 @@ class MyApp extends StatelessWidget {
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);

@ -4,8 +4,8 @@
# This file should be version controlled.
version:
revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
channel: stable
revision: 686fe913dc963954b99e62048569cb9ac8e551c8
channel: beta
project_type: app
@ -13,26 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: android
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: ios
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: linux
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: macos
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: web
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
- platform: windows
create_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
base_revision: ffccd96b62ee8cec7740dab303538c5fc26ac543
create_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
base_revision: 686fe913dc963954b99e62048569cb9ac8e551c8
# User provided section

@ -46,7 +46,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "dev.flutter.animations"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

@ -11,3 +11,6 @@ steps:
- windows
- name: Flutter recreate
flutter: create --org dev.flutter .
- name: Strip DEVELOPMENT_TEAM
strip-lines-containing: DEVELOPMENT_TEAM =
path: ios/Runner.xcodeproj/project.pbxproj

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -171,6 +171,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -185,6 +186,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -478,4 +480,4 @@
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -6,6 +6,8 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
// ignore: depend_on_referenced_packages
import 'package:window_size/window_size.dart';
@ -147,29 +149,39 @@ final miscDemos = [
builder: (context) => const CurvedAnimationDemo()),
];
final basicDemoRoutes =
Map.fromEntries(basicDemos.map((d) => MapEntry(d.route, d.builder)));
final miscDemoRoutes =
Map.fromEntries(miscDemos.map((d) => MapEntry(d.route, d.builder)));
final allRoutes = <String, WidgetBuilder>{
...basicDemoRoutes,
...miscDemoRoutes,
};
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
routes: [
for (final demo in basicDemos)
GoRoute(
path: demo.route,
builder: (context, state) => demo.builder(context),
),
for (final demo in miscDemos)
GoRoute(
path: demo.route,
builder: (context, state) => demo.builder(context),
),
],
),
],
);
class AnimationSamples extends StatelessWidget {
const AnimationSamples({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
return MaterialApp.router(
title: 'Animation Samples',
theme: ThemeData(
primarySwatch: Colors.deepPurple,
colorSchemeSeed: Colors.deepPurple,
useMaterial3: true,
),
routes: allRoutes,
home: const HomePage(),
routerConfig: router,
);
}
}
@ -206,7 +218,7 @@ class DemoTile extends StatelessWidget {
return ListTile(
title: Text(demo.name),
onTap: () {
Navigator.pushNamed(context, demo.route);
context.go('/${demo.route}');
},
);
}

@ -12,7 +12,7 @@ Color generateColor() => Color(0xFFFFFFFF & Random().nextInt(0xFFFFFFFF));
class AnimatedContainerDemo extends StatefulWidget {
const AnimatedContainerDemo({super.key});
static String routeName = '/basics/01_animated_container';
static String routeName = 'basics/01_animated_container';
@override
State<AnimatedContainerDemo> createState() => _AnimatedContainerDemoState();

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class PageRouteBuilderDemo extends StatelessWidget {
const PageRouteBuilderDemo({super.key});
static const String routeName = '/basics/page_route_builder';
static const String routeName = 'basics/page_route_builder';
@override
Widget build(BuildContext context) {

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class AnimationControllerDemo extends StatefulWidget {
const AnimationControllerDemo({super.key});
static const String routeName = '/basics/animation_controller';
static const String routeName = 'basics/animation_controller';
@override
State<AnimationControllerDemo> createState() =>

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class TweenDemo extends StatefulWidget {
const TweenDemo({super.key});
static const String routeName = '/basics/tweens';
static const String routeName = 'basics/tweens';
@override
State<TweenDemo> createState() => _TweenDemoState();

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class AnimatedBuilderDemo extends StatefulWidget {
const AnimatedBuilderDemo({super.key});
static const String routeName = '/basics/animated_builder';
static const String routeName = 'basics/animated_builder';
@override
State<AnimatedBuilderDemo> createState() => _AnimatedBuilderDemoState();

@ -17,7 +17,7 @@ class TypewriterTween extends Tween<String> {
class CustomTweenDemo extends StatefulWidget {
const CustomTweenDemo({super.key});
static const String routeName = '/basics/custom_tweens';
static const String routeName = 'basics/custom_tweens';
@override
State<CustomTweenDemo> createState() => _CustomTweenDemoState();
@ -50,8 +50,7 @@ class _CustomTweenDemoState extends State<CustomTweenDemo>
appBar: AppBar(
title: const Text('Custom Tween'),
actions: [
MaterialButton(
textColor: Colors.white,
TextButton(
onPressed: () {
if (controller.status == AnimationStatus.completed) {
controller.reverse().whenComplete(() {

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class TweenSequenceDemo extends StatefulWidget {
const TweenSequenceDemo({super.key});
static const String routeName = '/basics/chaining_tweens';
static const String routeName = 'basics/chaining_tweens';
@override
State<TweenSequenceDemo> createState() => _TweenSequenceDemoState();

@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
// for examples of other common animated widgets.
class FadeTransitionDemo extends StatefulWidget {
const FadeTransitionDemo({super.key});
static const String routeName = '/basics/fade_transition';
static const String routeName = 'basics/fade_transition';
@override
State<FadeTransitionDemo> createState() => _FadeTransitionDemoState();

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class AnimatedListDemo extends StatefulWidget {
const AnimatedListDemo({super.key});
static String routeName = '/misc/animated_list';
static String routeName = 'misc/animated_list';
@override
State<AnimatedListDemo> createState() => _AnimatedListDemoState();

@ -8,7 +8,7 @@ import 'package:flutter/material.dart';
class AnimatedPositionedDemo extends StatefulWidget {
const AnimatedPositionedDemo({super.key});
static String routeName = '/basics/09_animated_positioned';
static String routeName = 'misc/animated_positioned';
@override
State<AnimatedPositionedDemo> createState() => _AnimatedPositionedDemoState();

@ -24,7 +24,7 @@ Widget generateContainer(int keyCount) => Container(
class AnimatedSwitcherDemo extends StatefulWidget {
const AnimatedSwitcherDemo({super.key});
static String routeName = '/basics/10_animated_switcher';
static String routeName = 'misc/animated_switcher';
@override
State<AnimatedSwitcherDemo> createState() => _AnimatedSwitcherDemoState();
@ -47,15 +47,11 @@ class _AnimatedSwitcherDemoState extends State<AnimatedSwitcherDemo> {
appBar: AppBar(
title: const Text('AnimatedSwitcher'),
actions: [
MaterialButton(
TextButton(
onPressed: () => setState(
() => container = generateContainer(++keyCount),
),
child: Text(
'Change Widget',
style: TextStyle(
color: Theme.of(context).buttonTheme.colorScheme!.onPrimary),
),
child: const Text('Change Widget'),
),
],
),

@ -7,7 +7,7 @@ import 'package:flutter/physics.dart';
class CardSwipeDemo extends StatefulWidget {
const CardSwipeDemo({super.key});
static String routeName = '/misc/card_swipe';
static String routeName = 'misc/card_swipe';
@override
State<CardSwipeDemo> createState() => _CardSwipeDemoState();

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
class CarouselDemo extends StatelessWidget {
CarouselDemo({super.key});
static String routeName = '/misc/carousel';
static String routeName = 'misc/carousel';
static const List<String> fileNames = [
'assets/eat_cape_town_sm.jpg',

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
class CurvedAnimationDemo extends StatefulWidget {
const CurvedAnimationDemo({super.key});
static const String routeName = '/misc/curved_animation';
static const String routeName = 'misc/curved_animation';
@override
State<CurvedAnimationDemo> createState() => _CurvedAnimationDemoState();

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class ExpandCardDemo extends StatelessWidget {
const ExpandCardDemo({super.key});
static const String routeName = '/misc/expand_card';
static const String routeName = 'misc/expand_card';
@override
Widget build(BuildContext context) {

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class FocusImageDemo extends StatelessWidget {
const FocusImageDemo({super.key});
static String routeName = '/misc/focus_image';
static String routeName = 'misc/focus_image';
@override
Widget build(BuildContext context) {

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class HeroAnimationDemo extends StatelessWidget {
const HeroAnimationDemo({super.key});
static const String routeName = '/misc/hero_animation';
static const String routeName = 'misc/hero_animation';
@override
Widget build(BuildContext context) {

@ -7,7 +7,7 @@ import 'package:flutter/physics.dart';
class PhysicsCardDragDemo extends StatelessWidget {
const PhysicsCardDragDemo({super.key});
static const String routeName = '/misc/physics_card';
static const String routeName = 'misc/physics_card';
@override
Widget build(BuildContext context) {

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class RepeatingAnimationDemo extends StatefulWidget {
const RepeatingAnimationDemo({super.key});
static String routeName = '/misc/repeating_animation';
static String routeName = 'misc/repeating_animation';
@override
State<RepeatingAnimationDemo> createState() => _RepeatingAnimationDemoState();

@ -1,4 +1,4 @@
platform :osx, '10.11'
platform :osx, '10.14'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
@ -235,6 +235,7 @@
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -344,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
@ -423,7 +424,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@ -470,7 +471,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;

@ -11,4 +11,4 @@ PRODUCT_NAME = animations
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.animations
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2022 dev.flutter. All rights reserved.
PRODUCT_COPYRIGHT = Copyright © 2023 dev.flutter. All rights reserved.

@ -10,6 +10,7 @@ dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
go_router: ^6.0.0
dev_dependencies:
flutter_test:

@ -46,11 +46,12 @@
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine().then(function(appRunner) {
appRunner.runApp();
});
}
}).then(function(engineInitializer) {
return engineInitializer.initializeEngine();
}).then(function(appRunner) {
return appRunner.runApp();
});
});
</script>

@ -33,6 +33,7 @@ target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
# Add dependency libraries and include directories. Add any application-specific
# dependencies here.
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed.

@ -93,7 +93,7 @@ BEGIN
VALUE "FileDescription", "animations" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "animations" "\0"
VALUE "LegalCopyright", "Copyright (C) 2022 dev.flutter. All rights reserved." "\0"
VALUE "LegalCopyright", "Copyright (C) 2023 dev.flutter. All rights reserved." "\0"
VALUE "OriginalFilename", "animations.exe" "\0"
VALUE "ProductName", "animations" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"

@ -26,6 +26,11 @@ bool FlutterWindow::OnCreate() {
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
return true;
}

@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.CreateAndShow(L"animations", origin, size)) {
if (!window.Create(L"animations", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);

@ -1,13 +1,31 @@
#include "win32_window.h"
#include <dwmapi.h>
#include <flutter_windows.h>
#include "resource.h"
namespace {
/// Window attribute that enables dark mode window decorations.
///
/// Redefined in case the developer's machine has a Windows SDK older than
/// version 10.0.22000.0.
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
/// Registry key for app theme preference.
///
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
/// value indicates apps should use light mode.
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) {
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
FreeLibrary(user32_module);
}
FreeLibrary(user32_module);
}
} // namespace
@ -102,9 +120,9 @@ Win32Window::~Win32Window() {
Destroy();
}
bool Win32Window::CreateAndShow(const std::wstring& title,
const Point& origin,
const Size& size) {
bool Win32Window::Create(const std::wstring& title,
const Point& origin,
const Size& size) {
Destroy();
const wchar_t* window_class =
@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this);
@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
return false;
}
UpdateTheme(window);
return OnCreate();
}
bool Win32Window::Show() {
return ShowWindow(window_handle_, SW_SHOWNORMAL);
}
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd,
SetFocus(child_content_);
}
return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
@ -243,3 +271,18 @@ bool Win32Window::OnCreate() {
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
void Win32Window::UpdateTheme(HWND const window) {
DWORD light_mode;
DWORD light_mode_size = sizeof(light_mode);
LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
kGetPreferredBrightnessRegValue,
RRF_RT_REG_DWORD, nullptr, &light_mode,
&light_mode_size);
if (result == ERROR_SUCCESS) {
BOOL enable_dark_mode = light_mode == 0;
DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
&enable_dark_mode, sizeof(enable_dark_mode));
}
}

@ -28,15 +28,16 @@ class Win32Window {
Win32Window();
virtual ~Win32Window();
// Creates and shows a win32 window with |title| and position and size using
// Creates a win32 window with |title| that is positioned and sized using
// |origin| and |size|. New windows are created on the default monitor. Window
// sizes are specified to the OS in physical pixels, hence to ensure a
// consistent size to will treat the width height passed in to this function
// as logical pixels and scale to appropriate for the default monitor. Returns
// true if the window was created successfully.
bool CreateAndShow(const std::wstring& title,
const Point& origin,
const Size& size);
// consistent size this function will scale the inputted width and height as
// as appropriate for the default monitor. The window is invisible until
// |Show| is called. Returns true if the window was created successfully.
bool Create(const std::wstring& title, const Point& origin, const Size& size);
// Show the current window. Returns true if the window was successfully shown.
bool Show();
// Release OS resources associated with window.
void Destroy();
@ -86,6 +87,9 @@ class Win32Window {
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
// Update the window frame's theme to match the system theme.
static void UpdateTheme(HWND const window);
bool quit_on_close_ = false;
// window handle for top level window.

@ -0,0 +1 @@
include: ../analysis_options.yaml

@ -0,0 +1,155 @@
// Copyright 2022 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io' show Directory;
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart' as uuid;
import 'simple_database.dart';
///////////////////////////////////////////////////////////////////////////////
// This is the UI which will present the contents of the [SimpleDatabase]. To
// see where Background Isolate Channels are used see simple_database.dart.
///////////////////////////////////////////////////////////////////////////////
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Background Isolate Channels',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Background Isolate Channels'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
/// The database that is running on a background [Isolate]. This is nullable
/// because acquiring a [SimpleDatabase] is an asynchronous operation. This
/// value is `null` until the database is initialized.
SimpleDatabase? _database;
/// Local cache of the query results returned by the [SimpleDatabase] for the
/// UI to render from. It is nullable since querying the results is
/// asynchronous. The value is `null` before any result has been received.
List<String>? _entries;
/// What is searched for in the [SimpleDatabase].
String _query = '';
@override
void initState() {
// Write the value to [SharedPreferences] which will get read on the
// [SimpleDatabase]'s isolate. For this example the value is always true
// just for demonstration purposes.
final Future<void> sharedPreferencesSet = SharedPreferences.getInstance()
.then(
(sharedPreferences) => sharedPreferences.setBool('isDebug', true));
final Future<Directory> tempDirFuture =
path_provider.getTemporaryDirectory();
// Wait until the [SharedPreferences] value is set and the temporary
// directory is received before opening the database. If
// [sharedPreferencesSet] does not happen before opening the
// [SimpleDatabase] there has to be a way to refresh
// [_SimpleDatabaseServer]'s [SharedPreferences] cached values.
Future.wait([sharedPreferencesSet, tempDirFuture]).then((values) {
final Directory? tempDir = values[1] as Directory?;
final String dbPath = path.join(tempDir!.path, 'database.db');
SimpleDatabase.open(dbPath).then((database) {
setState(() {
_database = database;
});
_refresh();
});
});
super.initState();
}
@override
void dispose() {
_database?.stop();
super.dispose();
}
/// Performs a find on [SimpleDatabase] with [query] and updates the listed
/// contents.
void _refresh({String? query}) {
if (query != null) {
_query = query;
}
_database!.find(_query).toList().then((entries) {
setState(() {
_entries = entries;
});
});
}
/// Adds a UUID and a timestamp to the [SimpleDatabase].
void _addDate() {
final DateTime now = DateTime.now();
final DateFormat formatter =
DateFormat('EEEE MMMM d, HH:mm:ss\n${const uuid.Uuid().v4()}');
final String formatted = formatter.format(now);
_database!.addEntry(formatted).then((_) => _refresh());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
TextField(
onChanged:
_database == null ? null : (query) => _refresh(query: query),
decoration: const InputDecoration(
labelText: 'Search',
suffixIcon: Icon(Icons.search),
),
),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return ListTile(title: Text(_entries![index]));
},
itemCount: _entries?.length ?? 0,
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _database == null ? null : _addDate,
tooltip: 'Add',
child: const Icon(Icons.add),
),
);
}
}

@ -0,0 +1,255 @@
// Copyright 2022 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
///////////////////////////////////////////////////////////////////////////////
// **WARNING:** This is not production code and is only intended to be used for
// demonstration purposes.
//
// The following database works by spawning a background isolate and
// communicating with it over Dart's SendPort API. It is presented below as a
// demonstration of the feature "Background Isolate Channels" and shows using
// plugins from a background isolate. The [SimpleDatabase] operates on the root
// isolate and the [_SimpleDatabaseServer] operates on a background isolate.
//
// Here is an example of the protocol they use to communicate:
//
// _________________ ________________________
// [:SimpleDatabase] [:_SimpleDatabaseServer]
// ----------------- ------------------------
// | |
// |<---------------(init)------------------------|
// |----------------(init)----------------------->|
// |<---------------(ack)------------------------>|
// | |
// |----------------(add)------------------------>|
// |<---------------(ack)-------------------------|
// | |
// |----------------(query)---------------------->|
// |<---------------(result)----------------------|
// |<---------------(result)----------------------|
// |<---------------(done)------------------------|
//
///////////////////////////////////////////////////////////////////////////////
/// The size of the database entries in bytes.
const int _entrySize = 256;
/// All the command codes that can be sent and received between [SimpleDatabase] and
/// [_SimpleDatabaseServer].
enum _Codes {
init,
add,
query,
ack,
result,
done,
}
/// A command sent between [SimpleDatabase] and [_SimpleDatabaseServer].
class _Command {
const _Command(this.code, {this.arg0, this.arg1});
final _Codes code;
final Object? arg0;
final Object? arg1;
}
/// A SimpleDatabase that stores entries of strings to disk where they can be
/// queried.
///
/// All the disk operations and queries are executed in a background isolate
/// operating. This class just sends and receives messages to the isolate.
class SimpleDatabase {
SimpleDatabase._(this._isolate, this._path);
final Isolate _isolate;
final String _path;
late final SendPort _sendPort;
// Completers are stored in a queue so multiple commands can be queued up and
// handled serially.
final Queue<Completer<void>> _completers = Queue<Completer<void>>();
// Similarly, StreamControllers are stored in a queue so they can be handled
// asynchronously and serially.
final Queue<StreamController<String>> _resultsStream =
Queue<StreamController<String>>();
/// Open the database at [path] and launch the server on a background isolate..
static Future<SimpleDatabase> open(String path) async {
final ReceivePort receivePort = ReceivePort();
final Isolate isolate =
await Isolate.spawn(_SimpleDatabaseServer._run, receivePort.sendPort);
final SimpleDatabase result = SimpleDatabase._(isolate, path);
Completer<void> completer = Completer<void>();
result._completers.addFirst(completer);
receivePort.listen((message) {
result._handleCommand(message as _Command);
});
await completer.future;
return result;
}
/// Writes [value] to the database.
Future<void> addEntry(String value) {
// No processing happens on the calling isolate, it gets delegated to the
// background isolate, see [__SimpleDatabaseServer._doAddEntry].
Completer<void> completer = Completer<void>();
_completers.addFirst(completer);
_sendPort.send(_Command(_Codes.add, arg0: value));
return completer.future;
}
/// Returns all the strings in the database that contain [query].
Stream<String> find(String query) {
// No processing happens on the calling isolate, it gets delegated to the
// background isolate, see [__SimpleDatabaseServer._doFind].
StreamController<String> resultsStream = StreamController<String>();
_resultsStream.addFirst(resultsStream);
_sendPort.send(_Command(_Codes.query, arg0: query));
return resultsStream.stream;
}
/// Handler invoked when a message is received from the port communicating
/// with the database server.
void _handleCommand(_Command command) {
switch (command.code) {
case _Codes.init:
_sendPort = command.arg0 as SendPort;
// ----------------------------------------------------------------------
// Before using platform channels and plugins from background isolates we
// need to register it with its root isolate. This is achieved by
// acquiring a [RootIsolateToken] which the background isolate uses to
// invoke [BackgroundIsolateBinaryMessenger.ensureInitialized].
// ----------------------------------------------------------------------
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
_sendPort
.send(_Command(_Codes.init, arg0: _path, arg1: rootIsolateToken));
break;
case _Codes.ack:
_completers.removeLast().complete();
break;
case _Codes.result:
_resultsStream.last.add(command.arg0 as String);
break;
case _Codes.done:
_resultsStream.removeLast().close();
break;
default:
debugPrint('SimpleDatabase unrecognized command: ${command.code}');
}
}
/// Kills the background isolate and its database server.
void stop() {
_isolate.kill();
}
}
/// The portion of the [SimpleDatabase] that runs on the background isolate.
///
/// This is where we use the new feature Background Isolate Channels, which
/// allows us to use plugins from background isolates.
class _SimpleDatabaseServer {
_SimpleDatabaseServer(this._sendPort);
final SendPort _sendPort;
late final String _path;
// ----------------------------------------------------------------------
// Here the plugin is used from the background isolate.
// ----------------------------------------------------------------------
/// The main entrypoint for the background isolate sent to [Isolate.spawn].
static void _run(SendPort sendPort) {
ReceivePort receivePort = ReceivePort();
sendPort.send(_Command(_Codes.init, arg0: receivePort.sendPort));
final _SimpleDatabaseServer server = _SimpleDatabaseServer(sendPort);
receivePort.listen((message) async {
final _Command command = message as _Command;
await server._handleCommand(command);
});
}
/// Handle the [command] received from the [ReceivePort].
Future<void> _handleCommand(_Command command) async {
switch (command.code) {
case _Codes.init:
_path = command.arg0 as String;
// ----------------------------------------------------------------------
// The [RootIsolateToken] is required for
// [BackgroundIsolateBinaryMessenger.ensureInitialized] and must be
// obtained on the root isolate and passed into the background isolate via
// a [SendPort].
// ----------------------------------------------------------------------
RootIsolateToken rootIsolateToken = command.arg1 as RootIsolateToken;
// ----------------------------------------------------------------------
// [BackgroundIsolateBinaryMessenger.ensureInitialized] for each
// background isolate that will use plugins. This sets up the
// [BinaryMessenger] that the Platform Channels will communicate with on
// the background isolate.
// ----------------------------------------------------------------------
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
_sendPort.send(const _Command(_Codes.ack, arg0: null));
break;
case _Codes.add:
_doAddEntry(command.arg0 as String);
break;
case _Codes.query:
_doFind(command.arg0 as String);
break;
default:
debugPrint(
'_SimpleDatabaseServer unrecognized command ${command.code}');
}
}
/// Perform the add entry operation.
void _doAddEntry(String value) {
debugPrint('Performing add: $value');
File file = File(_path);
if (!file.existsSync()) {
file.createSync();
}
RandomAccessFile writer = file.openSync(mode: FileMode.append);
List<int> bytes = utf8.encode(value);
if (bytes.length > _entrySize) {
bytes = bytes.sublist(0, _entrySize);
} else if (bytes.length < _entrySize) {
List<int> newBytes = List.filled(_entrySize, 0);
for (int i = 0; i < bytes.length; ++i) {
newBytes[i] = bytes[i];
}
bytes = newBytes;
}
writer.writeFromSync(bytes);
writer.closeSync();
_sendPort.send(const _Command(_Codes.ack, arg0: null));
}
/// Perform the find entry operation.
void _doFind(String query) {
debugPrint('Performing find: $query');
File file = File(_path);
if (file.existsSync()) {
RandomAccessFile reader = file.openSync();
List<int> buffer = List.filled(_entrySize, 0);
while (reader.readIntoSync(buffer) == _entrySize) {
List<int> foo = buffer.takeWhile((value) => value != 0).toList();
String string = utf8.decode(foo);
if (string.contains(query)) {
_sendPort.send(_Command(_Codes.result, arg0: string));
}
}
reader.closeSync();
}
_sendPort.send(const _Command(_Codes.done, arg0: null));
}
}

@ -0,0 +1,27 @@
name: background_isolate_channels
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: '>=2.19.0-224.0.dev <3.0.0'
dependencies:
cupertino_icons: ^1.0.2
flutter:
sdk: flutter
intl: ^0.18.0
path: ^1.8.2
path_provider: ^2.0.11
shared_preferences: ^2.0.15
uuid: ^3.0.6
dev_dependencies:
flutter_lints: ^2.0.1
flutter_test:
sdk: flutter
flutter:
uses-material-design: true

@ -0,0 +1,26 @@
# Use latest stable channel SDK.
FROM dart:stable AS build
# Copy shared code.
WORKDIR /shared
COPY /shared/. .
# Copy server code.
WORKDIR /server
COPY /server/. .
# Resolve app dependencies.
RUN dart pub get
# AOT compile app.
RUN dart compile exe bin/server.dart -o bin/server
# Build minimal serving image from AOT-compiled `/server`
# and the pre-built AOT-runtime in the `/runtime/` directory of the base image.
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /server/bin/server /app/bin/
# Start server.
EXPOSE 8080
CMD ["/app/bin/server"]

@ -0,0 +1,24 @@
# MacOS/Linux-only. Sadly, this is only helpful as documentation for Windows.
# LOCAL / DOCKER
run-server:
# Depends on `make build`
docker-compose up -d
stop-server:
docker-compose stop
# Flutter
flutter-local:
cd client && flutter run -d macos
test:
(cd shared && dart test)
(cd server && dart test)
(cd client && flutter test)
# Docker
build:
(cd server && dart pub get)
docker build . -t codesharingserver

@ -0,0 +1,191 @@
# Code Sharing
A full-stack Dart application using Flutter on the client and
[`shelf`](https://pub.dev/packages/shelf) on the server. The Flutter app
itself is still the counter app, but the actual number is stored on the server
and incremented over HTTP using transport data classes understood by both the
Flutter client and shelf server.
## Goals
The goal of this sample is to demonstrate the mechanics of sharing business
logic between a Flutter client and a Dart server. The sample also includes a
slightly modified Dockerfile which is required to build a Docker image from
a Dart app containing nested packages.
## Project Structure
The sample's project structure is as follows:
```
code_sharing/
# Flutter app
client/
lib/
...
pubspec.yaml
...
# Shelf
server/
bin/
server.dart
pubspec.yaml
Dockerfile
# Common business logic
shared/
pubspec.yaml
lib/
...
```
## Recreating this on your own
Recreating this introductory project for yourself can be done in several steps.
1. Create a parent directory, likely sharing a name with your project or
product, which will contain everything.
2. Within that directory, run `flutter create client`. You may also name this
Flutter project `app`, `mobile`, `<project-name>-app` or anything else that
seems appropriate. At this point, your folder structure should look like this:
```
my_project/
client/
lib/
main.dart
pubspec.yaml
...
```
3. From the same location where you ran `flutter create`, run
`dart create -t server-shelf server`. You may also name this Shelf project,
`backend`, `api`, `<project-name>-server`, or anything else that seems
appropriate. At this point, your folder structure should look like this:
```
my_project/
client/
lib/
main.dart
pubspec.yaml
...
server/
bin/
server.dart
Dockerfile
pubspec.yaml
...
```
4. Enter your server directory (`cd server`), and run `dart create -t package shared`.
You may also name this package `common`, `domain`, `<project-name>-shared`, or
anything else that seems appropriate. At this point, your folder structure should
resemble the sample:
```
my_project/
client/
lib/
main.dart
pubspec.yaml
...
server/
bin/
server.dart
shared/
lib/
src/
...
shared.dart
pubspec.yaml
...
Dockerfile
pubspec.yaml
...
```
5. Next, begin granting access to your shared code by making the following
edits to your Flutter app's `pubspec.yaml` file. Open that file
(`client/pubspec.yaml`) and add the following dependency under the
`dependencies` block:
```
dependencies:
# Add these two lines:
shared:
path: ../server/shared
```
6. Next, finish granting access to your shared code by making the following
edits to your server's `pubspec.yaml` file. Open that file
(`server/pubspec.yaml`) and add the following dependency under the
`dependencies` block:
```
dependencies:
# Add these two lines:
shared:
path: ./shared
```
7. The final step is to adjust your `Dockerfile`, as it can no longer
successfully run `dart pub get` after only copying over the `pubspec.yaml`
file (that command now requires the entirety of your `shared` directory to be
present.
- Find the line that says `COPY pubspec.* ./`, and change it to `COPY . .`.
With that, you're ready to build and run the app.
## Running the sample
To run the sample, or an equivalent you've reconstructed yourself, choose a
runtime method below based on your needs.
### From the CLI
In one terminal window, run the following commands:
```sh
cd my_project/server
dart run bin/server.dart
```
In a separate terminal window, run the following commands:
```sh
cd my_project/client
flutter run
```
> Note: If you named your mobile client and backend servers something other
than `client` and `server`, you will need to substitute in those values above.
### Build and run with Docker
To build your server's Docker image, run the following commands in a terminal
window:
```sh
cd my_project/server
docker build . -t my_project_server
```
To run that image as a Docker container, run the following commands in a
terminal window:
```sh
docker run -it my_project_server
```
### Build and run with `docker-compose`
If you have [`docker-compose`](https://docs.docker.com/compose/install/)
installed on your machine, you can run the following command to build and
launch your server:
```sh
cd my_project
docker-compose up -d
```
And then later stop the server with:
```sh
docker-compose stop
```

@ -8,6 +8,7 @@
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
@ -31,9 +32,6 @@
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols

@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled.
version:
revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
channel: main
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: android
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: ios
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: linux
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: macos
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: web
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
- platform: windows
create_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
base_revision: f16fe11ecf81a85d926ea3817ba1c87bdbbefa41
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

@ -0,0 +1,16 @@
# client
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

@ -22,8 +22,8 @@ linter:
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
avoid_print: false
prefer_single_quotes: true
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
# https://dart.dev/guides/language/analysis-options

@ -44,7 +44,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.null_safe_app"
applicationId "com.example.client"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion flutter.minSdkVersion

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.null_safe_app">
package="com.example.client">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.null_safe_app">
package="com.example.client">
<application
android:label="null_safe_app"
android:label="client"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

@ -1,5 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.null_safe_app">
package="com.example.client">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

@ -0,0 +1 @@
#include "Generated.xcconfig"

@ -0,0 +1 @@
#include "Generated.xcconfig"

@ -3,14 +3,13 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
8748D946026204182E6B40D0 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FFEE57B373485B4E5061F1D /* Pods_Runner.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
@ -32,12 +31,10 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
225928EB6BEF9C71BAA174AC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7D2BD6112A0848868742BAE5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -45,8 +42,6 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9FFEE57B373485B4E5061F1D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7F95606AB9D77667850CC96 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -54,32 +49,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8748D946026204182E6B40D0 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
13317245121AEC564850999A /* Frameworks */ = {
isa = PBXGroup;
children = (
9FFEE57B373485B4E5061F1D /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
153F4A5B2684EF7375FE2B98 /* Pods */ = {
isa = PBXGroup;
children = (
7D2BD6112A0848868742BAE5 /* Pods-Runner.debug.xcconfig */,
D7F95606AB9D77667850CC96 /* Pods-Runner.release.xcconfig */,
225928EB6BEF9C71BAA174AC /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@ -97,8 +72,6 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
153F4A5B2684EF7375FE2B98 /* Pods */,
13317245121AEC564850999A /* Frameworks */,
);
sourceTree = "<group>";
};
@ -132,7 +105,6 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
AFA824A7938C6B95337017B3 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
@ -199,6 +171,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -213,6 +186,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -225,28 +199,6 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
AFA824A7938C6B95337017B3 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -344,7 +296,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nullUnsafeApp;
PRODUCT_BUNDLE_IDENTIFIER = com.example.client;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -472,7 +424,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nullUnsafeApp;
PRODUCT_BUNDLE_IDENTIFIER = com.example.client;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -494,7 +446,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.nullUnsafeApp;
PRODUCT_BUNDLE_IDENTIFIER = com.example.client;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save