Add android analyzer commands for applinks (#131009)
Since applink validation tool is going to be a static tool, It won't have access to vmservices. [flutter.dev/go/static-tooling-in-devtools](http://flutter.dev/go/static-tooling-in-devtools) I remove the vm services and also update the deeplink task to also include path pattern and custom scheme http://go/android-applink-apis (internal only)
This commit is contained in:
parent
6fd3387977
commit
4930613999
@ -16,6 +16,7 @@ import '../runner/flutter_command.dart';
|
||||
import 'analyze_base.dart';
|
||||
import 'analyze_continuously.dart';
|
||||
import 'analyze_once.dart';
|
||||
import 'android_analyze.dart';
|
||||
import 'validate_project.dart';
|
||||
|
||||
class AnalyzeCommand extends FlutterCommand {
|
||||
@ -99,6 +100,37 @@ class AnalyzeCommand extends FlutterCommand {
|
||||
argParser.addFlag('fatal-warnings',
|
||||
help: 'Treat warning level issues as fatal.',
|
||||
defaultsTo: true);
|
||||
|
||||
argParser.addFlag('android',
|
||||
negatable: false,
|
||||
help: 'Analyze Android sub-project. Used by internal tools only.',
|
||||
hide: !verboseHelp,
|
||||
);
|
||||
|
||||
if (verboseHelp) {
|
||||
argParser.addSeparator('Usage: flutter analyze --android [arguments]');
|
||||
}
|
||||
|
||||
argParser.addFlag('list-build-variants',
|
||||
negatable: false,
|
||||
help: 'Print out a list of available build variants for the '
|
||||
'Android sub-project.',
|
||||
hide: !verboseHelp,
|
||||
);
|
||||
|
||||
argParser.addFlag('output-app-link-settings',
|
||||
negatable: false,
|
||||
help: 'Output a JSON with Android app link settings into a file. '
|
||||
'The "--build-variant" must also be set.',
|
||||
hide: !verboseHelp,
|
||||
);
|
||||
|
||||
argParser.addOption('build-variant',
|
||||
help: 'Sets the Android build variant to be analyzed.',
|
||||
valueHelp: 'use "flutter analyze --android --list-build-variants" to get '
|
||||
'all available build variants',
|
||||
hide: !verboseHelp,
|
||||
);
|
||||
}
|
||||
|
||||
/// The working directory for testing analysis using dartanalyzer.
|
||||
@ -142,12 +174,51 @@ class AnalyzeCommand extends FlutterCommand {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't run pub if asking for android analysis.
|
||||
if (boolArg('android')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.shouldRunPub;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
if (boolArg('suggestions')) {
|
||||
if (boolArg('android')) {
|
||||
final AndroidAnalyzeOption option;
|
||||
final String? buildVariant;
|
||||
if (argResults!['list-build-variants'] as bool && argResults!['output-app-link-settings'] as bool) {
|
||||
throwToolExit('Only one of "--list-build-variants" or "--output-app-link-settings" can be provided');
|
||||
}
|
||||
if (argResults!['list-build-variants'] as bool) {
|
||||
option = AndroidAnalyzeOption.listBuildVariant;
|
||||
buildVariant = null;
|
||||
} else if (argResults!['output-app-link-settings'] as bool) {
|
||||
option = AndroidAnalyzeOption.outputAppLinkSettings;
|
||||
buildVariant = argResults!['build-variant'] as String?;
|
||||
if (buildVariant == null) {
|
||||
throwToolExit('"--build-variant" must be provided');
|
||||
}
|
||||
} else {
|
||||
throwToolExit('No argument is provided to analyze. Use -h to see available commands.');
|
||||
}
|
||||
final Set<String> items = findDirectories(argResults!, _fileSystem);
|
||||
final String directoryPath;
|
||||
if (items.isEmpty) { // user did not specify any path
|
||||
directoryPath = _fileSystem.currentDirectory.path;
|
||||
} else if (items.length > 1) { // if the user sends more than one path
|
||||
throwToolExit('The Android analyze can process only one directory path');
|
||||
} else {
|
||||
directoryPath = items.first;
|
||||
}
|
||||
await AndroidAnalyze(
|
||||
fileSystem: _fileSystem,
|
||||
option: option,
|
||||
userPath: directoryPath,
|
||||
buildVariant: buildVariant,
|
||||
logger: _logger,
|
||||
).analyze();
|
||||
} else if (boolArg('suggestions')) {
|
||||
final String directoryPath;
|
||||
if (boolArg('watch')) {
|
||||
throwToolExit('flag --watch is not compatible with --suggestions');
|
||||
|
56
packages/flutter_tools/lib/src/commands/android_analyze.dart
Normal file
56
packages/flutter_tools/lib/src/commands/android_analyze.dart
Normal file
@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import '../base/file_system.dart';
|
||||
import '../base/logger.dart';
|
||||
import '../convert.dart';
|
||||
import '../project.dart';
|
||||
|
||||
/// The type of analysis to perform.
|
||||
enum AndroidAnalyzeOption {
|
||||
/// Prints out available build variants of the Android sub-project.
|
||||
///
|
||||
/// An example output:
|
||||
/// ["debug", "profile", "release"]
|
||||
listBuildVariant,
|
||||
|
||||
/// Outputs app link settings of the Android sub-project into a file.
|
||||
///
|
||||
/// The file path will be printed after the command is run successfully.
|
||||
outputAppLinkSettings,
|
||||
}
|
||||
|
||||
/// Analyze the Android sub-project of a Flutter project.
|
||||
///
|
||||
/// The [userPath] must be point to a flutter project.
|
||||
class AndroidAnalyze {
|
||||
AndroidAnalyze({
|
||||
required this.fileSystem,
|
||||
required this.option,
|
||||
required this.userPath,
|
||||
this.buildVariant,
|
||||
required this.logger,
|
||||
}) : assert(option == AndroidAnalyzeOption.listBuildVariant || buildVariant != null);
|
||||
|
||||
final FileSystem fileSystem;
|
||||
final AndroidAnalyzeOption option;
|
||||
final String? buildVariant;
|
||||
final String userPath;
|
||||
final Logger logger;
|
||||
|
||||
Future<void> analyze() async {
|
||||
final FlutterProject project = FlutterProject.fromDirectory(fileSystem.directory(userPath));
|
||||
switch (option) {
|
||||
case AndroidAnalyzeOption.listBuildVariant:
|
||||
logger.printStatus(jsonEncode(await project.android.getBuildVariants()));
|
||||
case AndroidAnalyzeOption.outputAppLinkSettings:
|
||||
assert(buildVariant != null);
|
||||
await project.android.outputsAppLinkSettings(variant: buildVariant!);
|
||||
final String filePath = fileSystem.path.join(project.directory.path, 'build', 'app', 'app-link-settings-$buildVariant.json`');
|
||||
logger.printStatus('result saved in $filePath');
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
// 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.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/android/android_builder.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/terminal.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/analyze.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/project_validator.dart';
|
||||
import 'package:test/fake.dart';
|
||||
|
||||
import '../../src/context.dart';
|
||||
import '../../src/test_flutter_command_runner.dart';
|
||||
|
||||
void main() {
|
||||
|
||||
group('Android analyze command', () {
|
||||
late FileSystem fileSystem;
|
||||
late Platform platform;
|
||||
late BufferLogger logger;
|
||||
late FakeProcessManager processManager;
|
||||
late Terminal terminal;
|
||||
late AnalyzeCommand command;
|
||||
late CommandRunner<void> runner;
|
||||
late Directory tempDir;
|
||||
late FakeAndroidBuilder builder;
|
||||
|
||||
setUpAll(() {
|
||||
Cache.disableLocking();
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
fileSystem = MemoryFileSystem.test();
|
||||
platform = FakePlatform();
|
||||
logger = BufferLogger.test();
|
||||
processManager = FakeProcessManager.empty();
|
||||
terminal = Terminal.test();
|
||||
command = AnalyzeCommand(
|
||||
artifacts: Artifacts.test(),
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
platform: platform,
|
||||
processManager: processManager,
|
||||
terminal: terminal,
|
||||
allProjectValidators: <ProjectValidator>[],
|
||||
suppressAnalytics: true,
|
||||
);
|
||||
runner = createTestCommandRunner(command);
|
||||
tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
|
||||
tempDir.childDirectory('android').createSync();
|
||||
|
||||
// Setup repo roots
|
||||
const String homePath = '/home/user/flutter';
|
||||
Cache.flutterRoot = homePath;
|
||||
for (final String dir in <String>['dev', 'examples', 'packages']) {
|
||||
fileSystem.directory(homePath).childDirectory(dir).createSync(recursive: true);
|
||||
}
|
||||
builder = FakeAndroidBuilder();
|
||||
|
||||
});
|
||||
|
||||
testUsingContext('can list build variants', () async {
|
||||
builder.variants = <String>['debug', 'release'];
|
||||
await runner.run(<String>['analyze', '--android', '--list-build-variants', tempDir.path]);
|
||||
expect(logger.statusText, contains('["debug","release"]'));
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidBuilder: () => builder,
|
||||
});
|
||||
|
||||
testUsingContext('throw if provide multiple path', () async {
|
||||
final Directory anotherTempDir = fileSystem.systemTempDirectory.createTempSync('another');
|
||||
await expectLater(
|
||||
runner.run(<String>['analyze', '--android', '--list-build-variants', tempDir.path, anotherTempDir.path]),
|
||||
throwsA(
|
||||
isA<Exception>().having(
|
||||
(Exception e) => e.toString(),
|
||||
'description',
|
||||
contains('The Android analyze can process only one directory path'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testUsingContext('can output app link settings', () async {
|
||||
const String buildVariant = 'release';
|
||||
await runner.run(<String>['analyze', '--android', '--output-app-link-settings', '--build-variant=$buildVariant', tempDir.path]);
|
||||
expect(builder.outputVariant, buildVariant);
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidBuilder: () => builder,
|
||||
});
|
||||
|
||||
testUsingContext('output app link settings throws if no build variant', () async {
|
||||
await expectLater(
|
||||
runner.run(<String>['analyze', '--android', '--output-app-link-settings', tempDir.path]),
|
||||
throwsA(
|
||||
isA<Exception>().having(
|
||||
(Exception e) => e.toString(),
|
||||
'description',
|
||||
contains('"--build-variant" must be provided'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FakeAndroidBuilder extends Fake implements AndroidBuilder {
|
||||
List<String> variants = const <String>[];
|
||||
String? outputVariant;
|
||||
|
||||
@override
|
||||
Future<List<String>> getBuildVariants({required FlutterProject project}) async {
|
||||
return variants;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> outputsAppLinkSettings(String buildVariant, {required FlutterProject project}) async {
|
||||
outputVariant = buildVariant;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user