mirror of
https://github.com/flutter/flutter
synced 2024-09-13 21:32:11 +00:00
Add API to read flavor from framework at run time (#134179)
Resolves #128046.
Adds a services API that allows flutter app developers to write app code that determines `--flavor` the app was built with.
This is implemented by having the tool adding the value of `--flavor` to its list of dart environment declarations, which will be available to the app at run time. Specifically,`FLUTTER_APP_FLAVOR` is set. I chose this implementation for its simplicity. There is some precedent for this, but only for web ([example](cd2f3f5e78/packages/flutter_tools/lib/src/runner/flutter_command.dart (L1231)
)).
This commit is contained in:
parent
c35515a079
commit
aa498cd51a
|
@ -3,6 +3,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flavors/main.dart' as app;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
|
@ -16,6 +17,7 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('paid'), findsOneWidget);
|
||||
expect(appFlavor, 'paid');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ export 'src/services/browser_context_menu.dart';
|
|||
export 'src/services/clipboard.dart';
|
||||
export 'src/services/debug.dart';
|
||||
export 'src/services/deferred_component.dart';
|
||||
export 'src/services/flavor.dart';
|
||||
export 'src/services/font_loader.dart';
|
||||
export 'src/services/haptic_feedback.dart';
|
||||
export 'src/services/hardware_keyboard.dart';
|
||||
|
|
10
packages/flutter/lib/src/services/flavor.dart
Normal file
10
packages/flutter/lib/src/services/flavor.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
// 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.
|
||||
|
||||
/// The flavor this app was built with.
|
||||
///
|
||||
/// This is equivalent to the value argued to the `--flavor` option at build time.
|
||||
/// This will be `null` if the `--flavor` option was not provided.
|
||||
const String? appFlavor = String.fromEnvironment('FLUTTER_APP_FLAVOR') != '' ?
|
||||
String.fromEnvironment('FLUTTER_APP_FLAVOR') : null;
|
|
@ -1247,10 +1247,20 @@ abstract class FlutterCommand extends Command<void> {
|
|||
}
|
||||
}
|
||||
|
||||
final String? flavor = argParser.options.containsKey('flavor') ? stringArg('flavor') : null;
|
||||
if (flavor != null) {
|
||||
if (globals.platform.environment['FLUTTER_APP_FLAVOR'] != null) {
|
||||
throwToolExit('FLUTTER_APP_FLAVOR is used by the framework and cannot be set in the environment.');
|
||||
}
|
||||
if (dartDefines.any((String define) => define.startsWith('FLUTTER_APP_FLAVOR'))) {
|
||||
throwToolExit('FLUTTER_APP_FLAVOR is used by the framework and cannot be '
|
||||
'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}');
|
||||
}
|
||||
dartDefines.add('FLUTTER_APP_FLAVOR=$flavor');
|
||||
}
|
||||
|
||||
return BuildInfo(buildMode,
|
||||
argParser.options.containsKey('flavor')
|
||||
? stringArg('flavor')
|
||||
: null,
|
||||
flavor,
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
frontendServerStarterPath: argParser.options
|
||||
.containsKey(FlutterOptions.kFrontendServerStarterPath)
|
||||
|
|
|
@ -11,11 +11,14 @@ import 'package:flutter_tools/src/base/common.dart';
|
|||
import 'package:flutter_tools/src/base/error_handling_io.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/signals.dart';
|
||||
import 'package:flutter_tools/src/base/time.dart';
|
||||
import 'package:flutter_tools/src/base/user_messages.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/run.dart';
|
||||
import 'package:flutter_tools/src/dart/pub.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
@ -700,6 +703,67 @@ void main() {
|
|||
expect(testLogger.statusText, contains(UserMessages().flutterSpecifyDevice));
|
||||
});
|
||||
});
|
||||
|
||||
group('--flavor', () {
|
||||
late _TestDeviceManager testDeviceManager;
|
||||
late Logger logger;
|
||||
late FileSystem fileSystem;
|
||||
|
||||
setUp(() {
|
||||
logger = BufferLogger.test();
|
||||
testDeviceManager = _TestDeviceManager(logger: logger);
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
});
|
||||
|
||||
testUsingContext("tool exits when FLUTTER_APP_FLAVOR is already set in user's environment", () async {
|
||||
fileSystem.file('lib/main.dart').createSync(recursive: true);
|
||||
fileSystem.file('pubspec.yaml').createSync();
|
||||
fileSystem.file('.packages').createSync();
|
||||
|
||||
final FakeDevice device = FakeDevice('name', 'id');
|
||||
testDeviceManager.devices = <Device>[device];
|
||||
final _TestRunCommandThatOnlyValidates command = _TestRunCommandThatOnlyValidates();
|
||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||
|
||||
expect(runner.run(<String>['run', '--no-pub', '--no-hot', '--flavor=strawberry']),
|
||||
throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set in the environment.'));
|
||||
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => testDeviceManager,
|
||||
Platform: () => FakePlatform(
|
||||
environment: <String, String>{
|
||||
'FLUTTER_APP_FLAVOR': 'I was already set'
|
||||
}
|
||||
),
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('tool exits when FLUTTER_APP_FLAVOR is set in --dart-define or --dart-define-from-file', () async {
|
||||
fileSystem.file('lib/main.dart').createSync(recursive: true);
|
||||
fileSystem.file('pubspec.yaml').createSync();
|
||||
fileSystem.file('.packages').createSync();
|
||||
fileSystem.file('config.json')..createSync()..writeAsStringSync('{"FLUTTER_APP_FLAVOR": "strawberry"}');
|
||||
|
||||
final FakeDevice device = FakeDevice('name', 'id');
|
||||
testDeviceManager.devices = <Device>[device];
|
||||
final _TestRunCommandThatOnlyValidates command = _TestRunCommandThatOnlyValidates();
|
||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||
|
||||
expect(runner.run(<String>['run', '--dart-define=FLUTTER_APP_FLAVOR=strawberry', '--no-pub', '--no-hot', '--flavor=strawberry']),
|
||||
throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set using --dart-define or --dart-define-from-file'));
|
||||
|
||||
expect(runner.run(<String>['run', '--dart-define-from-file=config.json', '--no-pub', '--no-hot', '--flavor=strawberry']),
|
||||
throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set using --dart-define or --dart-define-from-file'));
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => testDeviceManager,
|
||||
Platform: () => FakePlatform(),
|
||||
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -853,3 +917,22 @@ class FakePub extends Fake implements Pub {
|
|||
PubOutputMode outputMode = PubOutputMode.all,
|
||||
}) async { }
|
||||
}
|
||||
|
||||
class _TestDeviceManager extends DeviceManager {
|
||||
_TestDeviceManager({required super.logger});
|
||||
List<Device> devices = <Device>[];
|
||||
|
||||
@override
|
||||
List<DeviceDiscovery> get deviceDiscoverers {
|
||||
final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery();
|
||||
devices.forEach(discoverer.addDevice);
|
||||
return <DeviceDiscovery>[discoverer];
|
||||
}
|
||||
}
|
||||
|
||||
class _TestRunCommandThatOnlyValidates extends RunCommand {
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
return FlutterCommandResult.success();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue