mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Enable null safety by default in templates (#78619)
This commit is contained in:
parent
e93590474d
commit
2cdd51900c
@ -38,13 +38,14 @@ void main() {
|
||||
run(ui.window.defaultRouteName);
|
||||
}
|
||||
|
||||
Future<String> run(String name) async {
|
||||
Future<String> run(String? name) async {
|
||||
// The platform-specific component will call [setInitialRoute] on the Flutter
|
||||
// view (or view controller for iOS) to set [ui.window.defaultRouteName].
|
||||
// We then dispatch based on the route names to show different Flutter
|
||||
// widgets.
|
||||
// Since we don't really care about Flutter-side navigation in this app, we're
|
||||
// not using a regular routes map.
|
||||
name ??= '';
|
||||
switch (name) {
|
||||
case greenMarqueeRouteName:
|
||||
runApp(Marquee(color: Colors.green[400]));
|
||||
@ -62,7 +63,7 @@ Future<String> run(String name) async {
|
||||
}
|
||||
|
||||
class FlutterView extends StatelessWidget {
|
||||
const FlutterView({@required this.initialRoute});
|
||||
const FlutterView({required this.initialRoute});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -76,7 +77,7 @@ class FlutterView extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({this.initialRoute});
|
||||
const MyHomePage({required this.initialRoute});
|
||||
|
||||
@override
|
||||
_MyHomePageState createState() => _MyHomePageState();
|
||||
@ -131,7 +132,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
/// Callback for messages sent by the platform-specific component.
|
||||
///
|
||||
/// Increments our internal counter.
|
||||
Future<String> _handlePlatformIncrement(String message) async {
|
||||
Future<String> _handlePlatformIncrement(String? message) async {
|
||||
// Normally we'd dispatch based on the value of [message], but in this
|
||||
// sample, there is only one message that is sent to us.
|
||||
_incrementCounter();
|
||||
|
@ -7,7 +7,7 @@ import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class _MarqueeText extends AnimatedWidget {
|
||||
const _MarqueeText({Key key, Animation<double> animation})
|
||||
const _MarqueeText({Key? key, required Animation<double> animation})
|
||||
: super(key: key, listenable: animation);
|
||||
|
||||
@override
|
||||
@ -26,15 +26,15 @@ class _MarqueeText extends AnimatedWidget {
|
||||
class Marquee extends StatefulWidget {
|
||||
const Marquee({this.color});
|
||||
|
||||
final Color color;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => MarqueeState();
|
||||
}
|
||||
|
||||
class MarqueeState extends State<Marquee> with SingleTickerProviderStateMixin {
|
||||
AnimationController controller;
|
||||
Animation<double> animation;
|
||||
late AnimationController controller;
|
||||
late Animation<double> animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -242,8 +242,8 @@ class CreateCommand extends CreateBase {
|
||||
macos: featureFlags.isMacOSEnabled && platforms.contains('macos'),
|
||||
windows: featureFlags.isWindowsEnabled && platforms.contains('windows'),
|
||||
windowsUwp: featureFlags.isWindowsUwpEnabled && platforms.contains('winuwp'),
|
||||
// Enable null-safety for sample code, which is - unlike our regular templates - already migrated.
|
||||
dartSdkVersionBounds: sampleCode != null ? '">=2.12.0-0 <3.0.0"' : '">=2.7.0 <3.0.0"'
|
||||
// Enable null safety everywhere.
|
||||
dartSdkVersionBounds: '">=2.12.0 <3.0.0"'
|
||||
);
|
||||
|
||||
final String relativeDirPath = globals.fs.path.relative(projectDirPath);
|
||||
@ -325,11 +325,6 @@ In order to run your $application, type:
|
||||
\$ cd $relativeAppPath
|
||||
\$ flutter run
|
||||
|
||||
To enable null safety, type:
|
||||
|
||||
\$ cd $relativeAppPath
|
||||
\$ dart migrate --apply-changes
|
||||
|
||||
Your $application code is in $relativeAppMain.
|
||||
''');
|
||||
// Show warning if any selected platform is not enabled
|
||||
|
@ -35,7 +35,7 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
MyHomePage({Key? key, required this.title}) : super(key: key);
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
@ -138,8 +138,10 @@ class _MyAppState extends State<MyApp> {
|
||||
Future<void> initPlatformState() async {
|
||||
String platformVersion;
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
// We also handle the message potentially returning null.
|
||||
try {
|
||||
platformVersion = await {{pluginDartClass}}.platformVersion;
|
||||
platformVersion =
|
||||
await {{pluginDartClass}}.platformVersion ?? 'Unknown platform version';
|
||||
} on PlatformException {
|
||||
platformVersion = 'Failed to get platform version.';
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ void main() {
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(Widget widget) => widget is Text &&
|
||||
widget.data.startsWith('Running on:'),
|
||||
widget.data!.startsWith('Running on:'),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
@ -32,7 +32,7 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
MyHomePage({Key? key, required this.title}) : super(key: key);
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
@ -135,8 +135,10 @@ class _MyAppState extends State<MyApp> {
|
||||
Future<void> initPlatformState() async {
|
||||
String platformVersion;
|
||||
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||
// We also handle the message potentially returning null.
|
||||
try {
|
||||
platformVersion = await {{pluginDartClass}}.platformVersion;
|
||||
platformVersion =
|
||||
await {{pluginDartClass}}.platformVersion ?? 'Unknown platform version';
|
||||
} on PlatformException {
|
||||
platformVersion = 'Failed to get platform version.';
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ void main() {
|
||||
expect(
|
||||
find.byWidgetPredicate(
|
||||
(Widget widget) => widget is Text &&
|
||||
widget.data.startsWith('Running on:'),
|
||||
widget.data!.startsWith('Running on:'),
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
@ -13,8 +13,8 @@ class {{pluginDartClass}} {
|
||||
static const MethodChannel _channel =
|
||||
const MethodChannel('{{projectName}}');
|
||||
|
||||
static Future<String> get platformVersion async {
|
||||
final String version = await _channel.invokeMethod('getPlatformVersion');
|
||||
static Future<String?> get platformVersion async {
|
||||
final String? version = await _channel.invokeMethod('getPlatformVersion');
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ class {{pluginDartClass}}Web {
|
||||
switch (call.method) {
|
||||
case 'getPlatformVersion':
|
||||
return getPlatformVersion();
|
||||
break;
|
||||
default:
|
||||
throw PlatformException(
|
||||
code: 'Unimplemented',
|
||||
|
@ -4,7 +4,7 @@ version: 0.0.1
|
||||
homepage:
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
sdk: {{dartSdkVersionBounds}}
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
dependencies:
|
||||
|
@ -2450,25 +2450,6 @@ void main() {
|
||||
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true, isAndroidEnabled: false, isIOSEnabled: false),
|
||||
Logger: () => logger,
|
||||
});
|
||||
|
||||
testUsingContext('flutter create prints note about null safety', () async {
|
||||
await _createProject(
|
||||
projectDir,
|
||||
<String>[],
|
||||
<String>[],
|
||||
);
|
||||
expect(logger.statusText, contains('dart migrate --apply-changes'));
|
||||
}, overrides: <Type, Generator>{
|
||||
Pub: () => Pub(
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
processManager: globals.processManager,
|
||||
usage: globals.flutterUsage,
|
||||
botDetector: globals.botDetector,
|
||||
platform: globals.platform,
|
||||
),
|
||||
Logger: () => logger,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _createProject(
|
||||
|
@ -47,7 +47,7 @@ void main() {
|
||||
// We need to add a dependency with web support to trigger
|
||||
// the generated_plugin_registrant generation.
|
||||
await _addDependency(projectDir, 'shared_preferences',
|
||||
version: '^0.5.12+4');
|
||||
version: '^2.0.0');
|
||||
await _analyzeProject(projectDir);
|
||||
|
||||
expect(
|
||||
|
@ -1,106 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import 'test_utils.dart';
|
||||
|
||||
void main() {
|
||||
/// Verifies that `dart migrate` will run successfully on the default `flutter create`
|
||||
/// template.
|
||||
group('dart migrate', () {
|
||||
testWithoutContext('dart migrate succeeds on flutter create template', () async {
|
||||
Directory tempDir;
|
||||
try {
|
||||
tempDir = await _createProject(tempDir);
|
||||
await _migrate(tempDir);
|
||||
await _analyze(tempDir);
|
||||
} finally {
|
||||
tempDir?.deleteSync(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
/// Verifies that `dart migrate` will run successfully on the module template
|
||||
/// used by `flutter create --template=module`.
|
||||
testWithoutContext('dart migrate succeeds on module template', () async {
|
||||
Directory tempDir;
|
||||
try {
|
||||
tempDir = await _createProject(tempDir, <String>['--template=module']);
|
||||
await _migrate(tempDir);
|
||||
await _analyze(tempDir);
|
||||
} finally {
|
||||
tempDir?.deleteSync(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
/// Verifies that `dart migrate` will run successfully on the module template
|
||||
/// used by `flutter create --template=plugin`.
|
||||
testWithoutContext('dart migrate succeeds on plugin template', () async {
|
||||
Directory tempDir;
|
||||
try {
|
||||
tempDir = await _createProject(tempDir, <String>['--template=plugin']);
|
||||
await _migrate(tempDir);
|
||||
await _analyze(tempDir);
|
||||
} finally {
|
||||
tempDir?.deleteSync(recursive: true);
|
||||
}
|
||||
});
|
||||
|
||||
/// Verifies that `dart migrate` will run successfully on the module template
|
||||
/// used by `flutter create --template=package`.
|
||||
testWithoutContext('dart migrate succeeds on package template', () async {
|
||||
Directory tempDir;
|
||||
try {
|
||||
tempDir = await _createProject(tempDir, <String>['--template=package']);
|
||||
await _migrate(tempDir);
|
||||
await _analyze(tempDir);
|
||||
} finally {
|
||||
tempDir?.deleteSync(recursive: true);
|
||||
}
|
||||
});
|
||||
}, timeout: const Timeout(Duration(seconds: 90)));
|
||||
}
|
||||
|
||||
Future<Directory> _createProject(Directory tempDir, [List<String> extraAgs]) async {
|
||||
tempDir = createResolvedTempDirectorySync('dart_migrate_test.');
|
||||
final ProcessResult createResult = await processManager.run(<String>[
|
||||
_flutterBin,
|
||||
'create',
|
||||
if (extraAgs != null)
|
||||
...extraAgs,
|
||||
'foo',
|
||||
], workingDirectory: tempDir.path);
|
||||
if (createResult.exitCode != 0) {
|
||||
fail('flutter create did not work: ${createResult.stdout}${createResult.stderr}');
|
||||
}
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
Future<void> _migrate(Directory tempDir) async {
|
||||
final ProcessResult migrateResult = await processManager.run(<String>[
|
||||
_dartBin,
|
||||
'migrate',
|
||||
'--apply-changes',
|
||||
], workingDirectory: fileSystem.path.join(tempDir.path, 'foo'));
|
||||
if (migrateResult.exitCode != 0) {
|
||||
fail('dart migrate did not work: ${migrateResult.stdout}${migrateResult.stderr}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _analyze(Directory tempDir) async {
|
||||
final ProcessResult analyzeResult = await processManager.run(<String>[
|
||||
_flutterBin,
|
||||
'analyze',
|
||||
], workingDirectory: fileSystem.path.join(tempDir.path, 'foo'));
|
||||
if (analyzeResult.exitCode != 0) {
|
||||
fail('flutter analyze had errors: ${analyzeResult.stdout}${analyzeResult.stderr}');
|
||||
}
|
||||
}
|
||||
|
||||
String get _flutterBin => fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter');
|
||||
String get _dartBin => fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'dart.bat' : 'dart');
|
Loading…
Reference in New Issue
Block a user