build_aar.dart 5.82 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import '../android/android_builder.dart';
6
import '../android/android_sdk.dart';
7
import '../android/gradle_utils.dart';
8
import '../base/common.dart';
9
import '../base/file_system.dart';
10 11
import '../base/os.dart';
import '../build_info.dart';
12
import '../cache.dart';
13
import '../project.dart';
14
import '../reporting/reporting.dart';
15
import '../runner/flutter_command.dart' show FlutterCommandResult;
16 17 18
import 'build.dart';

class BuildAarCommand extends BuildSubCommand {
19
  BuildAarCommand({
20
    required super.logger,
21 22 23 24 25 26
    required AndroidSdk? androidSdk,
    required FileSystem fileSystem,
    required bool verboseHelp,
  }): _androidSdk = androidSdk,
      _fileSystem = fileSystem,
      super(verboseHelp: verboseHelp) {
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
    argParser
      ..addFlag(
        'debug',
        defaultsTo: true,
        help: 'Build a debug version of the current project.',
      )
      ..addFlag(
        'profile',
        defaultsTo: true,
        help: 'Build a version of the current project specialized for performance profiling.',
      )
      ..addFlag(
        'release',
        defaultsTo: true,
        help: 'Build a release version of the current project.',
      );
43
    addTreeShakeIconsFlag();
44
    usesFlavorOption();
45
    usesBuildNumberOption();
46
    usesOutputDir();
47
    usesPubOption();
48 49
    addSplitDebugInfoOption();
    addDartObfuscationOption();
50
    usesDartDefineOption();
51
    usesExtraDartFlagOptions(verboseHelp: verboseHelp);
52
    usesTrackWidgetCreation(verboseHelp: false);
53
    addNullSafetyModeOptions(hide: !verboseHelp);
54
    addEnableExperimentation(hide: !verboseHelp);
55
    addAndroidSpecificBuildOptions(hide: !verboseHelp);
56
    argParser
57
      .addMultiOption(
58
        'target-platform',
59
        defaultsTo: <String>['android-arm', 'android-arm64', 'android-x64'],
60 61 62 63
        allowed: <String>['android-arm', 'android-arm64', 'android-x86', 'android-x64'],
        help: 'The target platform for which the project is compiled.',
      );
  }
64 65
  final AndroidSdk? _androidSdk;
  final FileSystem _fileSystem;
66 67 68 69

  @override
  final String name = 'aar';

70 71 72
  @override
  bool get reportNullSafety => false;

73 74 75 76 77
  @override
  Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
    DevelopmentArtifact.androidGenSnapshot,
  };

78
  @override
79
  Future<CustomDimensions> get usageValues async {
xster's avatar
xster committed
80
    final FlutterProject flutterProject = _getProject();
81 82

    String projectType;
xster's avatar
xster committed
83
    if (flutterProject.manifest.isModule) {
84
      projectType = 'module';
xster's avatar
xster committed
85
    } else if (flutterProject.manifest.isPlugin) {
86
      projectType = 'plugin';
87
    } else {
88
      projectType = 'app';
89
    }
90 91 92 93 94

    return CustomDimensions(
      commandBuildAarProjectType: projectType,
      commandBuildAarTargetPlatform: stringsArg('target-platform').join(','),
    );
95 96 97 98
  }

  @override
  final String description = 'Build a repository containing an AAR and a POM file.\n\n'
99 100
      'By default, AARs are built for `release`, `debug` and `profile`.\n'
      'The POM file is used to include the dependencies that the AAR was compiled against.\n'
101 102
      'To learn more about how to use these artifacts, see: https://flutter.dev/go/build-aar\n'
      'This command assumes that the entrypoint is "lib/main.dart". '
103
      'This cannot currently be configured.';
104 105 106

  @override
  Future<FlutterCommandResult> runCommand() async {
107
    if (_androidSdk == null) {
108 109
      exitWithNoSdkMessage();
    }
110
    final Set<AndroidBuildInfo> androidBuildInfo = <AndroidBuildInfo>{};
111 112 113 114

    final Iterable<AndroidArch> targetArchitectures =
        stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName);

115
    final String? buildNumberArg = stringArg('build-number');
116
    final String buildNumber = argParser.options.containsKey('build-number')
117 118 119
      && buildNumberArg != null
      && buildNumberArg.isNotEmpty
      ? buildNumberArg
120
      : '1.0';
121

122
    final File targetFile = _fileSystem.file(_fileSystem.path.join('lib', 'main.dart'));
123
    for (final String buildMode in const <String>['debug', 'profile', 'release']) {
124
      if (boolArg(buildMode)) {
125 126
        androidBuildInfo.add(
          AndroidBuildInfo(
127
            await getBuildInfo(
128
              forcedBuildMode: BuildMode.fromCliName(buildMode),
129 130
              forcedTargetFile: targetFile,
            ),
131 132 133
            targetArchs: targetArchitectures,
          )
        );
134 135 136 137 138
      }
    }
    if (androidBuildInfo.isEmpty) {
      throwToolExit('Please specify a build mode and try again.');
    }
139

140
    displayNullSafetyMode(androidBuildInfo.first.buildInfo);
141
    await androidBuilder?.buildAar(
142
      project: _getProject(),
143
      target: targetFile.path,
144
      androidBuildInfo: androidBuildInfo,
145
      outputDirectoryPath: stringArg('output'),
146
      buildNumber: buildNumber,
147
    );
148
    return FlutterCommandResult.success();
149 150
  }

151
  /// Returns the [FlutterProject] which is determined from the remaining command-line
152 153
  /// argument if any or the current working directory.
  FlutterProject _getProject() {
154 155
    final List<String> remainingArguments = argResults!.rest;
    if (remainingArguments.isEmpty) {
156 157
      return FlutterProject.current();
    }
158
    final File mainFile = _fileSystem.file(remainingArguments.first);
159 160
    final String path;
    if (!mainFile.existsSync()) {
161
      final Directory pathProject = _fileSystem.directory(remainingArguments.first);
162 163 164 165 166 167 168
      if (!pathProject.existsSync()) {
        throwToolExit('${remainingArguments.first} does not exist');
      }
      path = pathProject.path;
    } else {
      path = mainFile.parent.path;
    }
169
    final String? projectRoot = findProjectRoot(_fileSystem, path);
170 171 172
    if (projectRoot == null) {
      throwToolExit('${mainFile.parent.path} is not a valid flutter project');
    }
173
    return FlutterProject.fromDirectory(_fileSystem.directory(projectRoot));
174 175
  }
}