first commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
name: Dart
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Fetch Flutter SDK
|
||||
run: |
|
||||
git clone --depth=1 https://github.com/flutter/flutter.git
|
||||
cd flutter
|
||||
git fetch --depth=1 https://github.com/flutter/flutter.git `cat ../bin/internal/flutter.version`
|
||||
git checkout FETCH_HEAD
|
||||
- name: Install pub dependencies
|
||||
run: flutter/bin/flutter pub get
|
||||
- name: Verify formatting
|
||||
run: flutter/bin/dart format --output=none --set-exit-if-changed lib
|
||||
- name: Analyze project source
|
||||
run: flutter/bin/dart analyze --fatal-infos lib
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.lock
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# Visual Studio Code related
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
.vscode/
|
||||
|
||||
# Flutter repo-specific
|
||||
/bin/cache/
|
||||
/bin/mingit/
|
||||
/dev/benchmarks/mega_gallery/
|
||||
/dev/bots/.recipe_deps
|
||||
/dev/bots/android_tools/
|
||||
/dev/docs/doc/
|
||||
/dev/docs/flutter.docs.zip
|
||||
/dev/docs/lib/
|
||||
/dev/docs/pubspec.yaml
|
||||
/dev/integration_tests/**/xcuserdata
|
||||
/dev/integration_tests/**/Pods
|
||||
/packages/flutter/coverage/
|
||||
version
|
||||
|
||||
# packages file containing multi-root paths
|
||||
.packages.generated
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
build/
|
||||
flutter_*.png
|
||||
linked_*.ds
|
||||
unlinked.ds
|
||||
unlinked_spec.ds
|
||||
|
||||
# Android related
|
||||
**/android/**/gradle-wrapper.jar
|
||||
**/android/.gradle
|
||||
**/android/captures/
|
||||
**/android/gradlew
|
||||
**/android/gradlew.bat
|
||||
**/android/local.properties
|
||||
**/android/**/GeneratedPluginRegistrant.java
|
||||
**/android/key.properties
|
||||
*.jks
|
||||
|
||||
# iOS/XCode related
|
||||
**/ios/**/*.mode1v3
|
||||
**/ios/**/*.mode2v3
|
||||
**/ios/**/*.moved-aside
|
||||
**/ios/**/*.pbxuser
|
||||
**/ios/**/*.perspectivev3
|
||||
**/ios/**/*sync/
|
||||
**/ios/**/.sconsign.dblite
|
||||
**/ios/**/.tags*
|
||||
**/ios/**/.vagrant/
|
||||
**/ios/**/DerivedData/
|
||||
**/ios/**/Icon?
|
||||
**/ios/**/Pods/
|
||||
**/ios/**/.symlinks/
|
||||
**/ios/**/profile
|
||||
**/ios/**/xcuserdata
|
||||
**/ios/.generated/
|
||||
**/ios/Flutter/App.framework
|
||||
**/ios/Flutter/Flutter.framework
|
||||
**/ios/Flutter/Flutter.podspec
|
||||
**/ios/Flutter/Generated.xcconfig
|
||||
**/ios/Flutter/app.flx
|
||||
**/ios/Flutter/app.zip
|
||||
**/ios/Flutter/flutter_assets/
|
||||
**/ios/Flutter/flutter_export_environment.sh
|
||||
**/ios/ServiceDefinitions.json
|
||||
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# macOS
|
||||
**/macos/Flutter/GeneratedPluginRegistrant.swift
|
||||
**/macos/Flutter/Flutter-Debug.xcconfig
|
||||
**/macos/Flutter/Flutter-Release.xcconfig
|
||||
**/macos/Flutter/Flutter-Profile.xcconfig
|
||||
|
||||
# Coverage
|
||||
coverage/
|
||||
|
||||
# Symbols
|
||||
app.*.symbols
|
||||
|
||||
# Exceptions to above rules.
|
||||
!**/ios/**/default.mode1v3
|
||||
!**/ios/**/default.mode2v3
|
||||
!**/ios/**/default.pbxuser
|
||||
!**/ios/**/default.perspectivev3
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
!/dev/ci/**/Gemfile.lock
|
||||
@@ -0,0 +1,7 @@
|
||||
# Below is a list of people and organizations that have contributed
|
||||
# to sony/flutter-elinux from after forking flutter-tizen. Names should
|
||||
# be added to the list like so:
|
||||
#
|
||||
# Name/Organization <email address>
|
||||
|
||||
Sony Group Corporation
|
||||
@@ -0,0 +1,2 @@
|
||||
# Contributing to flutter-elinux
|
||||
Welcome to this project. We welcome all your contribution and feedback. If you've never submitted code before, you must add your (or your organization's) name and contact info to the [AUTHORS](./AUTHORS) file.
|
||||
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2021 Sony Group Corporation. All rights reserved.
|
||||
Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
Copyright (c) 2014 The Flutter Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the names of the copyright holders nor the names of the
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Flutter for Embedded Linux (eLinux)
|
||||
This software is a **non-official** extension to the [Flutter SDK](https://github.com/flutter/flutter) to build Flutter apps for Embedded Linux devices.
|
||||
|
||||
## Documentation
|
||||
See https://github.com/sony/flutter-elinux/wiki
|
||||
|
||||
## Contributing
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## Related projects/repos
|
||||
### Flutter plugins for eLinux
|
||||
- [flutter-elinux-plugins](https://github.com/sony/flutter-elinux-plugins)
|
||||
|
||||
### Flutter embedder (engine) for eLinux
|
||||
- [flutter-embedded-linux](https://github.com/sony/flutter-embedded-linux)
|
||||
|
||||
### Yocto recipes for Flutter embedder for eLinux
|
||||
- [meta-flutter](https://github.com/sony/meta-flutter)
|
||||
|
||||
## Base software
|
||||
This software was created based on the [flutter-tizen](https://github.com/flutter-tizen/flutter-tizen) (branched from [this version](https://github.com/flutter-tizen/flutter-tizen/commit/ed128233c0bce33c77dd0df69afa59f0888d2d00)). Special thanks to the flutter-tizen team.
|
||||
@@ -0,0 +1,20 @@
|
||||
include: flutter/packages/flutter_tools/analysis_options.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- "flutter/bin/cache/**"
|
||||
- "flutter/dev/**"
|
||||
- "flutter/examples/**"
|
||||
- "flutter/packages/flutter/**"
|
||||
- "flutter/packages/flutter_driver/**"
|
||||
- "flutter/packages/flutter_goldens/**"
|
||||
- "flutter/packages/flutter_goldens_client/**"
|
||||
- "flutter/packages/flutter_localizations/**"
|
||||
- "flutter/packages/flutter_test/**"
|
||||
- "flutter/packages/flutter_web_plugins/**"
|
||||
- "flutter/packages/fuchsia_remote_debug_protocol/**"
|
||||
- "flutter/packages/integration_test/**"
|
||||
|
||||
linter:
|
||||
rules:
|
||||
implementation_imports: false
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
# Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
# 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.
|
||||
|
||||
set -e
|
||||
|
||||
# Needed because if it is set, cd may print the path it changed to.
|
||||
unset CDPATH
|
||||
|
||||
# On Mac OS, readlink -f doesn't work, so follow_links traverses the path one
|
||||
# link at a time, and then cds into the link destination and find out where it
|
||||
# ends up.
|
||||
#
|
||||
# The returned filesystem path must be a format usable by Dart's URI parser,
|
||||
# since the Dart command line tool treats its argument as a file URI, not a
|
||||
# filename. For instance, multiple consecutive slashes should be reduced to a
|
||||
# single slash, since double-slashes indicate a URI "authority", and these are
|
||||
# supposed to be filenames. There is an edge case where this will return
|
||||
# multiple slashes: when the input resolves to the root directory. However, if
|
||||
# that were the case, we wouldn't be running this shell, so we don't do anything
|
||||
# about it.
|
||||
#
|
||||
# The function is enclosed in a subshell to avoid changing the working directory
|
||||
# of the caller.
|
||||
function follow_links() (
|
||||
cd -P "$(dirname -- "$1")"
|
||||
file="$PWD/$(basename -- "$1")"
|
||||
while [[ -h "$file" ]]; do
|
||||
cd -P "$(dirname -- "$file")"
|
||||
file="$(readlink -- "$file")"
|
||||
cd -P "$(dirname -- "$file")"
|
||||
file="$PWD/$(basename -- "$file")"
|
||||
done
|
||||
echo "$file"
|
||||
)
|
||||
|
||||
PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")"
|
||||
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
|
||||
OS="$(uname -s)"
|
||||
|
||||
# Allow only 64-bit host platform.
|
||||
if [ "$(getconf LONG_BIT)" != "64" ]; then
|
||||
echo "$(basename $PROG_NAME) only supports 64 bit platforms."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If we're on Windows, invoke the batch script instead to get proper locking.
|
||||
if [[ $OS =~ MINGW.* || $OS =~ CYGWIN.* ]]; then
|
||||
echo "Window platforms are not supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$BIN_DIR/internal/shared.sh"
|
||||
|
||||
# Clone or update the flutter repo.
|
||||
update_flutter
|
||||
|
||||
# Upgrade flutter-elinux if needed.
|
||||
update_flutter_elinux
|
||||
|
||||
# Run the snapshot.
|
||||
exec_snapshot "$@"
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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_elinux/executable.dart' as executable;
|
||||
|
||||
void main(List<String> args) {
|
||||
executable.main(args);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
9d517f475ba1282b619477bde8e708d6a34287cf
|
||||
@@ -0,0 +1 @@
|
||||
615957513eb43b128a16048ab5aa2daaba1656cd
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
# Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
# ---------------------------------- NOTE ---------------------------------- #
|
||||
#
|
||||
# Please keep the logic in this file consistent with the logic in the
|
||||
# `shared.bat` script in the same directory to ensure that Flutter continue
|
||||
# to work across all platforms!
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
set -e
|
||||
|
||||
# Needed because if it is set, cd may print the path it changed to.
|
||||
unset CDPATH
|
||||
|
||||
FLUTTER_REPO="https://github.com/flutter/flutter.git"
|
||||
|
||||
if [[ -z "$BIN_DIR" ]]; then
|
||||
echo "BIN_DIR is not set."
|
||||
exit 1
|
||||
fi
|
||||
ROOT_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
|
||||
FLUTTER_DIR="$ROOT_DIR/flutter"
|
||||
SNAPSHOT_PATH="$ROOT_DIR/bin/cache/flutter-elinux.snapshot"
|
||||
|
||||
FLUTTER_EXE="$FLUTTER_DIR/bin/flutter"
|
||||
DART_EXE="$FLUTTER_DIR/bin/cache/dart-sdk/bin/dart"
|
||||
|
||||
function update_flutter() {
|
||||
if [[ -e "$FLUTTER_DIR" && ! -d "$FLUTTER_DIR/.git" ]]; then
|
||||
echo "$FLUTTER_DIR is not a git directory. Remove it and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clone flutter repo if not installed.
|
||||
if [[ ! -d "$FLUTTER_DIR" ]]; then
|
||||
git clone --depth=1 "$FLUTTER_REPO" "$FLUTTER_DIR"
|
||||
fi
|
||||
|
||||
# GIT_DIR and GIT_WORK_TREE are used in the git command.
|
||||
export GIT_DIR="$FLUTTER_DIR/.git"
|
||||
export GIT_WORK_TREE="$FLUTTER_DIR"
|
||||
|
||||
# Update flutter repo if needed.
|
||||
local version="$(cat "$ROOT_DIR/bin/internal/flutter.version")"
|
||||
if [[ "$version" != "$(git rev-parse HEAD)" ]]; then
|
||||
git reset --hard
|
||||
git clean -xdf
|
||||
git fetch --depth=1 "$FLUTTER_REPO" "$version"
|
||||
git checkout FETCH_HEAD
|
||||
|
||||
# Invalidate the cache.
|
||||
rm -fr "$ROOT_DIR/bin/cache"
|
||||
fi
|
||||
|
||||
if [[ "$version" != "$(git rev-parse HEAD)" ]]; then
|
||||
echo "Something went wrong when upgrading the Flutter SDK." \
|
||||
"Remove directory $FLUTTER_DIR and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unset GIT_DIR
|
||||
unset GIT_WORK_TREE
|
||||
|
||||
# Invalidate the flutter cache.
|
||||
local stamp_path="$FLUTTER_DIR/bin/cache/flutter_tools.stamp"
|
||||
if [[ ! -f "$stamp_path" || "$version" != "$(cat "$stamp_path")" ]]; then
|
||||
"$FLUTTER_EXE" --version
|
||||
fi
|
||||
}
|
||||
|
||||
function update_flutter_elinux() {
|
||||
mkdir -p "$ROOT_DIR/bin/cache"
|
||||
|
||||
local revision="$(git --git-dir="$ROOT_DIR/.git" rev-parse HEAD)"
|
||||
local stamp_path="$ROOT_DIR/bin/cache/flutter-elinux.stamp"
|
||||
|
||||
if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$stamp_path" || "$revision" != "$(cat "$stamp_path")"
|
||||
|| "$ROOT_DIR/pubspec.yaml" -nt "$ROOT_DIR/pubspec.lock" ]]; then
|
||||
echo "Running pub upgrade..."
|
||||
(cd "$ROOT_DIR" && "$FLUTTER_EXE" pub upgrade) || {
|
||||
>&2 echo "Error: Unable to 'pub upgrade' flutter-elinux."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Compiling flutter-elinux..."
|
||||
"$DART_EXE" --disable-dart-dev --no-enable-mirrors \
|
||||
--snapshot="$SNAPSHOT_PATH" --packages="$ROOT_DIR/.packages" \
|
||||
"$ROOT_DIR/bin/flutter_elinux.dart"
|
||||
|
||||
echo "$revision" > "$stamp_path"
|
||||
fi
|
||||
}
|
||||
|
||||
function exec_snapshot() {
|
||||
"$DART_EXE" --disable-dart-dev --packages="$ROOT_DIR/.packages" "$SNAPSHOT_PATH" "$@"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/commands/analyze.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxAnalyzeCommand extends AnalyzeCommand with ELinuxExtension {
|
||||
ELinuxAnalyzeCommand({bool verboseHelp = false})
|
||||
: super(
|
||||
verboseHelp: verboseHelp,
|
||||
fileSystem: globals.fs,
|
||||
platform: globals.platform,
|
||||
processManager: globals.processManager,
|
||||
logger: globals.logger,
|
||||
terminal: globals.terminal,
|
||||
artifacts: globals.artifacts,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/commands/attach.dart';
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxAttachCommand extends AttachCommand with ELinuxExtension {
|
||||
ELinuxAttachCommand({bool verboseHelp = false})
|
||||
: super(verboseHelp: verboseHelp);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/android/build_validation.dart' as android;
|
||||
import 'package:flutter_tools/src/base/analyze_size.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/commands/build.dart';
|
||||
import 'package:flutter_tools/src/commands/build_apk.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
|
||||
import '../elinux_builder.dart';
|
||||
import '../elinux_cache.dart';
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxBuildCommand extends BuildCommand {
|
||||
ELinuxBuildCommand({bool verboseHelp = false})
|
||||
: super(verboseHelp: verboseHelp) {
|
||||
addSubcommand(BuildPackageCommand(verboseHelp: verboseHelp));
|
||||
}
|
||||
}
|
||||
|
||||
class BuildPackageCommand extends BuildSubCommand with ELinuxExtension {
|
||||
/// See: [BuildApkCommand] in `build_apk.dart`
|
||||
BuildPackageCommand({bool verboseHelp = false}) {
|
||||
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
||||
usesBuildNameOption();
|
||||
argParser.addOption(
|
||||
'target-arch',
|
||||
defaultsTo: _getCurrentHostPlatformArchName(),
|
||||
allowed: <String>['x64', 'arm64'],
|
||||
help: 'Target architecture for which the the app is compiled',
|
||||
);
|
||||
argParser.addOption(
|
||||
'target-backend-type',
|
||||
defaultsTo: 'wayland',
|
||||
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
|
||||
help: 'Target backend type that the app will run on devices.',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
final String name = 'elinux';
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
|
||||
<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.androidGenSnapshot,
|
||||
ELinuxDevelopmentArtifact.elinux,
|
||||
};
|
||||
|
||||
@override
|
||||
final String description = 'Build an eLinux package from your app.';
|
||||
|
||||
/// See: [android.validateBuild] in `build_validation.dart`
|
||||
void validateBuild(ELinuxBuildInfo eLinuxBuildInfo) {
|
||||
if (eLinuxBuildInfo.buildInfo.mode.isPrecompiled &&
|
||||
eLinuxBuildInfo.targetArch == 'x86') {
|
||||
throwToolExit('x86 ABI does not support AOT compilation.');
|
||||
}
|
||||
}
|
||||
|
||||
/// See: [BuildApkCommand.runCommand] in `build_apk.dart`
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final BuildInfo buildInfo = await getBuildInfo();
|
||||
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
|
||||
buildInfo,
|
||||
targetArch: stringArg('target-arch'),
|
||||
targetBackendType: stringArg('target-backend-type'),
|
||||
);
|
||||
validateBuild(eLinuxBuildInfo);
|
||||
displayNullSafetyMode(buildInfo);
|
||||
|
||||
await ELinuxBuilder.buildBundle(
|
||||
project: FlutterProject.current(),
|
||||
targetFile: targetFile,
|
||||
eLinuxBuildInfo: eLinuxBuildInfo,
|
||||
sizeAnalyzer: SizeAnalyzer(
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
flutterUsage: globals.flutterUsage,
|
||||
),
|
||||
);
|
||||
return FlutterCommandResult.success();
|
||||
}
|
||||
|
||||
String _getCurrentHostPlatformArchName() {
|
||||
final HostPlatform hostPlatform = getCurrentHostPlatform();
|
||||
return getNameForHostPlatformArch(hostPlatform);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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:file/file.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/commands/clean.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import '../elinux_cmake_project.dart';
|
||||
|
||||
class ELinuxCleanCommand extends CleanCommand {
|
||||
ELinuxCleanCommand({bool verbose = false}) : super(verbose: verbose);
|
||||
|
||||
/// See: [CleanCommand.runCommand] in `clean.dart`
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final FlutterProject flutterProject = FlutterProject.current();
|
||||
_cleanELinuxProject(ELinuxProject.fromFlutter(flutterProject));
|
||||
|
||||
return super.runCommand();
|
||||
}
|
||||
|
||||
void _cleanELinuxProject(ELinuxProject project) {
|
||||
if (!project.existsSync()) {
|
||||
return;
|
||||
}
|
||||
_deleteFile(project.ephemeralDirectory);
|
||||
}
|
||||
|
||||
/// Source: [CleanCommand.deleteFile] in `clean.dart` (simplified)
|
||||
void _deleteFile(FileSystemEntity file) {
|
||||
if (!file.existsSync()) {
|
||||
return;
|
||||
}
|
||||
final String path = relative(file.path);
|
||||
final Status status = globals.logger.startProgress(
|
||||
'Deleting $path...',
|
||||
);
|
||||
try {
|
||||
file.deleteSync(recursive: true);
|
||||
} on FileSystemException catch (error) {
|
||||
globals.printError('Failed to remove $path: $error');
|
||||
} finally {
|
||||
status?.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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:file/file.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/terminal.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/create.dart';
|
||||
import 'package:flutter_tools/src/flutter_project_metadata.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:flutter_tools/src/template.dart';
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxCreateCommand extends CreateCommand {
|
||||
ELinuxCreateCommand({bool verboseHelp = false})
|
||||
: super(verboseHelp: verboseHelp) {
|
||||
argParser.addOption(
|
||||
'target-backend-type',
|
||||
defaultsTo: 'wayland',
|
||||
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
|
||||
help: 'Target backend type that the app will run on devices.',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void printUsage() {
|
||||
super.printUsage();
|
||||
// TODO(swift-kim): I couldn't find a proper way to override the --platforms
|
||||
// option without copying the entire class. This message is a workaround.
|
||||
print(
|
||||
'You don\'t have to specify "elinux" as a target platform with '
|
||||
'"--platforms" option. It is automatically added by default.',
|
||||
);
|
||||
}
|
||||
|
||||
/// See:
|
||||
/// - [CreateCommand.runCommand] in `create.dart`
|
||||
/// - [CreateCommand._getProjectType] in `create.dart` (generatePlugin)
|
||||
Future<FlutterCommandResult> runInternal() async {
|
||||
final FlutterCommandResult result = await super.runCommand();
|
||||
if (result != FlutterCommandResult.success() || argResults.rest.isEmpty) {
|
||||
return result;
|
||||
}
|
||||
|
||||
final bool generatePlugin = argResults['template'] != null
|
||||
? stringArg('template') ==
|
||||
flutterProjectTypeToString(FlutterProjectType.plugin)
|
||||
: determineTemplateType() == FlutterProjectType.plugin;
|
||||
if (generatePlugin) {
|
||||
// Assume that pubspec.yaml uses the multi-platforms plugin format if the
|
||||
// file already exists.
|
||||
// TODO(swift-kim): Skip this message if elinux already exists in pubspec.
|
||||
globals.printStatus(
|
||||
'The `pubspec.yaml` under the project directory must be updated to support ELinux.\n'
|
||||
'Add below lines to under the `platforms:` key.',
|
||||
emphasis: true,
|
||||
color: TerminalColor.yellow,
|
||||
);
|
||||
final Map<String, dynamic> templateContext = createTemplateContext(
|
||||
organization: '',
|
||||
projectName: projectName,
|
||||
flutterRoot: '',
|
||||
);
|
||||
globals.printStatus(
|
||||
'\nelinux:\n'
|
||||
' pluginClass: ${templateContext['pluginClass'] as String}\n'
|
||||
' fileName: ${projectName}_plugin.h',
|
||||
emphasis: true,
|
||||
color: TerminalColor.blue,
|
||||
);
|
||||
globals.printStatus('');
|
||||
}
|
||||
|
||||
if (boolArg('pub')) {
|
||||
final FlutterProject project = FlutterProject.fromDirectory(projectDir);
|
||||
await ensureReadyForELinuxTooling(project);
|
||||
if (project.hasExampleApp) {
|
||||
await ensureReadyForELinuxTooling(project.example);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// See: [Template.render] in `template.dart`
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
// The template directory that the flutter tools search for available
|
||||
// templates cannot be overriden because the implementation is private.
|
||||
// So we have to copy eLinux templates into the directory manually.
|
||||
final Directory eLinuxTemplates = globals.fs
|
||||
.directory(Cache.flutterRoot)
|
||||
.parent
|
||||
.childDirectory('templates');
|
||||
if (!eLinuxTemplates.existsSync()) {
|
||||
throwToolExit('Could not locate eLinux templates.');
|
||||
}
|
||||
final File eLinuxTemplateManifest =
|
||||
eLinuxTemplates.childFile('template_manifest.json');
|
||||
|
||||
final Directory templates = globals.fs
|
||||
.directory(Cache.flutterRoot)
|
||||
.childDirectory('packages')
|
||||
.childDirectory('flutter_tools')
|
||||
.childDirectory('templates');
|
||||
final File templateManifest = templates.childFile('template_manifest.json');
|
||||
|
||||
// This is required due to: https://github.com/flutter/flutter/pull/59706
|
||||
// TODO(swift-kim): Find any better workaround. One option is to override
|
||||
// renderTemplate() but it may result in additional complexity.
|
||||
eLinuxTemplateManifest.copySync(templateManifest.path);
|
||||
|
||||
final String backend = stringArg('target-backend-type');
|
||||
final List<Directory> created = <Directory>[];
|
||||
try {
|
||||
for (final Directory projectType
|
||||
in eLinuxTemplates.listSync().whereType<Directory>()) {
|
||||
final Directory sourceRunnerCommon =
|
||||
projectType.childDirectory('runner');
|
||||
if (!sourceRunnerCommon.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
final Directory sourceFlutter = projectType.childDirectory('flutter');
|
||||
if (!sourceFlutter.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final Directory dest = templates
|
||||
.childDirectory(projectType.basename)
|
||||
.childDirectory('elinux.tmpl');
|
||||
if (dest.existsSync()) {
|
||||
dest.deleteSync(recursive: true);
|
||||
}
|
||||
|
||||
copyDirectory(projectType, dest);
|
||||
copyDirectory(sourceFlutter, dest.childDirectory('flutter'));
|
||||
copyDirectory(sourceRunnerCommon, dest.childDirectory('runner'));
|
||||
if (projectType.basename == 'app') {
|
||||
final Directory sourceVariation =
|
||||
projectType.childDirectory('runner_$backend');
|
||||
if (!sourceVariation.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
copyDirectory(sourceVariation, dest.childDirectory('runner'));
|
||||
}
|
||||
created.add(dest);
|
||||
}
|
||||
return await runInternal();
|
||||
} finally {
|
||||
for (final Directory template in created) {
|
||||
template.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/commands/drive.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxDriveCommand extends DriveCommand with ELinuxExtension {
|
||||
ELinuxDriveCommand({bool verboseHelp = false})
|
||||
: super(
|
||||
verboseHelp: verboseHelp,
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
platform: globals.platform,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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/os.dart';
|
||||
import 'package:flutter_tools/src/commands/packages.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
/// This class was copied from [PackagesCommand] to substitute its
|
||||
/// [PackagesGetCommand] and [PackagesInteractiveGetCommand] subcommands with
|
||||
/// their ELinux equivalents. We may find a better workaround in the future.
|
||||
///
|
||||
/// Source: [PackagesCommand] in `packages.dart`
|
||||
class ELinuxPackagesCommand extends FlutterCommand {
|
||||
ELinuxPackagesCommand() {
|
||||
addSubcommand(ELinuxPackagesGetCommand('get', false));
|
||||
addSubcommand(ELinuxPackagesInteractiveGetCommand('upgrade',
|
||||
'Upgrade the current package\'s dependencies to latest versions.'));
|
||||
addSubcommand(ELinuxPackagesInteractiveGetCommand(
|
||||
'add', 'Add a dependency to pubspec.yaml.'));
|
||||
addSubcommand(ELinuxPackagesInteractiveGetCommand(
|
||||
'remove', 'Removes a dependency from the current package.'));
|
||||
addSubcommand(PackagesTestCommand());
|
||||
addSubcommand(PackagesForwardCommand(
|
||||
'publish', 'Publish the current package to pub.dartlang.org',
|
||||
requiresPubspec: true));
|
||||
addSubcommand(PackagesForwardCommand(
|
||||
'downgrade', 'Downgrade packages in a Flutter project',
|
||||
requiresPubspec: true));
|
||||
addSubcommand(PackagesForwardCommand('deps', 'Print package dependencies',
|
||||
requiresPubspec: true));
|
||||
addSubcommand(PackagesForwardCommand(
|
||||
'run', 'Run an executable from a package',
|
||||
requiresPubspec: true));
|
||||
addSubcommand(
|
||||
PackagesForwardCommand('cache', 'Work with the Pub system cache'));
|
||||
addSubcommand(PackagesForwardCommand('version', 'Print Pub version'));
|
||||
addSubcommand(PackagesForwardCommand(
|
||||
'uploader', 'Manage uploaders for a package on pub.dev'));
|
||||
addSubcommand(PackagesForwardCommand('login', 'Log into pub.dev.'));
|
||||
addSubcommand(PackagesForwardCommand('logout', 'Log out of pub.dev.'));
|
||||
addSubcommand(
|
||||
PackagesForwardCommand('global', 'Work with Pub global packages'));
|
||||
addSubcommand(PackagesForwardCommand(
|
||||
'outdated', 'Analyze dependencies to find which ones can be upgraded',
|
||||
requiresPubspec: true));
|
||||
addSubcommand(PackagesPassthroughCommand());
|
||||
}
|
||||
|
||||
@override
|
||||
final String name = 'pub';
|
||||
|
||||
@override
|
||||
List<String> get aliases => const <String>['packages'];
|
||||
|
||||
@override
|
||||
final String description = 'Commands for managing Flutter packages.';
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async => null;
|
||||
}
|
||||
|
||||
class ELinuxPackagesGetCommand extends PackagesGetCommand
|
||||
with _PostRunPluginInjection {
|
||||
ELinuxPackagesGetCommand(String name, bool upgrade) : super(name, upgrade);
|
||||
}
|
||||
|
||||
class ELinuxPackagesInteractiveGetCommand extends PackagesInteractiveGetCommand
|
||||
with _PostRunPluginInjection {
|
||||
ELinuxPackagesInteractiveGetCommand(String commandName, String description)
|
||||
: super(commandName, description);
|
||||
}
|
||||
|
||||
mixin _PostRunPluginInjection on FlutterCommand {
|
||||
/// See: [PackagesGetCommand.runCommand] in `packages.dart`
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final FlutterCommandResult result = await super.runCommand();
|
||||
|
||||
if (result == FlutterCommandResult.success()) {
|
||||
final String workingDirectory =
|
||||
argResults.rest.isNotEmpty ? argResults.rest[0] : null;
|
||||
final String target = findProjectRoot(globals.fs, workingDirectory);
|
||||
if (target == null) {
|
||||
return result;
|
||||
}
|
||||
final FlutterProject rootProject =
|
||||
FlutterProject.fromDirectory(globals.fs.directory(target));
|
||||
await ensureReadyForELinuxTooling(rootProject);
|
||||
if (rootProject.hasExampleApp &&
|
||||
rootProject.example.pubspecFile.existsSync()) {
|
||||
await ensureReadyForELinuxTooling(rootProject.example);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2021 Samsung Electronics Co., Ltd. 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/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/precache.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../elinux_cache.dart';
|
||||
|
||||
class ELinuxPrecacheCommand extends PrecacheCommand {
|
||||
ELinuxPrecacheCommand({
|
||||
bool verboseHelp = false,
|
||||
@required Cache cache,
|
||||
@required Platform platform,
|
||||
@required Logger logger,
|
||||
@required FeatureFlags featureFlags,
|
||||
}) : _cache = cache,
|
||||
_platform = platform,
|
||||
super(
|
||||
verboseHelp: verboseHelp,
|
||||
cache: cache,
|
||||
platform: platform,
|
||||
logger: logger,
|
||||
featureFlags: featureFlags,
|
||||
) {
|
||||
argParser.addFlag(
|
||||
'elinux',
|
||||
negatable: true,
|
||||
defaultsTo: false,
|
||||
help: 'Precache artifacts for Embedded Linux development.',
|
||||
);
|
||||
}
|
||||
|
||||
final Cache _cache;
|
||||
final Platform _platform;
|
||||
|
||||
bool get _includeOtherPlatforms =>
|
||||
boolArg('android') ||
|
||||
DevelopmentArtifact.values.any((DevelopmentArtifact artifact) =>
|
||||
boolArg(artifact.name) && argResults.wasParsed(artifact.name));
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final bool includeAllPlatforms = boolArg('all-platforms');
|
||||
final bool includeELinux = boolArg('elinux');
|
||||
final bool includeDefaults = !includeELinux && !_includeOtherPlatforms;
|
||||
|
||||
const String elinuxStampName = 'elinux-sdk';
|
||||
|
||||
// Re-lock the cache.
|
||||
if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
|
||||
await _cache.lock();
|
||||
}
|
||||
|
||||
if (includeAllPlatforms || includeDefaults || includeELinux) {
|
||||
if (boolArg('force')) {
|
||||
_cache.setStampFor(elinuxStampName, '');
|
||||
}
|
||||
await _cache.updateAll(<DevelopmentArtifact>{
|
||||
ELinuxDevelopmentArtifact.elinux,
|
||||
});
|
||||
}
|
||||
|
||||
if (includeAllPlatforms || includeDefaults || _includeOtherPlatforms) {
|
||||
// If the '--force' option is used, the super.runCommand() will delete
|
||||
// the elinux's stamp file. It should be restored.
|
||||
final String elinuxStamp = _cache.getStampFor(elinuxStampName);
|
||||
final FlutterCommandResult result = await super.runCommand();
|
||||
if (elinuxStamp != null) {
|
||||
_cache.setStampFor(elinuxStampName, elinuxStamp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return FlutterCommandResult.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/run.dart';
|
||||
|
||||
import '../elinux_cache.dart';
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxRunCommand extends RunCommand with ELinuxExtension {
|
||||
ELinuxRunCommand({bool verboseHelp = false})
|
||||
: super(verboseHelp: verboseHelp) {
|
||||
argParser.addOption(
|
||||
'target-backend-type',
|
||||
defaultsTo: 'wayland',
|
||||
allowed: <String>['wayland', 'gbm', 'eglstream', 'x11'],
|
||||
help: 'Target backend type that the app will run on devices.',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Set<DevelopmentArtifact>> get requiredArtifacts async =>
|
||||
<DevelopmentArtifact>{
|
||||
DevelopmentArtifact.androidGenSnapshot,
|
||||
ELinuxDevelopmentArtifact.elinux,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2021 Samsung Electronics Co., Ltd. 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/commands/test.dart';
|
||||
|
||||
import '../elinux_plugins.dart';
|
||||
|
||||
class ELinuxTestCommand extends TestCommand with ELinuxExtension {
|
||||
ELinuxTestCommand({bool verboseHelp = false})
|
||||
: super(verboseHelp: verboseHelp);
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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 'dart:io';
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/process.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/build_system/depfile.dart';
|
||||
import 'package:flutter_tools/src/build_system/exceptions.dart';
|
||||
import 'package:flutter_tools/src/build_system/source.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/android.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/assets.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/common.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/icon_tree_shaker.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/cmake.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
|
||||
import 'elinux_builder.dart';
|
||||
import 'elinux_cmake_project.dart';
|
||||
import 'elinux_plugins.dart';
|
||||
|
||||
/// Prepares the pre-built flutter bundle.
|
||||
///
|
||||
/// Source: [AndroidAssetBundle] in `android.dart`
|
||||
abstract class ELinuxAssetBundle extends Target {
|
||||
const ELinuxAssetBundle();
|
||||
|
||||
@override
|
||||
String get name => 'elinux_asset_bundle';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.pattern('{BUILD_DIR}/app.dill'),
|
||||
...IconTreeShaker.inputs,
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[];
|
||||
|
||||
@override
|
||||
List<String> get depfiles => <String>[
|
||||
'flutter_assets.d',
|
||||
];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
KernelSnapshot(),
|
||||
];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
if (environment.defines[kBuildMode] == null) {
|
||||
throw MissingDefineException(kBuildMode, name);
|
||||
}
|
||||
final BuildMode buildMode =
|
||||
getBuildModeForName(environment.defines[kBuildMode]);
|
||||
final Directory outputDirectory = environment.outputDir
|
||||
.childDirectory('flutter_assets')
|
||||
..createSync(recursive: true);
|
||||
|
||||
// Only copy the prebuilt runtimes and kernel blob in debug mode.
|
||||
if (buildMode == BuildMode.debug) {
|
||||
final String vmSnapshotData = environment.artifacts
|
||||
.getArtifactPath(Artifact.vmSnapshotData, mode: BuildMode.debug);
|
||||
final String isolateSnapshotData = environment.artifacts
|
||||
.getArtifactPath(Artifact.isolateSnapshotData, mode: BuildMode.debug);
|
||||
environment.buildDir
|
||||
.childFile('app.dill')
|
||||
.copySync(outputDirectory.childFile('kernel_blob.bin').path);
|
||||
environment.fileSystem
|
||||
.file(vmSnapshotData)
|
||||
.copySync(outputDirectory.childFile('vm_snapshot_data').path);
|
||||
environment.fileSystem
|
||||
.file(isolateSnapshotData)
|
||||
.copySync(outputDirectory.childFile('isolate_snapshot_data').path);
|
||||
}
|
||||
final Depfile assetDepfile = await copyAssets(
|
||||
environment,
|
||||
outputDirectory,
|
||||
targetPlatform: null, // corresponds to flutter-tester
|
||||
);
|
||||
final DepfileService depfileService = DepfileService(
|
||||
fileSystem: environment.fileSystem,
|
||||
logger: environment.logger,
|
||||
);
|
||||
depfileService.writeToFile(
|
||||
assetDepfile,
|
||||
environment.buildDir.childFile('flutter_assets.d'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Source: [DebugAndroidApplication] in `android.dart`
|
||||
class DebugELinuxApplication extends ELinuxAssetBundle {
|
||||
DebugELinuxApplication(this.buildInfo);
|
||||
|
||||
final ELinuxBuildInfo buildInfo;
|
||||
|
||||
@override
|
||||
String get name => 'debug_elinux_application';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => <Source>[
|
||||
...super.inputs,
|
||||
const Source.artifact(Artifact.vmSnapshotData, mode: BuildMode.debug),
|
||||
const Source.artifact(Artifact.isolateSnapshotData,
|
||||
mode: BuildMode.debug),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => <Source>[
|
||||
...super.outputs,
|
||||
const Source.pattern('{OUTPUT_DIR}/flutter_assets/vm_snapshot_data'),
|
||||
const Source.pattern(
|
||||
'{OUTPUT_DIR}/flutter_assets/isolate_snapshot_data'),
|
||||
const Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => <Target>[
|
||||
...super.dependencies,
|
||||
ELinuxPlugins(buildInfo),
|
||||
];
|
||||
}
|
||||
|
||||
/// See: [ReleaseAndroidApplication] in `android.dart`
|
||||
class ReleaseELinuxApplication extends ELinuxAssetBundle {
|
||||
ReleaseELinuxApplication(this.buildInfo);
|
||||
|
||||
final ELinuxBuildInfo buildInfo;
|
||||
|
||||
@override
|
||||
String get name => 'release_elinux_application';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => <Target>[
|
||||
...super.dependencies,
|
||||
ELinuxAotElf(),
|
||||
ELinuxPlugins(buildInfo),
|
||||
];
|
||||
}
|
||||
|
||||
/// Compiles eLinux native plugins into a single shared object.
|
||||
class ELinuxPlugins extends Target {
|
||||
ELinuxPlugins(this.buildInfo);
|
||||
|
||||
final ELinuxBuildInfo buildInfo;
|
||||
|
||||
@override
|
||||
String get name => 'elinux_plugins';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[
|
||||
Source.pattern('{FLUTTER_ROOT}/../lib/elinux_build_target.dart'),
|
||||
Source.pattern('{PROJECT_DIR}/.packages'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[];
|
||||
|
||||
@override
|
||||
List<String> get depfiles => <String>[
|
||||
'elinux_plugins.d',
|
||||
];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
// todo: add plugin build support.
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates an AOT snapshot (app.so) of the Dart code.
|
||||
///
|
||||
/// Source: [AotElfRelease] in `common.dart`
|
||||
class ELinuxAotElf extends AotElfBase {
|
||||
ELinuxAotElf();
|
||||
|
||||
@override
|
||||
String get name => 'elinux_aot_elf';
|
||||
|
||||
@override
|
||||
List<Source> get inputs => <Source>[
|
||||
const Source.pattern('{BUILD_DIR}/app.dill'),
|
||||
const Source.hostArtifact(HostArtifact.engineDartBinary),
|
||||
const Source.artifact(Artifact.skyEnginePath),
|
||||
// Any type of gen_snapshot is applicable here because engine artifacts
|
||||
// are assumed to be updated at once, not one by one for each platform
|
||||
// or build mode.
|
||||
const Source.artifact(Artifact.genSnapshot, mode: BuildMode.release),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[
|
||||
Source.pattern('{BUILD_DIR}/app.so'),
|
||||
];
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
KernelSnapshot(),
|
||||
];
|
||||
}
|
||||
|
||||
class NativeBundle {
|
||||
NativeBundle(this.buildInfo, this.targetFile);
|
||||
|
||||
final ELinuxBuildInfo buildInfo;
|
||||
final String targetFile;
|
||||
|
||||
final ProcessUtils _processUtils = ProcessUtils(
|
||||
logger: globals.logger, processManager: globals.processManager);
|
||||
|
||||
Future<void> build(Environment environment) async {
|
||||
final FlutterProject project =
|
||||
FlutterProject.fromDirectory(environment.projectDir);
|
||||
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
|
||||
|
||||
// Clean up the intermediate and output directories.
|
||||
final Directory eLinuxDir = eLinuxProject.editableDirectory;
|
||||
|
||||
final BuildMode buildMode = buildInfo.buildInfo.mode;
|
||||
final String buildConfig = buildMode.isPrecompiled ? 'release' : 'debug';
|
||||
final Directory outputDir = environment.outputDir
|
||||
.childDirectory(buildInfo.targetArch)
|
||||
.childDirectory(buildConfig);
|
||||
if (outputDir.existsSync()) {
|
||||
outputDir.deleteSync(recursive: true);
|
||||
}
|
||||
outputDir.createSync(recursive: true);
|
||||
|
||||
final Directory outputBundleDir = outputDir.childDirectory('bundle');
|
||||
if (outputBundleDir.existsSync()) {
|
||||
outputBundleDir.deleteSync(recursive: true);
|
||||
}
|
||||
outputBundleDir.createSync(recursive: true);
|
||||
|
||||
final Directory outputBundleLibDir = outputBundleDir.childDirectory('lib');
|
||||
if (outputBundleLibDir.existsSync()) {
|
||||
outputBundleLibDir.deleteSync(recursive: true);
|
||||
}
|
||||
outputBundleLibDir.createSync(recursive: true);
|
||||
|
||||
final Directory outputBundleDataDir =
|
||||
outputBundleDir.childDirectory('data');
|
||||
if (outputBundleDataDir.existsSync()) {
|
||||
outputBundleDataDir.deleteSync(recursive: true);
|
||||
}
|
||||
outputBundleDataDir.createSync(recursive: true);
|
||||
|
||||
// Copy necessary files
|
||||
final Directory engineDir =
|
||||
_getEngineArtifactsDirectory(buildInfo.targetArch, buildMode);
|
||||
final Directory commonDir =
|
||||
engineDir.parent.childDirectory('elinux-common');
|
||||
final File engineBinary = engineDir.childFile('libflutter_engine.so');
|
||||
final File embedder =
|
||||
engineDir.childFile(buildInfo.targetBackendType == 'gbm'
|
||||
? 'libflutter_elinux_gbm.so'
|
||||
: buildInfo.targetBackendType == 'eglstream'
|
||||
? 'libflutter_elinux_eglstream.so'
|
||||
: buildInfo.targetBackendType == 'x11'
|
||||
? 'libflutter_elinux_x11.so'
|
||||
: 'libflutter_elinux_wayland.so');
|
||||
final Directory clientWrapperDir =
|
||||
commonDir.childDirectory('cpp_client_wrapper');
|
||||
|
||||
final Directory pluginsDir =
|
||||
environment.buildDir.childDirectory('elinux_plugins');
|
||||
final File pluginsLib = pluginsDir.childFile('libflutter_plugins.so');
|
||||
if (pluginsLib.existsSync()) {
|
||||
pluginsLib
|
||||
.copySync(outputBundleLibDir.childFile(pluginsLib.basename).path);
|
||||
}
|
||||
final Directory pluginsUserLibDir = pluginsDir.childDirectory('lib');
|
||||
if (pluginsUserLibDir.existsSync()) {
|
||||
pluginsUserLibDir.listSync().whereType<File>().forEach((File lib) =>
|
||||
lib.copySync(outputBundleLibDir.childFile(lib.basename).path));
|
||||
}
|
||||
|
||||
final Directory flutterDir = eLinuxDir.childDirectory('flutter');
|
||||
final Directory flutterEphemeralDir =
|
||||
flutterDir.childDirectory('ephemeral');
|
||||
|
||||
// Copy necessary files.
|
||||
{
|
||||
if (flutterEphemeralDir.existsSync()) {
|
||||
flutterEphemeralDir.deleteSync(recursive: true);
|
||||
}
|
||||
flutterEphemeralDir.createSync(recursive: true);
|
||||
flutterEphemeralDir
|
||||
.childDirectory('cpp_client_wrapper')
|
||||
.createSync(recursive: true);
|
||||
|
||||
copyDirectory(
|
||||
clientWrapperDir,
|
||||
flutterEphemeralDir.childDirectory('cpp_client_wrapper'),
|
||||
);
|
||||
|
||||
commonDir.listSync().whereType<File>().forEach((File lib) =>
|
||||
lib.copySync(flutterEphemeralDir.childFile(lib.basename).path));
|
||||
|
||||
engineBinary
|
||||
.copySync(flutterEphemeralDir.childFile(engineBinary.basename).path);
|
||||
embedder.copySync(flutterEphemeralDir.childFile(embedder.basename).path);
|
||||
|
||||
final File icuData =
|
||||
commonDir.childDirectory('icu').childFile('icudtl.dat');
|
||||
icuData.copySync(flutterEphemeralDir.childFile(icuData.basename).path);
|
||||
|
||||
if (buildMode.isPrecompiled) {
|
||||
final File aotSharedLib = environment.buildDir.childFile('app.so');
|
||||
aotSharedLib.copySync(flutterEphemeralDir.childFile('libapp.so').path);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the environment that needs to be set for the re-entrant flutter build
|
||||
// step.
|
||||
{
|
||||
final Map<String, String> environment = <String, String>{
|
||||
if (targetFile != null) 'FLUTTER_TARGET': targetFile,
|
||||
...buildInfo.buildInfo.toEnvironmentConfig(),
|
||||
};
|
||||
if (globals.artifacts is LocalEngineArtifacts) {
|
||||
final LocalEngineArtifacts localEngineArtifacts =
|
||||
globals.artifacts as LocalEngineArtifacts;
|
||||
final String engineOutPath = localEngineArtifacts.engineOutPath;
|
||||
environment['FLUTTER_ENGINE'] =
|
||||
globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath));
|
||||
environment['LOCAL_ENGINE'] = globals.fs.path.basename(engineOutPath);
|
||||
}
|
||||
writeGeneratedCmakeConfig(Cache.flutterRoot, eLinuxProject, environment);
|
||||
|
||||
//createPluginSymlinks(eLinuxProject.parent);
|
||||
}
|
||||
|
||||
// Run the native build.
|
||||
final String cmakeBuildType = buildMode.isPrecompiled ? 'Release' : 'Debug';
|
||||
RunResult result = await _processUtils.run(
|
||||
<String>[
|
||||
'cmake',
|
||||
'-DCMAKE_BUILD_TYPE=$cmakeBuildType',
|
||||
'-DFLUTTER_TARGET_BACKEND_TYPE=${buildInfo.targetBackendType}',
|
||||
eLinuxDir.path,
|
||||
],
|
||||
workingDirectory: outputDir.path,
|
||||
environment: <String, String>{'CC': 'clang', 'CXX': 'clang++'},
|
||||
);
|
||||
if (result.exitCode != 0) {
|
||||
throwToolExit('Failed to cmake:\n$result');
|
||||
}
|
||||
|
||||
result = await _processUtils.run(
|
||||
<String>['cmake', '--build', '.'],
|
||||
workingDirectory: outputDir.path,
|
||||
);
|
||||
if (result.exitCode != 0) {
|
||||
throwToolExit('Failed to cmake build:\n$result');
|
||||
}
|
||||
|
||||
// Create flutter app's bunle.
|
||||
result = await _processUtils.run(
|
||||
<String>['cmake', '--install', '.'],
|
||||
workingDirectory: outputDir.path,
|
||||
);
|
||||
if (result.exitCode != 0) {
|
||||
throwToolExit('Failed to cmake install:\n$result');
|
||||
}
|
||||
{
|
||||
final Directory flutterAssetsDir =
|
||||
outputBundleDataDir.childDirectory('flutter_assets');
|
||||
copyDirectory(
|
||||
environment.outputDir.childDirectory('flutter_assets'),
|
||||
flutterAssetsDir,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts [targetArch] to an arch name that corresponds to the `BUILD_ARCH`
|
||||
/// value used by the eLinux native builder.
|
||||
String getELinuxBuildArch(String targetArch) {
|
||||
switch (targetArch) {
|
||||
case 'arm':
|
||||
return 'armel';
|
||||
case 'arm64':
|
||||
return 'aarch64';
|
||||
case 'x86':
|
||||
return 'i586';
|
||||
default:
|
||||
return targetArch;
|
||||
}
|
||||
}
|
||||
|
||||
/// On non-Windows, returns [path] unchanged.
|
||||
///
|
||||
/// On Windows, converts Windows-style [path] (e.g. 'C:\x\y') into Unix path
|
||||
/// ('/c/x/y') and returns.
|
||||
String getUnixPath(String path) {
|
||||
if (Platform.isWindows) {
|
||||
path = path.replaceAll(r'\', '/');
|
||||
if (path.startsWith(':', 1)) {
|
||||
path = '/${path[0].toLowerCase()}${path.substring(2)}';
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/// On non-Windows, returns the PATH environment variable.
|
||||
///
|
||||
/// On Windows, appends the msys2 executables directory to PATH and returns.
|
||||
String getDefaultPathVariable() {
|
||||
final Map<String, String> variables = globals.platform.environment;
|
||||
return variables.containsKey('PATH') ? variables['PATH'] : '';
|
||||
}
|
||||
|
||||
/// See: [CachedArtifacts._getEngineArtifactsPath]
|
||||
Directory _getEngineArtifactsDirectory(String arch, BuildMode mode) {
|
||||
assert(mode != null, 'Need to specify a build mode.');
|
||||
return globals.cache
|
||||
.getArtifactDirectory('engine')
|
||||
.childDirectory('elinux-$arch-${mode.name}');
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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:file/file.dart';
|
||||
import 'package:flutter_tools/src/android/android_builder.dart';
|
||||
import 'package:flutter_tools/src/android/gradle.dart';
|
||||
import 'package:flutter_tools/src/base/analyze_size.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/build_system/build_system.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/assemble.dart';
|
||||
import 'package:flutter_tools/src/commands/build_ios_framework.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/linux/build_linux.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'elinux_build_target.dart';
|
||||
import 'elinux_cmake_project.dart';
|
||||
|
||||
/// The define to control what eLinux device is built for.
|
||||
const String kTargetBackendType = 'TargetBackendType';
|
||||
|
||||
/// See: [AndroidBuildInfo] in `build_info.dart`
|
||||
class ELinuxBuildInfo {
|
||||
const ELinuxBuildInfo(
|
||||
this.buildInfo, {
|
||||
@required this.targetArch,
|
||||
@required this.targetBackendType,
|
||||
}) : assert(targetArch != null),
|
||||
assert(targetBackendType != null);
|
||||
|
||||
final BuildInfo buildInfo;
|
||||
final String targetArch;
|
||||
final String targetBackendType;
|
||||
}
|
||||
|
||||
/// See:
|
||||
/// - [AndroidBuilder] in `android_builder.dart`
|
||||
/// - [AndroidGradleBuilder.buildGradleApp] in `gradle.dart`
|
||||
/// - [BuildIOSFrameworkCommand._produceAppFramework] in `build_ios_framework.dart` (build target)
|
||||
/// - [AssembleCommand.runCommand] in `assemble.dart` (performance measurement)
|
||||
/// - [buildLinux] in `build_linux.dart` (code size)
|
||||
class ELinuxBuilder {
|
||||
static Future<void> buildBundle({
|
||||
@required FlutterProject project,
|
||||
@required ELinuxBuildInfo eLinuxBuildInfo,
|
||||
@required String targetFile,
|
||||
SizeAnalyzer sizeAnalyzer,
|
||||
}) async {
|
||||
final ELinuxProject elinuxProject = ELinuxProject.fromFlutter(project);
|
||||
if (!elinuxProject.existsSync()) {
|
||||
throwToolExit(
|
||||
'This project is not configured for eLinux.\n'
|
||||
'To fix this problem, create a new project by running `flutter-elinux create <app-dir>`.',
|
||||
);
|
||||
}
|
||||
|
||||
final Directory outputDir =
|
||||
project.directory.childDirectory('build').childDirectory('elinux');
|
||||
final BuildInfo buildInfo = eLinuxBuildInfo.buildInfo;
|
||||
final String buildModeName = getNameForBuildMode(buildInfo.mode);
|
||||
// Used by AotElfBase to generate an AOT snapshot.
|
||||
final String targetPlatform = getNameForTargetPlatform(
|
||||
_getTargetPlatformForArch(eLinuxBuildInfo.targetArch));
|
||||
|
||||
final Environment environment = Environment(
|
||||
projectDir: project.directory,
|
||||
outputDir: outputDir,
|
||||
buildDir: project.dartTool.childDirectory('flutter_build'),
|
||||
cacheDir: globals.cache.getRoot(),
|
||||
flutterRootDir: globals.fs.directory(Cache.flutterRoot),
|
||||
engineVersion: globals.flutterVersion.engineRevision,
|
||||
generateDartPluginRegistry: true,
|
||||
defines: <String, String>{
|
||||
kTargetFile: targetFile,
|
||||
kBuildMode: buildModeName,
|
||||
kTargetPlatform: targetPlatform,
|
||||
kDartObfuscation: buildInfo.dartObfuscation.toString(),
|
||||
kSplitDebugInfo: buildInfo.splitDebugInfoPath,
|
||||
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
|
||||
kTrackWidgetCreation: buildInfo.trackWidgetCreation.toString(),
|
||||
kCodeSizeDirectory: buildInfo.codeSizeDirectory,
|
||||
if (buildInfo.dartDefines?.isNotEmpty ?? false)
|
||||
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
|
||||
if (buildInfo.extraGenSnapshotOptions?.isNotEmpty ?? false)
|
||||
kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','),
|
||||
if (buildInfo.extraFrontEndOptions?.isNotEmpty ?? false)
|
||||
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','),
|
||||
kTargetBackendType: eLinuxBuildInfo.targetBackendType,
|
||||
},
|
||||
inputs: <String, String>{
|
||||
kBundleSkSLPath: buildInfo.bundleSkSLPath,
|
||||
},
|
||||
artifacts: globals.artifacts,
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
processManager: globals.processManager,
|
||||
platform: globals.platform,
|
||||
);
|
||||
|
||||
final Target target = buildInfo.isDebug
|
||||
? DebugELinuxApplication(eLinuxBuildInfo)
|
||||
: ReleaseELinuxApplication(eLinuxBuildInfo);
|
||||
|
||||
final Status status = globals.logger.startProgress(
|
||||
'Building an eLinux application with ${eLinuxBuildInfo.targetBackendType} backend in $buildModeName mode for ${eLinuxBuildInfo.targetArch} target...');
|
||||
try {
|
||||
final BuildResult result =
|
||||
await globals.buildSystem.build(target, environment);
|
||||
if (!result.success) {
|
||||
for (final ExceptionMeasurement measurement
|
||||
in result.exceptions.values) {
|
||||
globals.printError(measurement.exception.toString());
|
||||
}
|
||||
throwToolExit('The build failed.');
|
||||
}
|
||||
|
||||
// These pseudo targets cannot be skipped and should be invoked whenever
|
||||
// the build is run.
|
||||
await NativeBundle(eLinuxBuildInfo, targetFile).build(environment);
|
||||
|
||||
if (buildInfo.performanceMeasurementFile != null) {
|
||||
final File outFile =
|
||||
globals.fs.file(buildInfo.performanceMeasurementFile);
|
||||
// ignore: invalid_use_of_visible_for_testing_member
|
||||
writePerformanceData(result.performance.values, outFile);
|
||||
}
|
||||
} finally {
|
||||
status.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See: [getTargetPlatformForName] in `build_info.dart`
|
||||
TargetPlatform _getTargetPlatformForArch(String arch) {
|
||||
switch (arch) {
|
||||
case 'arm64':
|
||||
return TargetPlatform.android_arm64;
|
||||
default:
|
||||
return TargetPlatform.android_x64;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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/common.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart' show OperatingSystemUtils;
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/flutter_cache.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
/// See: [DevelopmentArtifact] in `cache.dart`
|
||||
class ELinuxDevelopmentArtifact implements DevelopmentArtifact {
|
||||
const ELinuxDevelopmentArtifact._(this.name, this.feature);
|
||||
|
||||
@override
|
||||
final String name;
|
||||
|
||||
@override
|
||||
final Feature feature;
|
||||
|
||||
static const DevelopmentArtifact elinux =
|
||||
ELinuxDevelopmentArtifact._('elinux', null);
|
||||
}
|
||||
|
||||
/// Extends [FlutterCache] to register [ELinuxEngineArtifacts].
|
||||
///
|
||||
/// See: [FlutterCache] in `flutter_cache.dart`
|
||||
class ELinuxFlutterCache extends FlutterCache {
|
||||
ELinuxFlutterCache({
|
||||
@required Logger logger,
|
||||
@required FileSystem fileSystem,
|
||||
@required Platform platform,
|
||||
@required OperatingSystemUtils osUtils,
|
||||
}) : super(
|
||||
logger: logger,
|
||||
fileSystem: fileSystem,
|
||||
platform: platform,
|
||||
osUtils: osUtils) {
|
||||
registerArtifact(ELinuxEngineArtifacts(this, platform: platform));
|
||||
}
|
||||
}
|
||||
|
||||
class ELinuxEngineArtifacts extends EngineCachedArtifact {
|
||||
ELinuxEngineArtifacts(
|
||||
Cache cache, {
|
||||
@required Platform platform,
|
||||
}) : _platform = platform,
|
||||
super(
|
||||
'elinux-sdk',
|
||||
cache,
|
||||
ELinuxDevelopmentArtifact.elinux,
|
||||
);
|
||||
|
||||
final Platform _platform;
|
||||
|
||||
@override
|
||||
String get version {
|
||||
final File versionFile = globals.fs
|
||||
.directory(Cache.flutterRoot)
|
||||
.parent
|
||||
.childDirectory('bin')
|
||||
.childDirectory('internal')
|
||||
.childFile('engine.version');
|
||||
return versionFile.existsSync()
|
||||
? versionFile.readAsStringSync().trim()
|
||||
: null;
|
||||
}
|
||||
|
||||
String get shortVersion {
|
||||
if (version != null && version.length >= 10) {
|
||||
return version.substring(0, 10);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/// See: [Cache.storageBaseUrl] in `cache.dart`
|
||||
String get engineBaseUrl {
|
||||
final String overrideUrl = _platform.environment['ELINUX_ENGINE_BASE_URL'];
|
||||
if (overrideUrl == null) {
|
||||
return 'https://github.com/sony/flutter-embedded-linux/releases';
|
||||
}
|
||||
try {
|
||||
Uri.parse(overrideUrl);
|
||||
} on FormatException catch (err) {
|
||||
throwToolExit('"ELINUX_ENGINE_BASE_URL" contains an invalid URI:\n$err');
|
||||
}
|
||||
return overrideUrl;
|
||||
}
|
||||
|
||||
@override
|
||||
List<List<String>> getBinaryDirs() => <List<String>>[
|
||||
<String>['elinux-common', 'elinux-common.zip'],
|
||||
<String>['elinux-arm64-debug', 'elinux-arm64-debug.zip'],
|
||||
<String>['elinux-arm64-profile', 'elinux-arm64-profile.zip'],
|
||||
<String>['elinux-arm64-release', 'elinux-arm64-release.zip'],
|
||||
<String>['elinux-x64-debug', 'elinux-x64-debug.zip'],
|
||||
<String>['elinux-x64-profile', 'elinux-x64-profile.zip'],
|
||||
<String>['elinux-x64-release', 'elinux-x64-release.zip'],
|
||||
];
|
||||
|
||||
@override
|
||||
List<String> getLicenseDirs() => const <String>[];
|
||||
|
||||
@override
|
||||
List<String> getPackageDirs() => const <String>[];
|
||||
|
||||
@override
|
||||
Future<void> updateInner(
|
||||
ArtifactUpdater artifactUpdater,
|
||||
FileSystem fileSystem,
|
||||
OperatingSystemUtils operatingSystemUtils,
|
||||
) async {
|
||||
final String downloadUrl = '$engineBaseUrl/download/$shortVersion';
|
||||
for (final List<String> toolsDir in getBinaryDirs()) {
|
||||
final String cacheDir = toolsDir[0];
|
||||
final String urlPath = toolsDir[1];
|
||||
await artifactUpdater.downloadZipArchive(
|
||||
'Downloading $cacheDir tools...',
|
||||
Uri.parse('$downloadUrl/$urlPath'),
|
||||
location.childDirectory(cacheDir),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// 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 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
|
||||
import 'elinux_plugins.dart';
|
||||
|
||||
/// The eLinux sub project.
|
||||
class ELinuxProject extends FlutterProjectPlatform
|
||||
implements CmakeBasedProject {
|
||||
ELinuxProject.fromFlutter(this.parent);
|
||||
|
||||
@override
|
||||
final FlutterProject parent;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => ELinuxPlugin.kConfigKey;
|
||||
|
||||
String get _childDirectory => 'elinux';
|
||||
|
||||
@override
|
||||
bool existsSync() => editableDirectory.existsSync() && cmakeFile.existsSync();
|
||||
|
||||
@override
|
||||
File get cmakeFile => editableDirectory.childFile('CMakeLists.txt');
|
||||
|
||||
@override
|
||||
File get managedCmakeFile => managedDirectory.childFile('CMakeLists.txt');
|
||||
|
||||
@override
|
||||
File get generatedCmakeConfigFile =>
|
||||
ephemeralDirectory.childFile('generated_config.cmake');
|
||||
|
||||
@override
|
||||
File get generatedPluginCmakeFile =>
|
||||
managedDirectory.childFile('generated_plugins.cmake');
|
||||
|
||||
@override
|
||||
Directory get pluginSymlinkDirectory =>
|
||||
ephemeralDirectory.childDirectory('.plugin_symlinks');
|
||||
|
||||
Directory get editableDirectory =>
|
||||
parent.directory.childDirectory(_childDirectory);
|
||||
|
||||
Directory get managedDirectory => editableDirectory.childDirectory('flutter');
|
||||
|
||||
Directory get ephemeralDirectory =>
|
||||
managedDirectory.childDirectory('ephemeral');
|
||||
|
||||
Future<void> ensureReadyForPlatformSpecificTooling() async {}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// 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 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_tools/src/android/android_device.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/convert.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/protocol_discovery.dart';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'elinux_builder.dart';
|
||||
import 'elinux_package.dart';
|
||||
|
||||
/// eLinux device implementation.
|
||||
///
|
||||
/// See: [DesktopDevice] in `desktop_device.dart`
|
||||
class ELinuxDevice extends Device {
|
||||
ELinuxDevice(
|
||||
String id, {
|
||||
@required bool desktop,
|
||||
@required String backendType,
|
||||
@required String targetArch,
|
||||
@required Logger logger,
|
||||
@required ProcessManager processManager,
|
||||
@required OperatingSystemUtils operatingSystemUtils,
|
||||
}) : _desktop = desktop,
|
||||
_backendType = backendType,
|
||||
_targetArch = targetArch,
|
||||
_logger = logger,
|
||||
_processManager = processManager,
|
||||
_operatingSystemUtils = operatingSystemUtils,
|
||||
super(id,
|
||||
category: Category.desktop,
|
||||
platformType: PlatformType.custom,
|
||||
ephemeral: true);
|
||||
|
||||
final bool _desktop;
|
||||
final String _backendType;
|
||||
final String _targetArch;
|
||||
final Logger _logger;
|
||||
final ProcessManager _processManager;
|
||||
final OperatingSystemUtils _operatingSystemUtils;
|
||||
final Set<Process> _runningProcesses = <Process>{};
|
||||
final ELinuxLogReader _logReader = ELinuxLogReader();
|
||||
|
||||
@override
|
||||
Future<bool> get isLocalEmulator async => false;
|
||||
|
||||
@override
|
||||
Future<String> get emulatorId async => null;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async {
|
||||
// Use tester as a platform identifer for eLinux.
|
||||
// There's currently no other choice because getNameForTargetPlatform()
|
||||
// throws an error for unknown platform types.
|
||||
return TargetPlatform.tester;
|
||||
}
|
||||
|
||||
@override
|
||||
bool supportsRuntimeMode(BuildMode buildMode) =>
|
||||
buildMode != BuildMode.jitRelease;
|
||||
|
||||
@override
|
||||
Future<String> get sdkNameAndVersion async => _operatingSystemUtils.name;
|
||||
|
||||
@override
|
||||
String get name => 'eLinux';
|
||||
|
||||
@override
|
||||
Future<bool> isAppInstalled(ELinuxApp app, {String userIdentifier}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isLatestBuildInstalled(ELinuxApp app) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> installApp(ELinuxApp app, {String userIdentifier}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> uninstallApp(ELinuxApp app, {String userIdentifier}) async {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Source: [AndroidDevice.startApp] in `android_device.dart`
|
||||
@override
|
||||
Future<LaunchResult> startApp(
|
||||
ELinuxApp package, {
|
||||
String mainPath,
|
||||
String route,
|
||||
DebuggingOptions debuggingOptions,
|
||||
Map<String, dynamic> platformArgs,
|
||||
bool prebuiltApplication = false,
|
||||
bool ipv6 = false,
|
||||
String userIdentifier,
|
||||
}) async {
|
||||
if (!prebuiltApplication) {
|
||||
_logger.printTrace('Building app');
|
||||
await buildForDevice(
|
||||
package,
|
||||
buildInfo: debuggingOptions.buildInfo,
|
||||
mainPath: mainPath,
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure that the executable is locatable.
|
||||
final BuildMode buildMode = debuggingOptions?.buildInfo?.mode;
|
||||
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
|
||||
final String executable = executablePathForDevice(package, buildMode);
|
||||
const String executableOptions = '--bundle=./';
|
||||
if (executable == null) {
|
||||
_logger.printError('Unable to find executable to run');
|
||||
return LaunchResult.failed();
|
||||
}
|
||||
|
||||
final Process process = await _processManager.start(
|
||||
<String>[
|
||||
executable,
|
||||
executableOptions,
|
||||
if (_desktop && _backendType == 'wayland') '-d',
|
||||
...?debuggingOptions?.dartEntrypointArgs,
|
||||
],
|
||||
environment: _computeEnvironment(debuggingOptions, traceStartup, route),
|
||||
);
|
||||
_runningProcesses.add(process);
|
||||
unawaited(process.exitCode.then((_) => _runningProcesses.remove(process)));
|
||||
|
||||
_logReader.initializeProcess(process);
|
||||
if (debuggingOptions?.buildInfo?.isRelease == true) {
|
||||
return LaunchResult.succeeded();
|
||||
}
|
||||
final ProtocolDiscovery observatoryDiscovery =
|
||||
ProtocolDiscovery.observatory(
|
||||
_logReader,
|
||||
devicePort: debuggingOptions?.deviceVmServicePort,
|
||||
hostPort: debuggingOptions?.hostVmServicePort,
|
||||
ipv6: ipv6,
|
||||
logger: _logger,
|
||||
);
|
||||
try {
|
||||
final Uri observatoryUri = await observatoryDiscovery.uri;
|
||||
if (observatoryUri != null) {
|
||||
onAttached(package, buildMode, process);
|
||||
return LaunchResult.succeeded(observatoryUri: observatoryUri);
|
||||
}
|
||||
_logger.printError(
|
||||
'Error waiting for a debug connection: '
|
||||
'The log reader stopped unexpectedly.',
|
||||
);
|
||||
} on Exception catch (error) {
|
||||
_logger.printError('Error waiting for a debug connection: $error');
|
||||
} finally {
|
||||
await observatoryDiscovery.cancel();
|
||||
}
|
||||
return LaunchResult.failed();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> stopApp(ELinuxApp app, {String userIdentifier}) async {
|
||||
bool succeeded = true;
|
||||
// Walk a copy of _runningProcesses, since the exit handler removes from the
|
||||
// set.
|
||||
for (final Process process in Set<Process>.of(_runningProcesses)) {
|
||||
succeeded &= _processManager.killPid(process.pid);
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
@override
|
||||
void clearLogs() {}
|
||||
|
||||
@override
|
||||
FutureOr<DeviceLogReader> getLogReader({
|
||||
ELinuxApp app,
|
||||
bool includePastLogs = false,
|
||||
}) =>
|
||||
_logReader;
|
||||
|
||||
@override
|
||||
DevicePortForwarder get portForwarder => null;
|
||||
|
||||
@override
|
||||
bool isSupported() => true;
|
||||
|
||||
@override
|
||||
bool get supportsScreenshot => false;
|
||||
|
||||
@override
|
||||
bool isSupportedForProject(FlutterProject flutterProject) {
|
||||
return flutterProject.isModule &&
|
||||
flutterProject.directory.childDirectory('elinux').existsSync();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {}
|
||||
|
||||
Future<void> buildForDevice(
|
||||
ELinuxApp package, {
|
||||
String mainPath,
|
||||
BuildInfo buildInfo,
|
||||
}) async {
|
||||
final FlutterProject project = FlutterProject.current();
|
||||
final ELinuxBuildInfo eLinuxBuildInfo = ELinuxBuildInfo(
|
||||
buildInfo,
|
||||
targetArch: _targetArch,
|
||||
targetBackendType: _backendType,
|
||||
);
|
||||
await ELinuxBuilder.buildBundle(
|
||||
project: project,
|
||||
targetFile: mainPath,
|
||||
eLinuxBuildInfo: eLinuxBuildInfo,
|
||||
);
|
||||
package = ELinuxApp.fromELinuxProject(project);
|
||||
}
|
||||
|
||||
String executablePathForDevice(ELinuxApp package, BuildMode buildMode) {
|
||||
return package.executable(buildMode, _targetArch);
|
||||
}
|
||||
|
||||
void onAttached(ELinuxApp package, BuildMode buildMode, Process process) {}
|
||||
|
||||
/// Computes a set of environment variables used to pass debugging information
|
||||
/// to the engine without interfering with application level command line
|
||||
/// arguments.
|
||||
///
|
||||
/// The format of the environment variables is:
|
||||
/// * FLUTTER_ENGINE_SWITCHES to the number of switches.
|
||||
/// * FLUTTER_ENGINE_SWITCH_<N> (indexing from 1) to the individual switches.
|
||||
Map<String, String> _computeEnvironment(
|
||||
DebuggingOptions debuggingOptions, bool traceStartup, String route) {
|
||||
int flags = 0;
|
||||
final Map<String, String> environment = <String, String>{};
|
||||
|
||||
void addFlag(String value) {
|
||||
flags += 1;
|
||||
environment['FLUTTER_ENGINE_SWITCH_$flags'] = value;
|
||||
}
|
||||
|
||||
void finish() {
|
||||
environment['FLUTTER_ENGINE_SWITCHES'] = flags.toString();
|
||||
}
|
||||
|
||||
addFlag('enable-dart-profiling=true');
|
||||
addFlag('enable-background-compilation=true');
|
||||
|
||||
if (traceStartup) {
|
||||
addFlag('trace-startup=true');
|
||||
}
|
||||
if (route != null) {
|
||||
addFlag('route=$route');
|
||||
}
|
||||
if (debuggingOptions.enableSoftwareRendering) {
|
||||
addFlag('enable-software-rendering=true');
|
||||
}
|
||||
if (debuggingOptions.skiaDeterministicRendering) {
|
||||
addFlag('skia-deterministic-rendering=true');
|
||||
}
|
||||
if (debuggingOptions.traceSkia) {
|
||||
addFlag('trace-skia=true');
|
||||
}
|
||||
if (debuggingOptions.traceAllowlist != null) {
|
||||
addFlag('trace-allowlist=${debuggingOptions.traceAllowlist}');
|
||||
}
|
||||
if (debuggingOptions.traceSkiaAllowlist != null) {
|
||||
addFlag('trace-skia-allowlist=${debuggingOptions.traceSkiaAllowlist}');
|
||||
}
|
||||
if (debuggingOptions.traceSystrace) {
|
||||
addFlag('trace-systrace=true');
|
||||
}
|
||||
if (debuggingOptions.endlessTraceBuffer) {
|
||||
addFlag('endless-trace-buffer=true');
|
||||
}
|
||||
if (debuggingOptions.dumpSkpOnShaderCompilation) {
|
||||
addFlag('dump-skp-on-shader-compilation=true');
|
||||
}
|
||||
if (debuggingOptions.cacheSkSL) {
|
||||
addFlag('cache-sksl=true');
|
||||
}
|
||||
if (debuggingOptions.purgePersistentCache) {
|
||||
addFlag('purge-persistent-cache=true');
|
||||
}
|
||||
// Options only supported when there is a VM Service connection between the
|
||||
// tool and the device, usually in debug or profile mode.
|
||||
if (debuggingOptions.debuggingEnabled) {
|
||||
if (debuggingOptions.deviceVmServicePort != null) {
|
||||
addFlag('observatory-port=${debuggingOptions.deviceVmServicePort}');
|
||||
}
|
||||
if (debuggingOptions.buildInfo.isDebug) {
|
||||
addFlag('enable-checked-mode=true');
|
||||
addFlag('verify-entry-points=true');
|
||||
}
|
||||
if (debuggingOptions.startPaused) {
|
||||
addFlag('start-paused=true');
|
||||
}
|
||||
if (debuggingOptions.disableServiceAuthCodes) {
|
||||
addFlag('disable-service-auth-codes=true');
|
||||
}
|
||||
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
|
||||
if (dartVmFlags.isNotEmpty) {
|
||||
addFlag('dart-flags=$dartVmFlags');
|
||||
}
|
||||
if (debuggingOptions.useTestFonts) {
|
||||
addFlag('use-test-fonts=true');
|
||||
}
|
||||
if (debuggingOptions.verboseSystemLogs) {
|
||||
addFlag('verbose-logging=true');
|
||||
}
|
||||
}
|
||||
finish();
|
||||
return environment;
|
||||
}
|
||||
}
|
||||
|
||||
class ELinuxLogReader extends DeviceLogReader {
|
||||
final StreamController<List<int>> _inputController =
|
||||
StreamController<List<int>>.broadcast();
|
||||
|
||||
void initializeProcess(Process process) {
|
||||
process.stdout.listen(_inputController.add);
|
||||
process.stderr.listen(_inputController.add);
|
||||
process.exitCode.whenComplete(_inputController.close);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<String> get logLines {
|
||||
return _inputController.stream
|
||||
.transform(utf8.decoder)
|
||||
.transform(const LineSplitter());
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => 'eLinux';
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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/android/android_device_discovery.dart';
|
||||
import 'package:flutter_tools/src/android/android_workflow.dart';
|
||||
import 'package:flutter_tools/src/base/context.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/context_runner.dart';
|
||||
import 'package:flutter_tools/src/custom_devices/custom_devices_config.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/flutter_device_manager.dart';
|
||||
import 'package:flutter_tools/src/fuchsia/fuchsia_workflow.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/macos/macos_workflow.dart';
|
||||
import 'package:flutter_tools/src/windows/uwptool.dart';
|
||||
import 'package:flutter_tools/src/windows/windows_workflow.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:process/process.dart';
|
||||
|
||||
import 'elinux_device.dart';
|
||||
import 'elinux_doctor.dart';
|
||||
|
||||
/// An extended [FlutterDeviceManager] for managing eLinux devices.
|
||||
class ELinuxDeviceManager extends FlutterDeviceManager {
|
||||
/// Source: [runInContext] in `context_runner.dart`
|
||||
ELinuxDeviceManager()
|
||||
: super(
|
||||
logger: globals.logger,
|
||||
processManager: globals.processManager,
|
||||
platform: globals.platform,
|
||||
androidSdk: globals.androidSdk,
|
||||
iosSimulatorUtils: globals.iosSimulatorUtils,
|
||||
featureFlags: featureFlags,
|
||||
fileSystem: globals.fs,
|
||||
iosWorkflow: globals.iosWorkflow,
|
||||
artifacts: globals.artifacts,
|
||||
flutterVersion: globals.flutterVersion,
|
||||
androidWorkflow: androidWorkflow,
|
||||
config: globals.config,
|
||||
fuchsiaWorkflow: fuchsiaWorkflow,
|
||||
xcDevice: globals.xcdevice,
|
||||
userMessages: globals.userMessages,
|
||||
windowsWorkflow: windowsWorkflow,
|
||||
macOSWorkflow: context.get<MacOSWorkflow>(),
|
||||
operatingSystemUtils: globals.os,
|
||||
terminal: globals.terminal,
|
||||
customDevicesConfig: CustomDevicesConfig(
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
platform: globals.platform,
|
||||
),
|
||||
uwptool: UwpTool(
|
||||
artifacts: globals.artifacts,
|
||||
logger: globals.logger,
|
||||
processManager: globals.processManager,
|
||||
),
|
||||
);
|
||||
|
||||
final ELinuxDeviceDiscovery _eLinuxDeviceDiscovery = ELinuxDeviceDiscovery(
|
||||
eLinuxWorkflow: eLinuxWorkflow,
|
||||
logger: globals.logger,
|
||||
processManager: globals.processManager,
|
||||
);
|
||||
|
||||
@override
|
||||
List<DeviceDiscovery> get deviceDiscoverers => <DeviceDiscovery>[
|
||||
...super.deviceDiscoverers,
|
||||
_eLinuxDeviceDiscovery,
|
||||
];
|
||||
}
|
||||
|
||||
/// Device discovery for eLinux devices.
|
||||
///
|
||||
/// Source: [AndroidDevices] in `android_device_discovery.dart`
|
||||
class ELinuxDeviceDiscovery extends PollingDeviceDiscovery {
|
||||
ELinuxDeviceDiscovery({
|
||||
@required ELinuxWorkflow eLinuxWorkflow,
|
||||
@required ProcessManager processManager,
|
||||
@required Logger logger,
|
||||
}) : _eLinuxWorkflow = eLinuxWorkflow,
|
||||
_logger = logger,
|
||||
_processManager = processManager,
|
||||
super('eLinux devices');
|
||||
|
||||
final ELinuxWorkflow _eLinuxWorkflow;
|
||||
final Logger _logger;
|
||||
final ProcessManager _processManager;
|
||||
|
||||
@override
|
||||
bool get supportsPlatform => _eLinuxWorkflow.appliesToHostPlatform;
|
||||
|
||||
@override
|
||||
bool get canListAnything => _eLinuxWorkflow.canListDevices;
|
||||
|
||||
@override
|
||||
Future<List<Device>> pollingGetDevices({Duration timeout}) async {
|
||||
if (!canListAnything) {
|
||||
return const <Device>[];
|
||||
}
|
||||
|
||||
return <Device>[
|
||||
ELinuxDevice('eLinux',
|
||||
desktop: true,
|
||||
targetArch: _getCurrentHostPlatformArchName(),
|
||||
backendType: 'wayland',
|
||||
logger: _logger ?? globals.logger,
|
||||
processManager: _processManager ?? globals.processManager,
|
||||
operatingSystemUtils: OperatingSystemUtils(
|
||||
fileSystem: globals.fs,
|
||||
logger: _logger ?? globals.logger,
|
||||
platform: globals.platform,
|
||||
processManager: const LocalProcessManager(),
|
||||
)),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getDiagnostics() async => const <String>[];
|
||||
|
||||
String _getCurrentHostPlatformArchName() {
|
||||
final HostPlatform hostPlatform = getCurrentHostPlatform();
|
||||
return getNameForHostPlatformArch(hostPlatform);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. 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 'dart:io';
|
||||
|
||||
import 'package:flutter_tools/src/android/android_workflow.dart';
|
||||
import 'package:flutter_tools/src/base/context.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/doctor.dart';
|
||||
import 'package:flutter_tools/src/doctor_validator.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'executable.dart';
|
||||
|
||||
ELinuxWorkflow get eLinuxWorkflow => context.get<ELinuxWorkflow>();
|
||||
ELinuxValidator get eLinuxValidator => context.get<ELinuxValidator>();
|
||||
|
||||
/// See: [_DefaultDoctorValidatorsProvider] in `doctor.dart`
|
||||
class ELinuxDoctorValidatorsProvider extends DoctorValidatorsProvider {
|
||||
@override
|
||||
List<DoctorValidator> get validators {
|
||||
final List<DoctorValidator> validators =
|
||||
DoctorValidatorsProvider.defaultInstance.validators;
|
||||
return <DoctorValidator>[
|
||||
validators.first,
|
||||
eLinuxValidator,
|
||||
...validators.sublist(1)
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
List<Workflow> get workflows => <Workflow>[
|
||||
...DoctorValidatorsProvider.defaultInstance.workflows,
|
||||
eLinuxWorkflow,
|
||||
];
|
||||
}
|
||||
|
||||
/// A validator that checks for eLinux SDK installation.
|
||||
class ELinuxValidator extends DoctorValidator {
|
||||
ELinuxValidator() : super('eLinux toolchain - develop for eLinux devices');
|
||||
|
||||
bool _validatePackages(List<ValidationMessage> messages) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// See: [AndroidValidator.validate] in `android_workflow.dart`
|
||||
@override
|
||||
Future<ValidationResult> validate() async {
|
||||
final List<ValidationMessage> messages = <ValidationMessage>[];
|
||||
|
||||
final FlutterVersion version = _FlutterELinuxVersion();
|
||||
messages.add(ValidationMessage(globals.userMessages.flutterRevision(
|
||||
version.frameworkRevisionShort,
|
||||
version.frameworkAge,
|
||||
version.frameworkCommitDate,
|
||||
)));
|
||||
messages.add(ValidationMessage(
|
||||
globals.userMessages.engineRevision(version.engineRevisionShort)));
|
||||
|
||||
if (!_validatePackages(messages)) {
|
||||
return ValidationResult(ValidationType.partial, messages);
|
||||
}
|
||||
return ValidationResult(ValidationType.installed, messages);
|
||||
}
|
||||
}
|
||||
|
||||
/// The eLinux-specific implementation of a [Workflow].
|
||||
///
|
||||
/// See: [AndroidWorkflow] in `android_workflow.dart`
|
||||
class ELinuxWorkflow extends Workflow {
|
||||
ELinuxWorkflow({
|
||||
@required OperatingSystemUtils operatingSystemUtils,
|
||||
}) : _operatingSystemUtils = operatingSystemUtils;
|
||||
|
||||
final OperatingSystemUtils _operatingSystemUtils;
|
||||
|
||||
@override
|
||||
bool get appliesToHostPlatform =>
|
||||
_operatingSystemUtils.hostPlatform != HostPlatform.linux_arm64;
|
||||
|
||||
@override
|
||||
bool get canLaunchDevices => true;
|
||||
|
||||
@override
|
||||
bool get canListDevices => true;
|
||||
|
||||
@override
|
||||
bool get canListEmulators => false;
|
||||
}
|
||||
|
||||
class _FlutterELinuxVersion extends FlutterVersion {
|
||||
_FlutterELinuxVersion() : super(workingDirectory: rootPath);
|
||||
|
||||
/// See: [Cache.getVersionFor] in `cache.dart`
|
||||
String _getVersionFor(String artifactName) {
|
||||
final File versionFile = globals.fs
|
||||
.directory(rootPath)
|
||||
.childDirectory('bin')
|
||||
.childDirectory('internal')
|
||||
.childFile('$artifactName.version');
|
||||
return versionFile.existsSync()
|
||||
? versionFile.readAsStringSync().trim()
|
||||
: null;
|
||||
}
|
||||
|
||||
@override
|
||||
String get engineRevision => _getVersionFor('engine');
|
||||
|
||||
/// See: [_runGit] in `version.dart`
|
||||
String _runGit(String command) => globals.processUtils
|
||||
.runSync(command.split(' '), workingDirectory: rootPath)
|
||||
.stdout
|
||||
.trim();
|
||||
|
||||
/// This should be overriden because [FlutterVersion._latestGitCommitDate]
|
||||
/// runs the git log command in the `Cache.flutterRoot` directory.
|
||||
@override
|
||||
String get frameworkCommitDate => _runGit(
|
||||
'git -c log.showSignature=false log -n 1 --pretty=format:%ad --date=iso');
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// 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:file/file.dart';
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cmake.dart';
|
||||
import 'package:flutter_tools/src/flutter_application_package.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'elinux_cmake_project.dart';
|
||||
|
||||
class ELinuxApplicationPackageFactory extends FlutterApplicationPackageFactory {
|
||||
ELinuxApplicationPackageFactory()
|
||||
: super(
|
||||
androidSdk: globals.androidSdk,
|
||||
processManager: globals.processManager,
|
||||
logger: globals.logger,
|
||||
userMessages: globals.userMessages,
|
||||
fileSystem: globals.fs,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<ApplicationPackage> getPackageForPlatform(
|
||||
TargetPlatform platform, {
|
||||
BuildInfo buildInfo,
|
||||
File applicationBinary,
|
||||
}) async {
|
||||
if (platform == TargetPlatform.tester) {
|
||||
return applicationBinary == null
|
||||
? ELinuxApp.fromELinuxProject(FlutterProject.current())
|
||||
: ELinuxApp.fromPrebuiltApp(applicationBinary);
|
||||
}
|
||||
return super.getPackageForPlatform(platform,
|
||||
buildInfo: buildInfo, applicationBinary: applicationBinary);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ELinuxApp extends ApplicationPackage {
|
||||
ELinuxApp({@required String projectBundleId}) : super(id: projectBundleId);
|
||||
|
||||
factory ELinuxApp.fromELinuxProject(FlutterProject project) {
|
||||
return BuildableELinuxApp(
|
||||
project: ELinuxProject.fromFlutter(project),
|
||||
);
|
||||
}
|
||||
|
||||
factory ELinuxApp.fromPrebuiltApp(FileSystemEntity applicationBinary) {
|
||||
return PrebuiltELinuxApp(
|
||||
executable: applicationBinary.path,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get displayName => id;
|
||||
|
||||
String executable(BuildMode buildMode, String targetArch);
|
||||
}
|
||||
|
||||
class PrebuiltELinuxApp extends ELinuxApp {
|
||||
PrebuiltELinuxApp({
|
||||
@required String executable,
|
||||
}) : _executable = executable,
|
||||
super(projectBundleId: executable);
|
||||
|
||||
final String _executable;
|
||||
|
||||
@override
|
||||
String executable(BuildMode buildMode, String targetArch) => _executable;
|
||||
|
||||
@override
|
||||
String get name => _executable;
|
||||
}
|
||||
|
||||
class BuildableELinuxApp extends ELinuxApp {
|
||||
BuildableELinuxApp({@required this.project})
|
||||
: super(projectBundleId: project.parent.manifest.appName);
|
||||
|
||||
final ELinuxProject project;
|
||||
|
||||
@override
|
||||
String executable(BuildMode buildMode, String targetArch) {
|
||||
final String binaryName = getCmakeExecutableName(project);
|
||||
return globals.fs.path.join(
|
||||
'build/elinux/',
|
||||
targetArch,
|
||||
getNameForBuildMode(buildMode),
|
||||
'bundle',
|
||||
binaryName,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String get name => project.parent.manifest.appName;
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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:file/file.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/terminal.dart';
|
||||
import 'package:flutter_tools/src/build_system/targets/web.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/dart/language_version.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/flutter_plugins.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/platform_plugins.dart';
|
||||
import 'package:flutter_tools/src/plugins.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'elinux_cmake_project.dart';
|
||||
|
||||
/// Contains the parameters to template a elinux plugin.
|
||||
///
|
||||
/// The [name] of the plugin is required. Either [dartPluginClass] or
|
||||
/// [pluginClass] are required. [pluginClass] will be the entry point to the
|
||||
/// plugin's native code. If [pluginClass] is not empty, the [fileName]
|
||||
/// containing the plugin's code is required.
|
||||
///
|
||||
/// Source: [LinuxPlugin] in `platform_plugins.dart`
|
||||
class ELinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
|
||||
ELinuxPlugin({
|
||||
@required this.name,
|
||||
@required this.directory,
|
||||
this.pluginClass,
|
||||
this.dartPluginClass,
|
||||
this.fileName,
|
||||
}) : assert(pluginClass != null || dartPluginClass != null);
|
||||
|
||||
factory ELinuxPlugin.fromYaml(
|
||||
String name, Directory directory, YamlMap yaml) {
|
||||
assert(validate(yaml));
|
||||
return ELinuxPlugin(
|
||||
name: name,
|
||||
directory: directory,
|
||||
pluginClass: yaml[kPluginClass] as String,
|
||||
dartPluginClass: yaml[kDartPluginClass] as String,
|
||||
fileName: yaml['fileName'] as String,
|
||||
);
|
||||
}
|
||||
|
||||
static bool validate(YamlMap yaml) {
|
||||
if (yaml == null) {
|
||||
return false;
|
||||
}
|
||||
return yaml[kPluginClass] is String || yaml[kDartPluginClass] is String;
|
||||
}
|
||||
|
||||
static const String kConfigKey = 'elinux';
|
||||
|
||||
final String name;
|
||||
final Directory directory;
|
||||
final String pluginClass;
|
||||
final String dartPluginClass;
|
||||
final String fileName;
|
||||
|
||||
@override
|
||||
bool isNative() => pluginClass != null;
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'name': name,
|
||||
if (pluginClass != null) 'class': pluginClass,
|
||||
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass,
|
||||
'file': fileName,
|
||||
};
|
||||
}
|
||||
|
||||
File get projectFile => directory.childFile('project_def.prop');
|
||||
|
||||
final RegExp _propertyFormat = RegExp(r'(\S+)\s*\+?=(.*)');
|
||||
|
||||
Map<String, String> _properties;
|
||||
|
||||
String getProperty(String key) {
|
||||
if (_properties == null) {
|
||||
if (!projectFile.existsSync()) {
|
||||
return null;
|
||||
}
|
||||
_properties = <String, String>{};
|
||||
|
||||
for (final String line in projectFile.readAsLinesSync()) {
|
||||
final Match match = _propertyFormat.firstMatch(line);
|
||||
if (match == null) {
|
||||
continue;
|
||||
}
|
||||
final String key = match.group(1);
|
||||
final String value = match.group(2).trim();
|
||||
_properties[key] = value;
|
||||
}
|
||||
}
|
||||
return _properties.containsKey(key) ? _properties[key] : null;
|
||||
}
|
||||
|
||||
List<String> getPropertyAsAbsolutePaths(String key) {
|
||||
final String property = getProperty(key);
|
||||
if (property == null) {
|
||||
return <String>[];
|
||||
}
|
||||
|
||||
final List<String> paths = <String>[];
|
||||
for (final String element in property.split(' ')) {
|
||||
if (globals.fs.path.isAbsolute(element)) {
|
||||
paths.add(element);
|
||||
} else {
|
||||
paths.add(globals.fs.path
|
||||
.normalize(globals.fs.path.join(directory.path, element)));
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
|
||||
/// Any [FlutterCommand] that invokes [usesPubOption] or [targetFile] should
|
||||
/// depend on this mixin to ensure plugins are correctly configured for eLinux.
|
||||
///
|
||||
/// See: [FlutterCommand.verifyThenRunCommand] in `flutter_command.dart`
|
||||
mixin ELinuxExtension on FlutterCommand {
|
||||
String _entrypoint;
|
||||
|
||||
bool get _usesTargetOption => argParser.options.containsKey('target');
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
|
||||
if (super.shouldRunPub) {
|
||||
// TODO(swift-kim): Should run pub get first before injecting plugins.
|
||||
await ensureReadyForELinuxTooling(FlutterProject.current());
|
||||
}
|
||||
if (_usesTargetOption) {
|
||||
_entrypoint =
|
||||
await _createEntrypoint(FlutterProject.current(), super.targetFile);
|
||||
}
|
||||
return super.verifyThenRunCommand(commandPath);
|
||||
}
|
||||
|
||||
@override
|
||||
String get targetFile => _entrypoint ?? super.targetFile;
|
||||
}
|
||||
|
||||
/// Creates an entrypoint wrapper of [targetFile] and returns its path.
|
||||
/// This effectively adds support for Dart plugins.
|
||||
///
|
||||
/// Source: [WebEntrypointTarget.build] in `web.dart`
|
||||
Future<String> _createEntrypoint(
|
||||
FlutterProject project, String targetFile) async {
|
||||
final List<ELinuxPlugin> dartPlugins =
|
||||
await findELinuxPlugins(project, dartOnly: true);
|
||||
if (dartPlugins.isEmpty) {
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
|
||||
if (!eLinuxProject.existsSync()) {
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
final File entrypoint = eLinuxProject.managedDirectory.childFile('main.dart')
|
||||
..createSync(recursive: true);
|
||||
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
|
||||
project.directory.childFile('.packages'),
|
||||
logger: globals.logger,
|
||||
);
|
||||
final FlutterProject flutterProject = FlutterProject.current();
|
||||
final LanguageVersion languageVersion = determineLanguageVersion(
|
||||
globals.fs.file(targetFile),
|
||||
packageConfig[flutterProject.manifest.appName],
|
||||
Cache.flutterRoot,
|
||||
);
|
||||
|
||||
final Uri mainUri = globals.fs.file(targetFile).absolute.uri;
|
||||
final String mainImport =
|
||||
packageConfig.toPackageUri(mainUri)?.toString() ?? mainUri.toString();
|
||||
|
||||
entrypoint.writeAsStringSync('''
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
// @dart=${languageVersion.major}.${languageVersion.minor}
|
||||
|
||||
import '$mainImport' as entrypoint;
|
||||
import 'generated_plugin_registrant.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
registerPlugins();
|
||||
entrypoint.main();
|
||||
}
|
||||
''');
|
||||
return entrypoint.path;
|
||||
}
|
||||
|
||||
const List<String> _knownPlugins = <String>[
|
||||
'audioplayers',
|
||||
'battery',
|
||||
'battery_plus',
|
||||
'camera',
|
||||
'connectivity',
|
||||
'device_info',
|
||||
'flutter_tts',
|
||||
'image_picker',
|
||||
'integration_test',
|
||||
'package_info',
|
||||
'package_info_plus',
|
||||
'path_provider',
|
||||
'permission_handler',
|
||||
'sensors',
|
||||
'sensors_plus',
|
||||
'share',
|
||||
'shared_preferences',
|
||||
'url_launcher',
|
||||
'video_player',
|
||||
'webview_flutter',
|
||||
'wifi_info_flutter',
|
||||
];
|
||||
|
||||
/// This function must be called whenever [FlutterProject.regeneratePlatformSpecificTooling]
|
||||
/// or [FlutterProject.ensureReadyForPlatformSpecificTooling] is called.
|
||||
///
|
||||
/// See: [FlutterProject.ensureReadyForPlatformSpecificTooling] in `project.dart`
|
||||
Future<void> ensureReadyForELinuxTooling(FlutterProject project) async {
|
||||
if (!project.directory.existsSync() ||
|
||||
project.hasExampleApp ||
|
||||
project.isPlugin) {
|
||||
return;
|
||||
}
|
||||
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
|
||||
await eLinuxProject.ensureReadyForPlatformSpecificTooling();
|
||||
|
||||
await injectELinuxPlugins(project);
|
||||
}
|
||||
|
||||
/// See: [injectPlugins] in `plugins.dart`
|
||||
Future<void> injectELinuxPlugins(FlutterProject project) async {
|
||||
final ELinuxProject eLinuxProject = ELinuxProject.fromFlutter(project);
|
||||
if (eLinuxProject.existsSync()) {
|
||||
final List<ELinuxPlugin> dartPlugins =
|
||||
await findELinuxPlugins(project, dartOnly: true);
|
||||
final List<ELinuxPlugin> nativePlugins =
|
||||
await findELinuxPlugins(project, nativeOnly: true);
|
||||
_writeDartPluginRegistrant(eLinuxProject.managedDirectory, dartPlugins);
|
||||
_writePluginCmakefileTemplate(
|
||||
eLinuxProject.managedDirectory, nativePlugins);
|
||||
}
|
||||
|
||||
final List<String> plugins =
|
||||
(await findPlugins(project)).map((Plugin p) => p.name).toList();
|
||||
for (final String plugin in plugins) {
|
||||
final String eLinuxPlugin = '${plugin}_elinux';
|
||||
if (_knownPlugins.contains(plugin) && !plugins.contains(eLinuxPlugin)) {
|
||||
globals.printStatus(
|
||||
'$eLinuxPlugin is available on pub.dev. Did you forget to add to pubspec.yaml?',
|
||||
color: TerminalColor.yellow,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Source: [findPlugins] in `plugins.dart`
|
||||
Future<List<ELinuxPlugin>> findELinuxPlugins(
|
||||
FlutterProject project, {
|
||||
bool dartOnly = false,
|
||||
bool nativeOnly = false,
|
||||
bool throwOnError = true,
|
||||
}) async {
|
||||
final List<ELinuxPlugin> plugins = <ELinuxPlugin>[];
|
||||
final File packagesFile = project.directory.childFile('.packages');
|
||||
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
|
||||
packagesFile,
|
||||
logger: globals.logger,
|
||||
throwOnError: throwOnError,
|
||||
);
|
||||
for (final Package package in packageConfig.packages) {
|
||||
final Uri packageRoot = package.packageUriRoot.resolve('..');
|
||||
final ELinuxPlugin plugin = _pluginFromPackage(package.name, packageRoot);
|
||||
if (plugin == null) {
|
||||
continue;
|
||||
} else if (nativeOnly && plugin.pluginClass == null) {
|
||||
continue;
|
||||
} else if (dartOnly && plugin.dartPluginClass == null) {
|
||||
continue;
|
||||
}
|
||||
plugins.add(plugin);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
/// Source: [_pluginFromPackage] in `plugins.dart`
|
||||
ELinuxPlugin _pluginFromPackage(String name, Uri packageRoot) {
|
||||
final String pubspecPath =
|
||||
globals.fs.path.fromUri(packageRoot.resolve('pubspec.yaml'));
|
||||
if (!globals.fs.isFileSync(pubspecPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
dynamic pubspec;
|
||||
try {
|
||||
pubspec = loadYaml(globals.fs.file(pubspecPath).readAsStringSync());
|
||||
} on YamlException catch (err) {
|
||||
globals.printTrace('Failed to parse plugin manifest for $name: $err');
|
||||
}
|
||||
if (pubspec == null) {
|
||||
return null;
|
||||
}
|
||||
final dynamic flutterConfig = pubspec['flutter'];
|
||||
if (flutterConfig == null || !(flutterConfig.containsKey('plugin') as bool)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Directory packageDir = globals.fs.directory(packageRoot);
|
||||
globals.printTrace('Found plugin $name at ${packageDir.path}');
|
||||
|
||||
final YamlMap pluginYaml = flutterConfig['plugin'] as YamlMap;
|
||||
if (pluginYaml == null || pluginYaml['platforms'] == null) {
|
||||
return null;
|
||||
}
|
||||
final YamlMap platformsYaml = pluginYaml['platforms'] as YamlMap;
|
||||
if (platformsYaml == null || platformsYaml[ELinuxPlugin.kConfigKey] == null) {
|
||||
return null;
|
||||
}
|
||||
return ELinuxPlugin.fromYaml(
|
||||
name,
|
||||
packageDir.childDirectory('elinux'),
|
||||
platformsYaml[ELinuxPlugin.kConfigKey] as YamlMap,
|
||||
);
|
||||
}
|
||||
|
||||
/// See: [_writeWebPluginRegistrant] in `plugins.dart`
|
||||
void _writeDartPluginRegistrant(
|
||||
Directory registryDirectory,
|
||||
List<ELinuxPlugin> plugins,
|
||||
) {
|
||||
final List<Map<String, dynamic>> pluginConfigs =
|
||||
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': pluginConfigs,
|
||||
};
|
||||
_renderTemplateToFile(
|
||||
'''
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
{{#plugins}}
|
||||
import 'package:{{name}}/{{name}}.dart';
|
||||
{{/plugins}}
|
||||
|
||||
// ignore: public_member_api_docs
|
||||
void registerPlugins() {
|
||||
{{#plugins}}
|
||||
{{dartPluginClass}}.register();
|
||||
{{/plugins}}
|
||||
}
|
||||
''',
|
||||
context,
|
||||
registryDirectory.childFile('generated_plugin_registrant.dart').path,
|
||||
);
|
||||
}
|
||||
|
||||
/// See: [_writeWindowsPluginFiles] in `plugins.dart`
|
||||
void _writePluginCmakefileTemplate(
|
||||
Directory registryDirectory,
|
||||
List<ELinuxPlugin> plugins,
|
||||
) {
|
||||
final List<Map<String, dynamic>> pluginConfigs =
|
||||
plugins.map((ELinuxPlugin plugin) => plugin.toMap()).toList();
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': pluginConfigs,
|
||||
};
|
||||
_renderTemplateToFile(
|
||||
'''
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
|
||||
#define GENERATED_PLUGIN_REGISTRANT_
|
||||
|
||||
#include <flutter/plugin_registry.h>
|
||||
|
||||
// Registers Flutter plugins.
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry);
|
||||
|
||||
#endif // GENERATED_PLUGIN_REGISTRANT_
|
||||
''',
|
||||
context,
|
||||
registryDirectory.childFile('generated_plugin_registrant.h').path,
|
||||
);
|
||||
_renderTemplateToFile(
|
||||
'''
|
||||
//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
}
|
||||
''',
|
||||
context,
|
||||
registryDirectory.childFile('generated_plugin_registrant.cc').path,
|
||||
);
|
||||
_renderTemplateToFile(
|
||||
r'''
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
{{#plugins}}
|
||||
{{name}}
|
||||
{{/plugins}}
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
|
||||
add_subdirectory(
|
||||
${USER_PROJECT_PATH}/flutter/plugins/${plugin}/elinux plugins/${plugin})
|
||||
|
||||
target_link_libraries(${TARGET}
|
||||
PRIVATE
|
||||
${plugin}_plugin
|
||||
)
|
||||
|
||||
list(APPEND PLUGIN_BUNDLED_LIBRARIES
|
||||
${PROJECT_BINARY_DIR}/plugins/${plugin}/lib${plugin}_plugin.so
|
||||
)
|
||||
endforeach(plugin)
|
||||
''',
|
||||
context,
|
||||
registryDirectory.childFile('generated_plugins.cmake').path,
|
||||
);
|
||||
}
|
||||
|
||||
/// Source: [_renderTemplateToFile] in `plugins.dart` (exact copy)
|
||||
void _renderTemplateToFile(String template, dynamic context, String filePath) {
|
||||
final String renderedTemplate = globals.templateRenderer
|
||||
.renderString(template, context, htmlEscapeValues: false);
|
||||
final File file = globals.fs.file(filePath);
|
||||
file.createSync(recursive: true);
|
||||
file.writeAsStringSync(renderedTemplate);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright 2021 Sony Group Corporation. All rights reserved.
|
||||
// Copyright 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
// 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 'dart:io';
|
||||
|
||||
import 'package:flutter_tools/executable.dart' as flutter;
|
||||
import 'package:flutter_tools/runner.dart' as runner;
|
||||
import 'package:flutter_tools/src/application_package.dart';
|
||||
import 'package:flutter_tools/src/base/context.dart';
|
||||
import 'package:flutter_tools/src/base/template.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/config.dart';
|
||||
import 'package:flutter_tools/src/commands/devices.dart';
|
||||
import 'package:flutter_tools/src/commands/doctor.dart';
|
||||
import 'package:flutter_tools/src/commands/emulators.dart';
|
||||
import 'package:flutter_tools/src/commands/format.dart';
|
||||
import 'package:flutter_tools/src/commands/generate_localizations.dart';
|
||||
import 'package:flutter_tools/src/commands/install.dart';
|
||||
import 'package:flutter_tools/src/commands/logs.dart';
|
||||
import 'package:flutter_tools/src/commands/screenshot.dart';
|
||||
import 'package:flutter_tools/src/commands/symbolize.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/doctor.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/isolated/mustache_template.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:path/path.dart';
|
||||
|
||||
import 'commands/analyze.dart';
|
||||
import 'commands/attach.dart';
|
||||
import 'commands/build.dart';
|
||||
import 'commands/clean.dart';
|
||||
import 'commands/create.dart';
|
||||
import 'commands/drive.dart';
|
||||
import 'commands/packages.dart';
|
||||
import 'commands/precache.dart';
|
||||
import 'commands/run.dart';
|
||||
import 'commands/test.dart';
|
||||
import 'elinux_cache.dart';
|
||||
import 'elinux_device_discovery.dart';
|
||||
import 'elinux_doctor.dart';
|
||||
import 'elinux_package.dart';
|
||||
|
||||
/// Main entry point for commands.
|
||||
///
|
||||
/// Source: [flutter.main] in `executable.dart` (some commands and options were omitted)
|
||||
Future<void> main(List<String> args) async {
|
||||
final bool veryVerbose = args.contains('-vv');
|
||||
final bool verbose =
|
||||
args.contains('-v') || args.contains('--verbose') || veryVerbose;
|
||||
|
||||
final bool doctor = (args.isNotEmpty && args.first == 'doctor') ||
|
||||
(args.length == 2 && verbose && args.last == 'doctor');
|
||||
final bool help = args.contains('-h') ||
|
||||
args.contains('--help') ||
|
||||
(args.isNotEmpty && args.first == 'help') ||
|
||||
(args.length == 1 && verbose);
|
||||
final bool muteCommandLogging = (help || doctor) && !veryVerbose;
|
||||
final bool verboseHelp = help && verbose;
|
||||
|
||||
final bool hasSpecifiedDeviceId =
|
||||
args.contains('-d') || args.contains('--device-id');
|
||||
|
||||
args = <String>[
|
||||
'--suppress-analytics', // Suppress flutter analytics by default.
|
||||
'--no-version-check',
|
||||
if (!hasSpecifiedDeviceId) ...<String>['--device-id', 'elinux'],
|
||||
...args,
|
||||
];
|
||||
|
||||
Cache.flutterRoot = join(rootPath, 'flutter');
|
||||
|
||||
await runner.run(
|
||||
args,
|
||||
() => <FlutterCommand>[
|
||||
// Commands directly from flutter_tools.
|
||||
ConfigCommand(verboseHelp: verboseHelp),
|
||||
DevicesCommand(verboseHelp: verboseHelp),
|
||||
DoctorCommand(verbose: verbose),
|
||||
EmulatorsCommand(),
|
||||
FormatCommand(),
|
||||
GenerateLocalizationsCommand(
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
),
|
||||
InstallCommand(),
|
||||
LogsCommand(),
|
||||
ScreenshotCommand(),
|
||||
SymbolizeCommand(stdio: globals.stdio, fileSystem: globals.fs),
|
||||
// Commands extended for ELinux.
|
||||
ELinuxAnalyzeCommand(verboseHelp: verboseHelp),
|
||||
ELinuxAttachCommand(verboseHelp: verboseHelp),
|
||||
ELinuxBuildCommand(verboseHelp: verboseHelp),
|
||||
ELinuxCleanCommand(verbose: verbose),
|
||||
ELinuxCreateCommand(verboseHelp: verboseHelp),
|
||||
ELinuxDriveCommand(verboseHelp: verboseHelp),
|
||||
ELinuxPackagesCommand(),
|
||||
ELinuxPrecacheCommand(
|
||||
verboseHelp: verboseHelp,
|
||||
cache: globals.cache,
|
||||
logger: globals.logger,
|
||||
platform: globals.platform,
|
||||
featureFlags: featureFlags,
|
||||
),
|
||||
ELinuxRunCommand(verboseHelp: verboseHelp),
|
||||
ELinuxTestCommand(verboseHelp: verboseHelp),
|
||||
],
|
||||
verbose: verbose,
|
||||
verboseHelp: verboseHelp,
|
||||
muteCommandLogging: muteCommandLogging,
|
||||
reportCrashes: false,
|
||||
overrides: <Type, Generator>{
|
||||
Cache: () => ELinuxFlutterCache(
|
||||
fileSystem: globals.fs,
|
||||
logger: globals.logger,
|
||||
platform: globals.platform,
|
||||
osUtils: globals.os,
|
||||
),
|
||||
TemplateRenderer: () => const MustacheTemplateRenderer(),
|
||||
ApplicationPackageFactory: () => ELinuxApplicationPackageFactory(),
|
||||
DeviceManager: () => ELinuxDeviceManager(),
|
||||
DoctorValidatorsProvider: () => ELinuxDoctorValidatorsProvider(),
|
||||
ELinuxWorkflow: () => ELinuxWorkflow(
|
||||
operatingSystemUtils: globals.os,
|
||||
),
|
||||
ELinuxValidator: () => ELinuxValidator(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// See: [Cache.defaultFlutterRoot] in `cache.dart`
|
||||
String get rootPath {
|
||||
final String scriptPath = Platform.script.toFilePath();
|
||||
return normalize(join(
|
||||
scriptPath,
|
||||
scriptPath.endsWith('.snapshot') ? '../../..' : '../..',
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
name: flutter_elinux
|
||||
description: Flutter application build tools for Embedded Linux devices
|
||||
homepage: https://github.com/sony/flutter-embedded-linux
|
||||
version: 2.2.1
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter_tools:
|
||||
path: flutter/packages/flutter_tools
|
||||
file: # inherit from flutter_tools
|
||||
meta:
|
||||
package_config:
|
||||
path:
|
||||
process:
|
||||
xml:
|
||||
yaml:
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mockito:
|
||||
pedantic:
|
||||
test:
|
||||
@@ -0,0 +1,104 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(runner LANGUAGES CXX)
|
||||
|
||||
set(BINARY_NAME "{{projectName}}")
|
||||
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
|
||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||
|
||||
# Root filesystem for cross-building.
|
||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif()
|
||||
|
||||
# Configure build options.
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||
STRING "Flutter build mode" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||
"Debug" "Profile" "Release")
|
||||
endif()
|
||||
|
||||
# Configure build option to target backend.
|
||||
if (NOT FLUTTER_TARGET_BACKEND_TYPE)
|
||||
set(FLUTTER_TARGET_BACKEND_TYPE "wayland" CACHE
|
||||
STRING "Flutter target backend type" FORCE)
|
||||
set_property(CACHE FLUTTER_TARGET_BACKEND_TYPE PROPERTY STRINGS
|
||||
"wayland" "gbm" "eglstream" "x11")
|
||||
endif()
|
||||
|
||||
# Compilation settings that should be applied to most targets.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_17)
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||
endfunction()
|
||||
|
||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||
|
||||
# Flutter library and tool build rules.
|
||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||
|
||||
# Application build
|
||||
add_subdirectory("runner")
|
||||
|
||||
# Generated plugin build rules, which manage building the plugins and adding
|
||||
# them to the application.
|
||||
include(flutter/generated_plugins.cmake)
|
||||
|
||||
# === Installation ===
|
||||
# By default, "installing" just makes a relocatable bundle in the build
|
||||
# directory.
|
||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||
endif()
|
||||
|
||||
# Start with a clean build bundle directory every time.
|
||||
install(CODE "
|
||||
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
||||
" COMPONENT Runtime)
|
||||
|
||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
|
||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
install(FILES "${FLUTTER_LIBRARY}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
install(FILES "${FLUTTER_EMBEDDER_LIBRARY}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
|
||||
if(PLUGIN_BUNDLED_LIBRARIES)
|
||||
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
|
||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||
# from a previous install.
|
||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||
install(CODE "
|
||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||
" COMPONENT Runtime)
|
||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||
|
||||
# Install the AOT library on non-Debug builds only.
|
||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||
COMPONENT Runtime)
|
||||
endif()
|
||||
@@ -0,0 +1,108 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||
|
||||
# Configuration provided via flutter tool.
|
||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||
|
||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
|
||||
|
||||
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
||||
# which isn't available in 3.10.
|
||||
function(list_prepend LIST_NAME PREFIX)
|
||||
set(NEW_LIST "")
|
||||
foreach(element ${${LIST_NAME}})
|
||||
list(APPEND NEW_LIST "${PREFIX}${element}")
|
||||
endforeach(element)
|
||||
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# === Flutter Library ===
|
||||
# System-level dependencies.
|
||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_engine.so")
|
||||
if(FLUTTER_TARGET_BACKEND_TYPE MATCHES "gbm")
|
||||
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_gbm.so")
|
||||
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "eglstream")
|
||||
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_eglstream.so")
|
||||
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "x11")
|
||||
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_x11.so")
|
||||
else()
|
||||
set(FLUTTER_EMBEDDER_LIBRARY "${EPHEMERAL_DIR}/libflutter_elinux_wayland.so")
|
||||
endif()
|
||||
|
||||
# Published to parent scope for install step.
|
||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||
set(FLUTTER_EMBEDDER_LIBRARY ${FLUTTER_EMBEDDER_LIBRARY} PARENT_SCOPE)
|
||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/elinux/" PARENT_SCOPE)
|
||||
set(AOT_LIBRARY "${EPHEMERAL_DIR}/libapp.so" PARENT_SCOPE)
|
||||
|
||||
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||
"flutter_export.h"
|
||||
"flutter_plugin_registrar.h"
|
||||
"flutter_messenger.h"
|
||||
"flutter_texture_registrar.h"
|
||||
"flutter_elinux.h"
|
||||
"flutter_platform_views.h"
|
||||
)
|
||||
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/")
|
||||
add_library(flutter INTERFACE)
|
||||
target_include_directories(flutter INTERFACE
|
||||
"${EPHEMERAL_DIR}"
|
||||
)
|
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
||||
target_link_libraries(flutter INTERFACE "${FLUTTER_EMBEDDER_LIBRARY}")
|
||||
add_dependencies(flutter flutter_assemble)
|
||||
|
||||
# === Wrapper ===
|
||||
list(APPEND CPP_WRAPPER_SOURCES_CORE
|
||||
"core_implementations.cc"
|
||||
"standard_codec.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
|
||||
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
|
||||
"plugin_registrar.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
|
||||
list(APPEND CPP_WRAPPER_SOURCES_APP
|
||||
"flutter_engine.cc"
|
||||
"flutter_view_controller.cc"
|
||||
)
|
||||
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
|
||||
|
||||
# Wrapper sources needed for a plugin.
|
||||
add_library(flutter_wrapper_plugin STATIC
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_PLUGIN}
|
||||
)
|
||||
apply_standard_settings(flutter_wrapper_plugin)
|
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
|
||||
target_include_directories(flutter_wrapper_plugin PUBLIC
|
||||
"${WRAPPER_ROOT}/include"
|
||||
)
|
||||
add_dependencies(flutter_wrapper_plugin flutter_assemble)
|
||||
|
||||
# Wrapper sources needed for the runner.
|
||||
add_library(flutter_wrapper_app STATIC
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_APP}
|
||||
)
|
||||
apply_standard_settings(flutter_wrapper_app)
|
||||
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
|
||||
target_include_directories(flutter_wrapper_app PUBLIC
|
||||
"${WRAPPER_ROOT}/include"
|
||||
)
|
||||
add_dependencies(flutter_wrapper_app flutter_assemble)
|
||||
|
||||
add_custom_target(flutter_assemble DEPENDS
|
||||
"${FLUTTER_LIBRARY}"
|
||||
"${FLUTTER_EMBEDDER_LIBRARY}"
|
||||
${FLUTTER_LIBRARY_HEADERS}
|
||||
${CPP_WRAPPER_SOURCES_CORE}
|
||||
${CPP_WRAPPER_SOURCES_PLUGIN}
|
||||
${CPP_WRAPPER_SOURCES_APP}
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(runner LANGUAGES CXX)
|
||||
|
||||
if(FLUTTER_TARGET_BACKEND_TYPE MATCHES "gbm")
|
||||
add_definitions(-DFLUTTER_TARGET_BACKEND_GBM)
|
||||
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "eglstream")
|
||||
add_definitions(-DFLUTTER_TARGET_BACKEND_EGLSTREAM)
|
||||
elseif(FLUTTER_TARGET_BACKEND_TYPE MATCHES "x11")
|
||||
add_definitions(-DFLUTTER_TARGET_BACKEND_X11)
|
||||
else()
|
||||
add_definitions(-DFLUTTER_TARGET_BACKEND_WAYLAND)
|
||||
endif()
|
||||
|
||||
add_executable(${BINARY_NAME}
|
||||
"flutter_window.cc"
|
||||
"main.cc"
|
||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||
)
|
||||
apply_standard_settings(${BINARY_NAME})
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
|
||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||
@@ -0,0 +1,367 @@
|
||||
// Copyright 2021 Sony Corporation. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMMAND_OPTIONS_
|
||||
#define COMMAND_OPTIONS_
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// todo: Supports other types besides int, string.
|
||||
|
||||
namespace commandline {
|
||||
|
||||
namespace {
|
||||
constexpr char kOptionStyleNormal[] = "--";
|
||||
constexpr char kOptionStyleShort[] = "-";
|
||||
constexpr char kOptionValueForHelpMessage[] = "=<value>";
|
||||
} // namespace
|
||||
|
||||
class Exception : public std::exception {
|
||||
public:
|
||||
Exception(const std::string& msg) : msg_(msg) {}
|
||||
~Exception() throw() {}
|
||||
|
||||
const char* what() const throw() { return msg_.c_str(); }
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
};
|
||||
|
||||
class CommandOptions {
|
||||
public:
|
||||
CommandOptions() = default;
|
||||
~CommandOptions() = default;
|
||||
|
||||
void AddWithoutValue(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, bool required) {
|
||||
Add<std::string, ReaderString>(name, short_name, description, "",
|
||||
ReaderString(), required, false);
|
||||
}
|
||||
|
||||
void AddInt(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, const int& default_value,
|
||||
bool required) {
|
||||
Add<int, ReaderInt>(name, short_name, description, default_value,
|
||||
ReaderInt(), required, true);
|
||||
}
|
||||
|
||||
void AddString(const std::string& name, const std::string& short_name,
|
||||
const std::string& description,
|
||||
const std::string& default_value, bool required) {
|
||||
Add<std::string, ReaderString>(name, short_name, description, default_value,
|
||||
ReaderString(), required, true);
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void Add(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, const T default_value,
|
||||
F reader = F(), bool required = true, bool required_value = true) {
|
||||
if (options_.find(name) != options_.end()) {
|
||||
std::cerr << "Already registered option: " << name << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lut_short_options_.find(short_name) != lut_short_options_.end()) {
|
||||
std::cerr << short_name << "is already registered" << std::endl;
|
||||
return;
|
||||
}
|
||||
lut_short_options_[short_name] = name;
|
||||
|
||||
options_[name] = std::make_unique<OptionValueReader<T, F>>(
|
||||
name, short_name, description, default_value, reader, required,
|
||||
required_value);
|
||||
|
||||
// register to show help message.
|
||||
registration_order_options_.push_back(options_[name].get());
|
||||
}
|
||||
|
||||
bool Exist(const std::string& name) {
|
||||
auto itr = options_.find(name);
|
||||
return itr != options_.end() && itr->second->HasValue();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& GetValue(const std::string& name) {
|
||||
auto itr = options_.find(name);
|
||||
if (itr == options_.end()) {
|
||||
throw Exception("Not found: " + name);
|
||||
}
|
||||
|
||||
auto* option_value = dynamic_cast<const OptionValue<T>*>(itr->second.get());
|
||||
if (!option_value) {
|
||||
throw Exception("Type mismatch: " + name);
|
||||
}
|
||||
return option_value->GetValue();
|
||||
}
|
||||
|
||||
bool Parse(int argc, const char* const* argv) {
|
||||
if (argc < 1) {
|
||||
errors_.push_back("No options");
|
||||
return false;
|
||||
}
|
||||
|
||||
command_name_ = argv[0];
|
||||
for (auto i = 1; i < argc; i++) {
|
||||
const std::string arg(argv[i]);
|
||||
|
||||
// normal options: e.g. --bundle=/data/sample/bundle --fullscreen
|
||||
if (arg.length() > 2 &&
|
||||
arg.substr(0, 2).compare(kOptionStyleNormal) == 0) {
|
||||
const size_t option_value_len = arg.find("=") != std::string::npos
|
||||
? (arg.length() - arg.find("="))
|
||||
: 0;
|
||||
const bool has_value = option_value_len != 0;
|
||||
std::string option_name =
|
||||
arg.substr(2, arg.length() - 2 - option_value_len);
|
||||
|
||||
if (options_.find(option_name) == options_.end()) {
|
||||
errors_.push_back("Not found option: " + option_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!has_value && options_[option_name]->IsRequiredValue()) {
|
||||
errors_.push_back(option_name + " requres an option value");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (has_value && !options_[option_name]->IsRequiredValue()) {
|
||||
errors_.push_back(option_name + " doesn't requres an option value");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (has_value) {
|
||||
SetOptionValue(option_name, arg.substr(arg.find("=") + 1));
|
||||
} else {
|
||||
SetOption(option_name);
|
||||
}
|
||||
}
|
||||
// short options: e.g. -f /foo/file.txt -h 640 -abc
|
||||
else if (arg.length() > 1 &&
|
||||
arg.substr(0, 1).compare(kOptionStyleShort) == 0) {
|
||||
for (size_t j = 1; j < arg.length(); j++) {
|
||||
const std::string option_name{argv[i][j]};
|
||||
|
||||
if (lut_short_options_.find(option_name) ==
|
||||
lut_short_options_.end()) {
|
||||
errors_.push_back("Not found short option: " + option_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == arg.length() - 1 &&
|
||||
options_[lut_short_options_[option_name]]->IsRequiredValue()) {
|
||||
if (i == argc - 1) {
|
||||
errors_.push_back("Invalid format option: " + option_name);
|
||||
break;
|
||||
}
|
||||
SetOptionValue(lut_short_options_[option_name], argv[++i]);
|
||||
} else {
|
||||
SetOption(lut_short_options_[option_name]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errors_.push_back("Invalid format option: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < registration_order_options_.size(); i++) {
|
||||
if (registration_order_options_[i]->IsRequired() &&
|
||||
!registration_order_options_[i]->HasValue()) {
|
||||
errors_.push_back(
|
||||
std::string(registration_order_options_[i]->GetName()) +
|
||||
" option is mandatory.");
|
||||
}
|
||||
}
|
||||
|
||||
return errors_.size() == 0;
|
||||
}
|
||||
|
||||
std::string GetError() { return errors_.size() > 0 ? errors_[0] : ""; }
|
||||
|
||||
std::vector<std::string>& GetErrors() { return errors_; }
|
||||
|
||||
std::string ShowHelp() {
|
||||
std::ostringstream ostream;
|
||||
|
||||
ostream << "Usage: " << command_name_ << " ";
|
||||
for (size_t i = 0; i < registration_order_options_.size(); i++) {
|
||||
if (registration_order_options_[i]->IsRequired()) {
|
||||
ostream << registration_order_options_[i]->GetHelpShortMessage() << " ";
|
||||
}
|
||||
}
|
||||
ostream << std::endl;
|
||||
|
||||
ostream << "Global options:" << std::endl;
|
||||
size_t max_name_len = 0;
|
||||
for (size_t i = 0; i < registration_order_options_.size(); i++) {
|
||||
max_name_len = std::max(
|
||||
max_name_len, registration_order_options_[i]->GetName().length());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < registration_order_options_.size(); i++) {
|
||||
if (!registration_order_options_[i]->GetShortName().empty()) {
|
||||
ostream << kOptionStyleShort
|
||||
<< registration_order_options_[i]->GetShortName() << ", ";
|
||||
} else {
|
||||
ostream << std::string(4, ' ');
|
||||
}
|
||||
|
||||
size_t index_adjust = 0;
|
||||
constexpr int kSpacerNum = 5;
|
||||
auto need_value = registration_order_options_[i]->IsRequiredValue();
|
||||
ostream << kOptionStyleNormal
|
||||
<< registration_order_options_[i]->GetName();
|
||||
if (need_value) {
|
||||
ostream << kOptionValueForHelpMessage;
|
||||
index_adjust += std::string(kOptionValueForHelpMessage).length();
|
||||
}
|
||||
ostream << std::string(
|
||||
max_name_len + kSpacerNum - index_adjust -
|
||||
registration_order_options_[i]->GetName().length(),
|
||||
' ');
|
||||
ostream << registration_order_options_[i]->GetDescription() << std::endl;
|
||||
}
|
||||
|
||||
return ostream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
struct ReaderInt {
|
||||
int operator()(const std::string& value) { return std::stoi(value); }
|
||||
};
|
||||
|
||||
struct ReaderString {
|
||||
std::string operator()(const std::string& value) { return value; }
|
||||
};
|
||||
|
||||
class Option {
|
||||
public:
|
||||
Option(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, bool required, bool required_value)
|
||||
: name_(name),
|
||||
short_name_(short_name),
|
||||
description_(description),
|
||||
is_required_(required),
|
||||
is_required_value_(required_value),
|
||||
value_set_(false){};
|
||||
virtual ~Option() = default;
|
||||
|
||||
const std::string& GetName() const { return name_; };
|
||||
|
||||
const std::string& GetShortName() const { return short_name_; };
|
||||
|
||||
const std::string& GetDescription() const { return description_; };
|
||||
|
||||
const std::string GetHelpShortMessage() const {
|
||||
std::string message = kOptionStyleNormal + name_;
|
||||
if (is_required_value_) {
|
||||
message += kOptionValueForHelpMessage;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
bool IsRequired() const { return is_required_; };
|
||||
|
||||
bool IsRequiredValue() const { return is_required_value_; };
|
||||
|
||||
void Set() { value_set_ = true; };
|
||||
|
||||
virtual bool SetValue(const std::string& value) = 0;
|
||||
|
||||
virtual bool HasValue() const = 0;
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
std::string short_name_;
|
||||
std::string description_;
|
||||
bool is_required_;
|
||||
bool is_required_value_;
|
||||
bool value_set_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class OptionValue : public Option {
|
||||
public:
|
||||
OptionValue(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, const T& default_value,
|
||||
bool required, bool required_value)
|
||||
: Option(name, short_name, description, required, required_value),
|
||||
default_value_(default_value),
|
||||
value_(default_value){};
|
||||
virtual ~OptionValue() = default;
|
||||
|
||||
bool SetValue(const std::string& value) {
|
||||
value_ = Read(value);
|
||||
value_set_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasValue() const { return value_set_; }
|
||||
|
||||
const T& GetValue() const { return value_; }
|
||||
|
||||
protected:
|
||||
virtual T Read(const std::string& s) = 0;
|
||||
|
||||
T default_value_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
template <typename T, typename F>
|
||||
class OptionValueReader : public OptionValue<T> {
|
||||
public:
|
||||
OptionValueReader(const std::string& name, const std::string& short_name,
|
||||
const std::string& description, const T default_value,
|
||||
F reader, bool required, bool required_value)
|
||||
: OptionValue<T>(name, short_name, description, default_value, required,
|
||||
required_value),
|
||||
reader_(reader) {}
|
||||
~OptionValueReader() = default;
|
||||
|
||||
private:
|
||||
T Read(const std::string& value) { return reader_(value); }
|
||||
|
||||
F reader_;
|
||||
};
|
||||
|
||||
bool SetOption(const std::string& name) {
|
||||
auto itr = options_.find(name);
|
||||
if (itr == options_.end()) {
|
||||
errors_.push_back("Unknown option: " + name);
|
||||
return false;
|
||||
}
|
||||
|
||||
itr->second->Set();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetOptionValue(const std::string& name, const std::string& value) {
|
||||
auto itr = options_.find(name);
|
||||
if (itr == options_.end()) {
|
||||
errors_.push_back("Unknown option: " + name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!itr->second->SetValue(value)) {
|
||||
errors_.push_back("Invalid option value: " + name + " = " + value);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string command_name_;
|
||||
std::unordered_map<std::string, std::unique_ptr<Option>> options_;
|
||||
std::unordered_map<std::string, std::string> lut_short_options_;
|
||||
std::vector<Option*> registration_order_options_;
|
||||
std::vector<std::string> errors_;
|
||||
};
|
||||
|
||||
} // namespace commandline
|
||||
|
||||
#endif // COMMAND_OPTIONS_
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2021 Sony Corporation. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_EMBEDDER_OPTIONS_
|
||||
#define FLUTTER_EMBEDDER_OPTIONS_
|
||||
|
||||
#include <flutter/flutter_view_controller.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "command_options.h"
|
||||
|
||||
class FlutterEmbedderOptions {
|
||||
public:
|
||||
FlutterEmbedderOptions() {
|
||||
options_.AddString("bundle", "b", "Path to Flutter app bundle", "./bundle",
|
||||
true);
|
||||
options_.AddWithoutValue("no-cursor", "n", "No mouse cursor/pointer",
|
||||
false);
|
||||
#if defined(FLUTTER_TARGET_BACKEND_GBM) || \
|
||||
defined(FLUTTER_TARGET_BACKEND_EGLSTREAM)
|
||||
// no more options.
|
||||
#elif defined(FLUTTER_TARGET_BACKEND_X11)
|
||||
options_.AddWithoutValue("fullscreen", "f", "Always full-screen display",
|
||||
false);
|
||||
options_.AddInt("width", "w", "Flutter app window width", 1280, false);
|
||||
options_.AddInt("height", "h", "Flutter app window height", 720, false);
|
||||
#else // FLUTTER_TARGET_BACKEND_WAYLAND
|
||||
options_.AddWithoutValue("onscreen-keyboard", "k",
|
||||
"Enable on-screen keyboard", false);
|
||||
options_.AddWithoutValue("window-decoration", "d",
|
||||
"Enable window decorations", false);
|
||||
options_.AddWithoutValue("fullscreen", "f", "Always full-screen display",
|
||||
false);
|
||||
options_.AddInt("width", "w", "Flutter app window width", 1280, false);
|
||||
options_.AddInt("height", "h", "Flutter app window height", 720, false);
|
||||
#endif
|
||||
}
|
||||
~FlutterEmbedderOptions() = default;
|
||||
|
||||
bool Parse(int argc, char** argv) {
|
||||
if (!options_.Parse(argc, argv)) {
|
||||
std::cerr << options_.GetError() << std::endl;
|
||||
std::cout << options_.ShowHelp();
|
||||
return false;
|
||||
}
|
||||
|
||||
bundle_path_ = options_.GetValue<std::string>("bundle");
|
||||
use_mouse_cursor_ = !options_.Exist("no-cursor");
|
||||
|
||||
#if defined(FLUTTER_TARGET_BACKEND_GBM) || \
|
||||
defined(FLUTTER_TARGET_BACKEND_EGLSTREAM)
|
||||
use_onscreen_keyboard_ = false;
|
||||
use_window_decoration_ = false;
|
||||
window_view_mode_ = flutter::FlutterViewController::ViewMode::kFullscreen;
|
||||
#elif defined(FLUTTER_TARGET_BACKEND_X11)
|
||||
use_onscreen_keyboard_ = false;
|
||||
use_window_decoration_ = false;
|
||||
window_view_mode_ =
|
||||
options_.Exist("fullscreen")
|
||||
? flutter::FlutterViewController::ViewMode::kFullscreen
|
||||
: flutter::FlutterViewController::ViewMode::kNormal;
|
||||
window_width_ = options_.GetValue<int>("width");
|
||||
window_height_ = options_.GetValue<int>("height");
|
||||
#else // FLUTTER_TARGET_BACKEND_WAYLAND
|
||||
use_onscreen_keyboard_ = options_.Exist("onscreen-keyboard");
|
||||
use_window_decoration_ = options_.Exist("window-decoration");
|
||||
window_view_mode_ =
|
||||
options_.Exist("fullscreen")
|
||||
? flutter::FlutterViewController::ViewMode::kFullscreen
|
||||
: flutter::FlutterViewController::ViewMode::kNormal;
|
||||
window_width_ = options_.GetValue<int>("width");
|
||||
window_height_ = options_.GetValue<int>("height");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string BundlePath() const { return bundle_path_; }
|
||||
bool IsUseMouseCursor() const { return use_mouse_cursor_; }
|
||||
bool IsUseOnscreenKeyboard() const { return use_onscreen_keyboard_; }
|
||||
bool IsUseWindowDecoraation() const { return use_window_decoration_; }
|
||||
flutter::FlutterViewController::ViewMode WindowViewMode() const {
|
||||
return window_view_mode_;
|
||||
}
|
||||
int WindowWidth() const { return window_width_; }
|
||||
int WindowHeight() const { return window_height_; }
|
||||
|
||||
private:
|
||||
commandline::CommandOptions options_;
|
||||
|
||||
std::string bundle_path_;
|
||||
bool use_mouse_cursor_ = true;
|
||||
bool use_onscreen_keyboard_ = false;
|
||||
bool use_window_decoration_ = false;
|
||||
flutter::FlutterViewController::ViewMode window_view_mode_ =
|
||||
flutter::FlutterViewController::ViewMode::kNormal;
|
||||
int window_width_ = 1280;
|
||||
int window_height_ = 720;
|
||||
};
|
||||
|
||||
#endif // FLUTTER_EMBEDDER_OPTIONS_
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2021 Sony Corporation. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter_window.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "flutter/generated_plugin_registrant.h"
|
||||
|
||||
FlutterWindow::FlutterWindow(
|
||||
const flutter::FlutterViewController::ViewProperties view_properties,
|
||||
const flutter::DartProject project)
|
||||
: view_properties_(view_properties), project_(project) {}
|
||||
|
||||
bool FlutterWindow::OnCreate() {
|
||||
flutter_view_controller_ = std::make_unique<flutter::FlutterViewController>(
|
||||
view_properties_, project_);
|
||||
|
||||
// Ensure that basic setup of the controller was successful.
|
||||
if (!flutter_view_controller_->engine() ||
|
||||
!flutter_view_controller_->view()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register Flutter plugins.
|
||||
RegisterPlugins(flutter_view_controller_->engine());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlutterWindow::OnDestroy() {
|
||||
if (flutter_view_controller_) {
|
||||
flutter_view_controller_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void FlutterWindow::Run() {
|
||||
// Main loop.
|
||||
auto next_flutter_event_time =
|
||||
std::chrono::steady_clock::time_point::clock::now();
|
||||
while (flutter_view_controller_->view()->DispatchEvent()) {
|
||||
// Wait until the next event.
|
||||
{
|
||||
auto wait_duration =
|
||||
std::max(std::chrono::nanoseconds(0),
|
||||
next_flutter_event_time -
|
||||
std::chrono::steady_clock::time_point::clock::now());
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(wait_duration));
|
||||
}
|
||||
|
||||
// Processes any pending events in the Flutter engine, and returns the
|
||||
// number of nanoseconds until the next scheduled event (or max, if none).
|
||||
auto wait_duration = flutter_view_controller_->engine()->ProcessMessages();
|
||||
{
|
||||
auto next_event_time = std::chrono::steady_clock::time_point::max();
|
||||
if (wait_duration != std::chrono::nanoseconds::max()) {
|
||||
next_event_time =
|
||||
std::min(next_event_time,
|
||||
std::chrono::steady_clock::time_point::clock::now() +
|
||||
wait_duration);
|
||||
} else {
|
||||
// Wait for the next frame if no events.
|
||||
auto frame_rate = flutter_view_controller_->view()->GetFrameRate();
|
||||
next_event_time = std::min(
|
||||
next_event_time,
|
||||
std::chrono::steady_clock::time_point::clock::now() +
|
||||
std::chrono::milliseconds(
|
||||
static_cast<int>(std::trunc(1000000.0 / frame_rate))));
|
||||
}
|
||||
next_flutter_event_time =
|
||||
std::max(next_flutter_event_time, next_event_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2021 Sony Corporation. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_WINDOW_
|
||||
#define FLUTTER_WINDOW_
|
||||
|
||||
#include <flutter/dart_project.h>
|
||||
#include <flutter/flutter_view_controller.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class FlutterWindow {
|
||||
public:
|
||||
explicit FlutterWindow(
|
||||
const flutter::FlutterViewController::ViewProperties view_properties,
|
||||
const flutter::DartProject project);
|
||||
~FlutterWindow() = default;
|
||||
|
||||
// Prevent copying.
|
||||
FlutterWindow(FlutterWindow const&) = delete;
|
||||
FlutterWindow& operator=(FlutterWindow const&) = delete;
|
||||
|
||||
bool OnCreate();
|
||||
void OnDestroy();
|
||||
void Run();
|
||||
|
||||
private:
|
||||
flutter::FlutterViewController::ViewProperties view_properties_;
|
||||
flutter::DartProject project_;
|
||||
std::unique_ptr<flutter::FlutterViewController> flutter_view_controller_;
|
||||
};
|
||||
|
||||
#endif // FLUTTER_WINDOW_
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2021 Sony Corporation. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <flutter/dart_project.h>
|
||||
#include <flutter/flutter_view_controller.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "flutter_embedder_options.h"
|
||||
#include "flutter_window.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
FlutterEmbedderOptions options;
|
||||
if (!options.Parse(argc, argv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Creates the Flutter project.
|
||||
const auto bundle_path = options.BundlePath();
|
||||
const std::wstring fl_path(bundle_path.begin(), bundle_path.end());
|
||||
flutter::DartProject project(fl_path);
|
||||
auto command_line_arguments = std::vector<std::string>();
|
||||
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
|
||||
|
||||
flutter::FlutterViewController::ViewProperties view_properties = {};
|
||||
view_properties.width = options.WindowWidth();
|
||||
view_properties.height = options.WindowHeight();
|
||||
view_properties.view_mode = options.WindowViewMode();
|
||||
view_properties.use_mouse_cursor = options.IsUseMouseCursor();
|
||||
view_properties.use_onscreen_keyboard = options.IsUseOnscreenKeyboard();
|
||||
view_properties.use_window_decoration = options.IsUseWindowDecoraation();
|
||||
|
||||
// The Flutter instance hosted by this window.
|
||||
FlutterWindow window(view_properties, project);
|
||||
if (!window.OnCreate()) {
|
||||
std::cerr << "Failed to create a Flutter window." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
window.Run();
|
||||
window.OnDestroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
{
|
||||
"version": 1.0,
|
||||
"_comment": "A listing of all possible template output files.",
|
||||
"files": [
|
||||
"templates/app/elinux.tmpl/.gitignore",
|
||||
"templates/app/elinux.tmpl/CMakeLists.txt.tmpl",
|
||||
"templates/app/elinux.tmpl/flutter/CMakeLists.txt",
|
||||
"templates/app/elinux.tmpl/runner/CMakeLists.txt",
|
||||
"templates/app/elinux.tmpl/runner/command_options.h",
|
||||
"templates/app/elinux.tmpl/runner/flutter_embedder_options.h",
|
||||
"templates/app/elinux.tmpl/runner/flutter_window.cc",
|
||||
"templates/app/elinux.tmpl/runner/flutter_window.h",
|
||||
"templates/app/elinux.tmpl/runner/main.cc",
|
||||
|
||||
"templates/app/.gitignore.tmpl",
|
||||
"templates/app/.idea/libraries/Dart_SDK.xml.tmpl",
|
||||
"templates/app/.idea/libraries/KotlinJavaRuntime.xml.tmpl",
|
||||
"templates/app/.idea/modules.xml.tmpl",
|
||||
"templates/app/.idea/runConfigurations/main_dart.xml.tmpl",
|
||||
"templates/app/.idea/workspace.xml.tmpl",
|
||||
"templates/app/.metadata.tmpl",
|
||||
"templates/app/android-java.tmpl/app/build.gradle.tmpl",
|
||||
"templates/app/android-java.tmpl/app/src/main/java/androidIdentifier/MainActivity.java.tmpl",
|
||||
"templates/app/android-java.tmpl/build.gradle",
|
||||
"templates/app/android-java.tmpl/projectName_android.iml.tmpl",
|
||||
"templates/app/android-kotlin.tmpl/app/build.gradle.tmpl",
|
||||
"templates/app/android-kotlin.tmpl/app/src/main/kotlin/androidIdentifier/MainActivity.kt.tmpl",
|
||||
"templates/app/android-kotlin.tmpl/build.gradle",
|
||||
"templates/app/android-kotlin.tmpl/projectName_android.iml.tmpl",
|
||||
"templates/app/android.tmpl/.gitignore",
|
||||
"templates/app/android.tmpl/app/src/debug/AndroidManifest.xml.tmpl",
|
||||
"templates/app/android.tmpl/app/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/app/android.tmpl/app/src/main/res/drawable/launch_background.xml",
|
||||
"templates/app/android.tmpl/app/src/main/res/drawable-v21/launch_background.xml",
|
||||
"templates/app/android.tmpl/app/src/main/res/mipmap-hdpi/ic_launcher.png",
|
||||
"templates/app/android.tmpl/app/src/main/res/mipmap-mdpi/ic_launcher.png",
|
||||
"templates/app/android.tmpl/app/src/main/res/mipmap-xhdpi/ic_launcher.png",
|
||||
"templates/app/android.tmpl/app/src/main/res/mipmap-xxhdpi/ic_launcher.png",
|
||||
"templates/app/android.tmpl/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png",
|
||||
"templates/app/android.tmpl/app/src/main/res/values/styles.xml",
|
||||
"templates/app/android.tmpl/app/src/main/res/values-night/styles.xml",
|
||||
"templates/app/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl",
|
||||
"templates/app/android.tmpl/gradle/wrapper/gradle-wrapper.properties",
|
||||
"templates/app/android.tmpl/gradle.properties.tmpl",
|
||||
"templates/app/android.tmpl/settings.gradle",
|
||||
"templates/app/ios-objc.tmpl/Runner/AppDelegate.h",
|
||||
"templates/app/ios-objc.tmpl/Runner/AppDelegate.m",
|
||||
"templates/app/ios-objc.tmpl/Runner/main.m",
|
||||
"templates/app/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
|
||||
"templates/app/ios-objc.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
|
||||
"templates/app/ios-swift.tmpl/Runner/AppDelegate.swift",
|
||||
"templates/app/ios-swift.tmpl/Runner/Runner-Bridging-Header.h",
|
||||
"templates/app/ios-swift.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
|
||||
"templates/app/ios-swift.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
|
||||
"templates/app/ios.tmpl/.gitignore",
|
||||
"templates/app/ios.tmpl/Flutter/AppFrameworkInfo.plist",
|
||||
"templates/app/ios.tmpl/Flutter/Debug.xcconfig",
|
||||
"templates/app/ios.tmpl/Flutter/Release.xcconfig",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png",
|
||||
"templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
|
||||
"templates/app/ios.tmpl/Runner/Base.lproj/LaunchScreen.storyboard",
|
||||
"templates/app/ios.tmpl/Runner/Base.lproj/Main.storyboard",
|
||||
"templates/app/ios.tmpl/Runner/Info.plist.tmpl",
|
||||
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
|
||||
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/app/ios.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
|
||||
"templates/app/ios.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
|
||||
"templates/app/ios.tmpl/Runner.xcworkspace/contents.xcworkspacedata",
|
||||
"templates/app/ios.tmpl/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/app/ios.tmpl/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
|
||||
"templates/app/lib/main.dart.tmpl",
|
||||
"templates/app/linux.tmpl/my_application.cc.tmpl",
|
||||
"templates/app/linux.tmpl/.gitignore",
|
||||
"templates/app/linux.tmpl/CMakeLists.txt.tmpl",
|
||||
"templates/app/linux.tmpl/flutter/CMakeLists.txt",
|
||||
"templates/app/linux.tmpl/main.cc",
|
||||
"templates/app/linux.tmpl/my_application.cc",
|
||||
"templates/app/linux.tmpl/my_application.h",
|
||||
"templates/app/macos.tmpl/.gitignore",
|
||||
"templates/app/macos.tmpl/Flutter/Flutter-Debug.xcconfig",
|
||||
"templates/app/macos.tmpl/Flutter/Flutter-Release.xcconfig",
|
||||
"templates/app/macos.tmpl/Runner/AppDelegate.swift",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png",
|
||||
"templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
|
||||
"templates/app/macos.tmpl/Runner/Base.lproj/MainMenu.xib",
|
||||
"templates/app/macos.tmpl/Runner/Configs/AppInfo.xcconfig.tmpl",
|
||||
"templates/app/macos.tmpl/Runner/Configs/Debug.xcconfig",
|
||||
"templates/app/macos.tmpl/Runner/Configs/Release.xcconfig",
|
||||
"templates/app/macos.tmpl/Runner/Configs/Warnings.xcconfig",
|
||||
"templates/app/macos.tmpl/Runner/DebugProfile.entitlements",
|
||||
"templates/app/macos.tmpl/Runner/Info.plist",
|
||||
"templates/app/macos.tmpl/Runner/MainFlutterWindow.swift",
|
||||
"templates/app/macos.tmpl/Runner/Release.entitlements",
|
||||
"templates/app/macos.tmpl/Runner.xcodeproj/project.pbxproj.tmpl",
|
||||
"templates/app/macos.tmpl/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/app/macos.tmpl/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme.tmpl",
|
||||
"templates/app/macos.tmpl/Runner.xcworkspace/contents.xcworkspacedata",
|
||||
"templates/app/macos.tmpl/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/app/projectName.iml.tmpl",
|
||||
"templates/app/pubspec.yaml.tmpl",
|
||||
"templates/app/README.md.tmpl",
|
||||
"templates/app/test/widget_test.dart.tmpl",
|
||||
"templates/app/web/favicon.png.copy.tmpl",
|
||||
"templates/app/web/icons/Icon-192.png.copy.tmpl",
|
||||
"templates/app/web/icons/Icon-512.png.copy.tmpl",
|
||||
"templates/app/web/index.html.tmpl",
|
||||
"templates/app/web/manifest.json.tmpl",
|
||||
"templates/app/windows.tmpl/.gitignore",
|
||||
"templates/app/windows.tmpl/CMakeLists.txt.tmpl",
|
||||
"templates/app/windows.tmpl/flutter/CMakeLists.txt",
|
||||
"templates/app/windows.tmpl/runner/CMakeLists.txt",
|
||||
"templates/app/windows.tmpl/runner/flutter_window.cpp",
|
||||
"templates/app/windows.tmpl/runner/flutter_window.h",
|
||||
"templates/app/windows.tmpl/runner/main.cpp.tmpl",
|
||||
"templates/app/windows.tmpl/runner/resource.h",
|
||||
"templates/app/windows.tmpl/runner/resources/app_icon.ico.img.tmpl",
|
||||
"templates/app/windows.tmpl/runner/runner.exe.manifest",
|
||||
"templates/app/windows.tmpl/runner/Runner.rc.tmpl",
|
||||
"templates/app/windows.tmpl/runner/run_loop.cpp",
|
||||
"templates/app/windows.tmpl/runner/run_loop.h",
|
||||
"templates/app/windows.tmpl/runner/utils.cpp",
|
||||
"templates/app/windows.tmpl/runner/utils.h",
|
||||
"templates/app/windows.tmpl/runner/win32_window.cpp",
|
||||
"templates/app/windows.tmpl/runner/win32_window.h",
|
||||
"templates/app/winuwp.tmpl/project_version",
|
||||
"templates/cocoapods/Podfile-ios-objc",
|
||||
"templates/cocoapods/Podfile-ios-swift",
|
||||
"templates/cocoapods/Podfile-macos",
|
||||
"templates/module/android/deferred_component/build.gradle.tmpl",
|
||||
"templates/module/android/deferred_component/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/module/android/gradle/build.gradle.copy.tmpl",
|
||||
"templates/module/android/gradle/gradle.properties.tmpl",
|
||||
"templates/module/android/host_app_common/app.tmpl/build.gradle.tmpl",
|
||||
"templates/module/android/host_app_common/app.tmpl/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/module/android/host_app_common/app.tmpl/src/main/java/androidIdentifier/host/MainActivity.java.tmpl",
|
||||
"templates/module/android/host_app_common/app.tmpl/src/main/res/drawable/launch_background.xml",
|
||||
"templates/module/android/host_app_common/app.tmpl/src/main/res/mipmap-hdpi/ic_launcher.png",
|
||||
"templates/module/android/host_app_common/app.tmpl/src/main/res/values/styles.xml",
|
||||
"templates/module/android/host_app_editable/settings.gradle.copy.tmpl",
|
||||
"templates/module/android/host_app_ephemeral/settings.gradle.copy.tmpl",
|
||||
"templates/module/android/library/Flutter.tmpl/build.gradle.tmpl",
|
||||
"templates/module/android/library/Flutter.tmpl/flutter.iml.copy.tmpl",
|
||||
"templates/module/android/library/Flutter.tmpl/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/module/android/library/Flutter.tmpl/src/main/java/io/flutter/facade/Flutter.java.tmpl",
|
||||
"templates/module/android/library/Flutter.tmpl/src/main/java/io/flutter/facade/FlutterFragment.java.tmpl",
|
||||
"templates/module/android/library/include_flutter.groovy.copy.tmpl",
|
||||
"templates/module/android/library/settings.gradle.copy.tmpl",
|
||||
"templates/module/android/library_new_embedding/Flutter.tmpl/build.gradle.tmpl",
|
||||
"templates/module/android/library_new_embedding/Flutter.tmpl/flutter.iml.copy.tmpl",
|
||||
"templates/module/android/library_new_embedding/Flutter.tmpl/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/module/android/library_new_embedding/include_flutter.groovy.copy.tmpl",
|
||||
"templates/module/android/library_new_embedding/settings.gradle.copy.tmpl",
|
||||
"templates/module/common/.gitignore.tmpl",
|
||||
"templates/module/common/.idea/libraries/Dart_SDK.xml.tmpl",
|
||||
"templates/module/common/.idea/modules.xml.tmpl",
|
||||
"templates/module/common/.idea/workspace.xml.tmpl",
|
||||
"templates/module/common/.metadata.tmpl",
|
||||
"templates/module/common/lib/main.dart.tmpl",
|
||||
"templates/module/common/projectName.iml.tmpl",
|
||||
"templates/module/common/projectName_android.iml.tmpl",
|
||||
"templates/module/common/pubspec.yaml.tmpl",
|
||||
"templates/module/common/README.md.tmpl",
|
||||
"templates/module/common/test/widget_test.dart.tmpl",
|
||||
"templates/module/ios/host_app_ephemeral/Config.tmpl/Debug.xcconfig",
|
||||
"templates/module/ios/host_app_ephemeral/Config.tmpl/Flutter.xcconfig",
|
||||
"templates/module/ios/host_app_ephemeral/Config.tmpl/Release.xcconfig",
|
||||
"templates/module/ios/host_app_ephemeral/Flutter/engine/Flutter.podspec.tmpl",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/AppDelegate.h",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/AppDelegate.m",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Contents.json",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/Contents.json",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/README.md",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Base.lproj/LaunchScreen.storyboard",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Base.lproj/Main.storyboard",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/Info.plist.tmpl",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.tmpl/main.m",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.pbxproj.tmpl",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/contents.xcworkspacedata",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist",
|
||||
"templates/module/ios/host_app_ephemeral/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings",
|
||||
"templates/module/ios/host_app_ephemeral_cocoapods/Config.tmpl/Debug.xcconfig",
|
||||
"templates/module/ios/host_app_ephemeral_cocoapods/Config.tmpl/Release.xcconfig",
|
||||
"templates/module/ios/host_app_ephemeral_cocoapods/Podfile.copy.tmpl",
|
||||
"templates/module/ios/host_app_ephemeral_cocoapods/Runner.tmpl/AppDelegate.m",
|
||||
"templates/module/ios/library/Flutter.tmpl/AppFrameworkInfo.plist",
|
||||
"templates/module/ios/library/Flutter.tmpl/podhelper.rb.tmpl",
|
||||
"templates/module/ios/library/Flutter.tmpl/projectName.podspec.tmpl",
|
||||
"templates/module/ios/library/Flutter.tmpl/README.md",
|
||||
"templates/module/README.md",
|
||||
"templates/package/.gitignore.tmpl",
|
||||
"templates/package/.idea/libraries/Dart_SDK.xml.tmpl",
|
||||
"templates/package/.idea/modules.xml.tmpl",
|
||||
"templates/package/.idea/workspace.xml.tmpl",
|
||||
"templates/package/.metadata.tmpl",
|
||||
"templates/package/CHANGELOG.md.tmpl",
|
||||
"templates/package/lib/projectName.dart.tmpl",
|
||||
"templates/package/LICENSE.tmpl",
|
||||
"templates/package/projectName.iml.tmpl",
|
||||
"templates/package/pubspec.yaml.tmpl",
|
||||
"templates/package/README.md.tmpl",
|
||||
"templates/package/test/projectName_test.dart.tmpl",
|
||||
"templates/plugin/.gitignore.tmpl",
|
||||
"templates/plugin/.idea/libraries/Dart_SDK.xml.tmpl",
|
||||
"templates/plugin/.idea/modules.xml.tmpl",
|
||||
"templates/plugin/.idea/runConfigurations/example_lib_main_dart.xml.tmpl",
|
||||
"templates/plugin/.idea/workspace.xml.tmpl",
|
||||
"templates/plugin/.metadata.tmpl",
|
||||
"templates/plugin/android-java.tmpl/build.gradle.tmpl",
|
||||
"templates/plugin/android-java.tmpl/projectName_android.iml.tmpl",
|
||||
"templates/plugin/android-java.tmpl/src/main/java/androidIdentifier/pluginClass.java.tmpl",
|
||||
"templates/plugin/android-kotlin.tmpl/build.gradle.tmpl",
|
||||
"templates/plugin/android-kotlin.tmpl/projectName_android.iml.tmpl",
|
||||
"templates/plugin/android-kotlin.tmpl/src/main/kotlin/androidIdentifier/pluginClass.kt.tmpl",
|
||||
"templates/plugin/android.tmpl/.gitignore",
|
||||
"templates/plugin/android.tmpl/gradle/wrapper/gradle-wrapper.properties",
|
||||
"templates/plugin/android.tmpl/gradle.properties.tmpl",
|
||||
"templates/plugin/android.tmpl/settings.gradle.tmpl",
|
||||
"templates/plugin/android.tmpl/src/main/AndroidManifest.xml.tmpl",
|
||||
"templates/plugin/CHANGELOG.md.tmpl",
|
||||
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.h.tmpl",
|
||||
"templates/plugin/ios-objc.tmpl/Classes/pluginClass.m.tmpl",
|
||||
"templates/plugin/ios-objc.tmpl/projectName.podspec.tmpl",
|
||||
"templates/plugin/ios-swift.tmpl/Classes/pluginClass.h.tmpl",
|
||||
"templates/plugin/ios-swift.tmpl/Classes/pluginClass.m.tmpl",
|
||||
"templates/plugin/ios-swift.tmpl/Classes/SwiftpluginClass.swift.tmpl",
|
||||
"templates/plugin/ios-swift.tmpl/projectName.podspec.tmpl",
|
||||
"templates/plugin/ios.tmpl/.gitignore",
|
||||
"templates/plugin/ios.tmpl/Assets/.gitkeep",
|
||||
"templates/plugin/lib/projectName.dart.tmpl",
|
||||
"templates/plugin/LICENSE.tmpl",
|
||||
"templates/plugin/linux.tmpl/CMakeLists.txt.tmpl",
|
||||
"templates/plugin/linux.tmpl/include/projectName.tmpl/pluginClassSnakeCase.h.tmpl",
|
||||
"templates/plugin/linux.tmpl/pluginClassSnakeCase.cc.tmpl",
|
||||
"templates/plugin/macos.tmpl/Classes/pluginClass.swift.tmpl",
|
||||
"templates/plugin/macos.tmpl/projectName.podspec.tmpl",
|
||||
"templates/plugin/projectName.iml.tmpl",
|
||||
"templates/plugin/pubspec.yaml.tmpl",
|
||||
"templates/plugin/README.md.tmpl",
|
||||
"templates/plugin/test/projectName_test.dart.tmpl",
|
||||
"templates/plugin/windows.tmpl/.gitignore",
|
||||
"templates/plugin/windows.tmpl/CMakeLists.txt.tmpl",
|
||||
"templates/plugin/windows.tmpl/include/projectName.tmpl/pluginClassSnakeCase.h.tmpl",
|
||||
"templates/plugin/windows.tmpl/pluginClassSnakeCase.cpp.tmpl",
|
||||
"templates/plugin/lib/projectName_web.dart.tmpl"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user