nativescript
Version:
Command-line interface for building NativeScript projects
571 lines • 30.3 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AndroidProjectService = void 0;
const path = require("path");
const shell = require("shelljs");
const _ = require("lodash");
const constants = require("../constants");
const semver = require("semver");
const projectServiceBaseLib = require("./platform-project-service-base");
const device_android_debug_bridge_1 = require("../common/mobile/android/device-android-debug-bridge");
const constants_1 = require("../common/constants");
const helpers_1 = require("../common/helpers");
const decorators_1 = require(".././common/decorators");
const yok_1 = require("../common/yok");
//
// we sort the native dependencies topologically to make sure they are processed in the right order
// native dependenciess need to be sorted so the deepst dependencies are built before it's parents
//
// for example, given this dep structure (assuming these are all native dependencies that need to be built)
// (note: we list all dependencies at the root level, so the leaf nodes are essentially references to the root nodes)
//
// |- dep1
// |- dep2
// |- |- dep3
// |- |- dep4
// |- |- |- dep5
// |- dep3
// |- dep4
// |- |- dep5
// |- dep5
//
// It is sorted:
//
// |- dep1
// |- dep3
// |- dep5
// |- dep4 # depends on dep5, so dep5 must be built first, ie above ^
// |- |- dep5
// |- dep2 # depends on dep3, dep4 (and dep5 through dep4) so all of them must be built first before dep2 is built
// |- |- dep3
// |- |- dep4
// |- |- |- dep5
//
// for more details see: https://wikiless.org/wiki/Topological_sorting?lang=en
//
function topologicalSortNativeDependencies(dependencies, start = [], depth = 0, total = 0 // do not pass in, we calculate it in the initial run!
) {
// we set the total on the initial call - and never increment it, as it's used for esacaping the recursion
if (total === 0) {
total = dependencies.length;
}
const sortedDeps = dependencies.reduce((sortedDeps, currentDependency) => {
const allSubDependenciesProcessed = currentDependency.dependencies.every((subDependency) => {
return sortedDeps.some((dep) => dep.name === subDependency);
});
if (allSubDependenciesProcessed) {
sortedDeps.push(currentDependency);
}
return sortedDeps;
}, start);
const remainingDeps = dependencies.filter((nativeDep) => !sortedDeps.includes(nativeDep));
// recurse if we still have remaining deps
// the second condition here prevents infinite recursion
if (remainingDeps.length && sortedDeps.length < total) {
return topologicalSortNativeDependencies(remainingDeps, sortedDeps, depth + 1, total);
}
return sortedDeps;
}
class AndroidProjectService extends projectServiceBaseLib.PlatformProjectServiceBase {
constructor($androidToolsInfo, $errors, $fs, $logger, $projectDataService, $options, $injector, $devicePlatformsConstants, $androidPluginBuildService, $platformEnvironmentRequirements, $androidResourcesMigrationService, $filesHashService, $gradleCommandService, $gradleBuildService, $analyticsService) {
super($fs, $projectDataService);
this.$androidToolsInfo = $androidToolsInfo;
this.$errors = $errors;
this.$logger = $logger;
this.$options = $options;
this.$injector = $injector;
this.$devicePlatformsConstants = $devicePlatformsConstants;
this.$androidPluginBuildService = $androidPluginBuildService;
this.$platformEnvironmentRequirements = $platformEnvironmentRequirements;
this.$androidResourcesMigrationService = $androidResourcesMigrationService;
this.$filesHashService = $filesHashService;
this.$gradleCommandService = $gradleCommandService;
this.$gradleBuildService = $gradleBuildService;
this.$analyticsService = $analyticsService;
this._platformData = null;
}
getPlatformData(projectData) {
if (!projectData && !this._platformData) {
throw new Error("First call of getPlatformData without providing projectData.");
}
if (projectData && projectData.platformsDir) {
const projectRoot = this.$options.hostProjectPath
? this.$options.hostProjectPath
: path.join(projectData.platformsDir, AndroidProjectService.ANDROID_PLATFORM_NAME);
const appDestinationDirectoryArr = [
projectRoot,
this.$options.hostProjectModuleName,
constants.SRC_DIR,
constants.MAIN_DIR,
constants.ASSETS_DIR,
];
const configurationsDirectoryArr = [
projectRoot,
this.$options.hostProjectModuleName,
constants.SRC_DIR,
constants.MAIN_DIR,
constants.MANIFEST_FILE_NAME,
];
const deviceBuildOutputArr = [
projectRoot,
this.$options.hostProjectModuleName,
constants.BUILD_DIR,
constants.OUTPUTS_DIR,
constants.APK_DIR,
];
const packageName = this.getProjectNameFromId(projectData);
const runtimePackage = this.$projectDataService.getRuntimePackage(projectData.projectDir, "android" /* constants.PlatformTypes.android */);
this._platformData = {
frameworkPackageName: runtimePackage.name,
normalizedPlatformName: "Android",
platformNameLowerCase: "android",
appDestinationDirectoryPath: path.join(...appDestinationDirectoryArr),
platformProjectService: this,
projectRoot: projectRoot,
getBuildOutputPath: (buildOptions) => {
if (buildOptions.androidBundle) {
return path.join(projectRoot, this.$options.hostProjectModuleName, constants.BUILD_DIR, constants.OUTPUTS_DIR, constants.BUNDLE_DIR);
}
return path.join(...deviceBuildOutputArr);
},
getValidBuildOutputData: (buildOptions) => {
const buildMode = buildOptions.release
? constants_1.Configurations.Release.toLowerCase()
: constants_1.Configurations.Debug.toLowerCase();
if (buildOptions.androidBundle) {
return {
packageNames: [
`${this.$options.hostProjectModuleName}${constants.AAB_EXTENSION_NAME}`,
`${this.$options.hostProjectModuleName}-${buildMode}${constants.AAB_EXTENSION_NAME}`,
],
};
}
return {
packageNames: [
`${packageName}-${buildMode}${constants.APK_EXTENSION_NAME}`,
`${projectData.projectName}-${buildMode}${constants.APK_EXTENSION_NAME}`,
`${projectData.projectName}${constants.APK_EXTENSION_NAME}`,
`${this.$options.hostProjectModuleName}-${buildMode}${constants.APK_EXTENSION_NAME}`,
],
regexes: [
new RegExp(`(${packageName}|${this.$options.hostProjectModuleName})-.*-(${constants_1.Configurations.Debug}|${constants_1.Configurations.Release})(-unsigned)?${constants.APK_EXTENSION_NAME}`, "i"),
],
};
},
configurationFileName: constants.MANIFEST_FILE_NAME,
configurationFilePath: path.join(...configurationsDirectoryArr),
relativeToFrameworkConfigurationFilePath: path.join(constants.SRC_DIR, constants.MAIN_DIR, constants.MANIFEST_FILE_NAME),
fastLivesyncFileExtensions: [".jpg", ".gif", ".png", ".bmp", ".webp"], // http://developer.android.com/guide/appendix/media-formats.html
};
}
return this._platformData;
}
getCurrentPlatformVersion(platformData, projectData) {
const currentPlatformData = this.$projectDataService.getRuntimePackage(projectData.projectDir, platformData.platformNameLowerCase);
return currentPlatformData && currentPlatformData[constants.VERSION_STRING];
}
async validateOptions() {
return true;
}
getAppResourcesDestinationDirectoryPath(projectData) {
const appResourcesDirStructureHasMigrated = this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath());
if (appResourcesDirStructureHasMigrated) {
return this.getUpdatedAppResourcesDestinationDirPath(projectData);
}
else {
return this.getLegacyAppResourcesDestinationDirPath(projectData);
}
}
async validate(projectData, options, notConfiguredEnvOptions) {
this.validatePackageName(projectData.projectIdentifiers.android);
this.validateProjectName(projectData.projectName);
const checkEnvironmentRequirementsOutput = await this.$platformEnvironmentRequirements.checkEnvironmentRequirements({
platform: this.getPlatformData(projectData).normalizedPlatformName,
projectDir: projectData.projectDir,
options,
notConfiguredEnvOptions,
});
this.$androidToolsInfo.validateInfo({
showWarningsAsErrors: true,
projectDir: projectData.projectDir,
validateTargetSdk: true,
});
return {
checkEnvironmentRequirementsOutput,
};
}
async createProject(frameworkDir, frameworkVersion, projectData) {
if (semver.lt(frameworkVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) {
this.$errors.fail(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`);
}
this.$fs.ensureDirectoryExists(this.getPlatformData(projectData).projectRoot);
const androidToolsInfo = this.$androidToolsInfo.getToolsInfo({
projectDir: projectData.projectDir,
});
const targetSdkVersion = androidToolsInfo && androidToolsInfo.targetSdkVersion;
this.$logger.trace(`Using Android SDK '${targetSdkVersion}'.`);
this.copy(this.getPlatformData(projectData).projectRoot, frameworkDir, "*", "-R");
// TODO: Check if we actually need this and if it should be targetSdk or compileSdk
this.cleanResValues(targetSdkVersion, projectData);
}
getResDestinationDir(projectData) {
const appResourcesDirStructureHasMigrated = this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath());
if (appResourcesDirStructureHasMigrated) {
const appResourcesDestinationPath = this.getUpdatedAppResourcesDestinationDirPath(projectData);
return path.join(appResourcesDestinationPath, constants.MAIN_DIR, constants.RESOURCES_DIR);
}
else {
return this.getLegacyAppResourcesDestinationDirPath(projectData);
}
}
cleanResValues(targetSdkVersion, projectData) {
const resDestinationDir = this.getResDestinationDir(projectData);
const directoriesInResFolder = this.$fs.readDirectory(resDestinationDir);
const directoriesToClean = directoriesInResFolder
.map((dir) => {
return {
dirName: dir,
sdkNum: parseInt(dir.substr(AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX.length)),
};
})
.filter((dir) => dir.dirName.match(AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX) &&
dir.sdkNum &&
(!targetSdkVersion || targetSdkVersion < dir.sdkNum))
.map((dir) => path.join(resDestinationDir, dir.dirName));
this.$logger.trace("Directories to clean:");
this.$logger.trace(directoriesToClean);
_.map(directoriesToClean, (dir) => this.$fs.deleteDirectory(dir));
}
async interpolateData(projectData) {
// Interpolate the apilevel and package
this.interpolateConfigurationFile(projectData);
const appResourcesDirectoryPath = projectData.getAppResourcesDirectoryPath();
let stringsFilePath;
const appResourcesDestinationDirectoryPath = this.getAppResourcesDestinationDirectoryPath(projectData);
if (this.$androidResourcesMigrationService.hasMigrated(appResourcesDirectoryPath)) {
stringsFilePath = path.join(appResourcesDestinationDirectoryPath, constants.MAIN_DIR, constants.RESOURCES_DIR, "values", "strings.xml");
}
else {
stringsFilePath = path.join(appResourcesDestinationDirectoryPath, "values", "strings.xml");
}
shell.sed("-i", /__NAME__/, projectData.projectName, stringsFilePath);
shell.sed("-i", /__TITLE_ACTIVITY__/, projectData.projectName, stringsFilePath);
const gradleSettingsFilePath = path.join(this.getPlatformData(projectData).projectRoot, "settings.gradle");
shell.sed("-i", /__PROJECT_NAME__/, this.getProjectNameFromId(projectData), gradleSettingsFilePath);
try {
// will replace applicationId in app/App_Resources/Android/app.gradle if it has not been edited by the user
const appGradleContent = this.$fs.readText(projectData.appGradlePath);
if (appGradleContent.indexOf(constants.PACKAGE_PLACEHOLDER_NAME) !== -1) {
//TODO: For compatibility with old templates. Once all templates are updated should delete.
shell.sed("-i", new RegExp(constants.PACKAGE_PLACEHOLDER_NAME), projectData.projectIdentifiers.android, projectData.appGradlePath);
}
}
catch (e) {
this.$logger.trace(`Templates updated and no need for replace in app.gradle.`);
}
}
interpolateConfigurationFile(projectData) {
const manifestPath = this.getPlatformData(projectData).configurationFilePath;
shell.sed("-i", /__PACKAGE__/, projectData.projectIdentifiers.android, manifestPath);
}
getProjectNameFromId(projectData) {
let id;
if (projectData &&
projectData.projectIdentifiers &&
projectData.projectIdentifiers.android) {
const idParts = projectData.projectIdentifiers.android.split(".");
id = idParts[idParts.length - 1];
}
return id;
}
afterCreateProject(projectRoot) {
return null;
}
async updatePlatform(currentVersion, newVersion, canUpdate, projectData, addPlatform, removePlatforms) {
if (semver.eq(newVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) {
const platformLowercase = this.getPlatformData(projectData).normalizedPlatformName.toLowerCase();
await removePlatforms([platformLowercase.split("@")[0]]);
await addPlatform(platformLowercase);
return false;
}
return true;
}
async buildProject(projectRoot, projectData, buildData) {
const platformData = this.getPlatformData(projectData);
await this.$gradleBuildService.buildProject(platformData.projectRoot, buildData);
const outputPath = platformData.getBuildOutputPath(buildData);
await this.$filesHashService.saveHashesForProject(this._platformData, outputPath);
await this.trackKotlinUsage(projectRoot);
}
async buildForDeploy(projectRoot, projectData, buildData) {
return this.buildProject(projectRoot, projectData, buildData);
}
isPlatformPrepared(projectRoot, projectData) {
return this.$fs.exists(path.join(this.getPlatformData(projectData).appDestinationDirectoryPath, this.$options.hostProjectModuleName));
}
getFrameworkFilesExtensions() {
return [".jar", ".dat"];
}
async prepareProject() {
// Intentionally left empty.
}
ensureConfigurationFileInAppResources(projectData) {
const appResourcesDirectoryPath = projectData.appResourcesDirectoryPath;
const appResourcesDirStructureHasMigrated = this.$androidResourcesMigrationService.hasMigrated(appResourcesDirectoryPath);
let originalAndroidManifestFilePath;
if (appResourcesDirStructureHasMigrated) {
originalAndroidManifestFilePath = path.join(appResourcesDirectoryPath, this.$devicePlatformsConstants.Android, "src", "main", this.getPlatformData(projectData).configurationFileName);
}
else {
originalAndroidManifestFilePath = path.join(appResourcesDirectoryPath, this.$devicePlatformsConstants.Android, this.getPlatformData(projectData).configurationFileName);
}
const manifestExists = this.$fs.exists(originalAndroidManifestFilePath);
if (!manifestExists) {
this.$logger.warn("No manifest found in " + originalAndroidManifestFilePath);
return;
}
// Overwrite the AndroidManifest from runtime.
if (!appResourcesDirStructureHasMigrated) {
this.$fs.copyFile(originalAndroidManifestFilePath, this.getPlatformData(projectData).configurationFilePath);
}
}
prepareAppResources(projectData) {
const platformData = this.getPlatformData(projectData);
const projectAppResourcesPath = projectData.getAppResourcesDirectoryPath(projectData.projectDir);
const platformsAppResourcesPath = this.getAppResourcesDestinationDirectoryPath(projectData);
this.cleanUpPreparedResources(projectData);
this.$fs.ensureDirectoryExists(platformsAppResourcesPath);
const appResourcesDirStructureHasMigrated = this.$androidResourcesMigrationService.hasMigrated(projectAppResourcesPath);
if (appResourcesDirStructureHasMigrated) {
this.$fs.copyFile(path.join(projectAppResourcesPath, platformData.normalizedPlatformName, constants.SRC_DIR, "*"), platformsAppResourcesPath);
}
else {
this.$fs.copyFile(path.join(projectAppResourcesPath, platformData.normalizedPlatformName, "*"), platformsAppResourcesPath);
// https://github.com/NativeScript/android-runtime/issues/899
// App_Resources/Android/libs is reserved to user's aars and jars, but they should not be copied as resources
this.$fs.deleteDirectory(path.join(platformsAppResourcesPath, "libs"));
}
const androidToolsInfo = this.$androidToolsInfo.getToolsInfo({
projectDir: projectData.projectDir,
});
const compileSdkVersion = androidToolsInfo && androidToolsInfo.compileSdkVersion;
this.cleanResValues(compileSdkVersion, projectData);
}
async preparePluginNativeCode(pluginData, projectData) {
// build Android plugins which contain AndroidManifest.xml and/or resources
const pluginPlatformsFolderPath = this.getPluginPlatformsFolderPath(pluginData, AndroidProjectService.ANDROID_PLATFORM_NAME);
if (this.$fs.exists(pluginPlatformsFolderPath)) {
const options = {
gradlePath: this.$options.gradlePath,
gradleArgs: this.$options.gradleArgs,
projectDir: projectData.projectDir,
pluginName: pluginData.name,
platformsAndroidDirPath: pluginPlatformsFolderPath,
aarOutputDir: pluginPlatformsFolderPath,
tempPluginDirPath: path.join(projectData.platformsDir, "tempPlugin"),
};
if (await this.$androidPluginBuildService.buildAar(options)) {
this.$logger.info(`Built aar for ${options.pluginName}`);
}
this.$androidPluginBuildService.migrateIncludeGradle(options);
}
}
async processConfigurationFilesFromAppResources() {
return;
}
async removePluginNativeCode(pluginData, projectData) {
// not implemented
}
async beforePrepareAllPlugins(projectData, dependencies) {
if (dependencies) {
dependencies = this.filterUniqueDependencies(dependencies);
return this.provideDependenciesJson(projectData, dependencies);
}
}
async handleNativeDependenciesChange(projectData, opts) {
return;
}
filterUniqueDependencies(dependencies) {
const depsDictionary = dependencies.reduce((dict, dep) => {
const collision = dict[dep.name];
// in case there are multiple dependencies to the same module, the one declared in the package.json takes precedence
if (!collision || collision.depth > dep.depth) {
dict[dep.name] = dep;
}
return dict;
}, {});
return _.values(depsDictionary);
}
provideDependenciesJson(projectData, dependencies) {
const platformDir = this.$options.hostProjectPath
? this.$options.hostProjectPath
: path.join(projectData.platformsDir, AndroidProjectService.ANDROID_PLATFORM_NAME);
const dependenciesJsonPath = path.join(platformDir, constants.DEPENDENCIES_JSON_NAME);
let nativeDependencyData = dependencies.filter(AndroidProjectService.isNativeAndroidDependency);
let nativeDependencies = nativeDependencyData.map(({ name, directory, dependencies }) => {
return {
name,
directory: path.relative(platformDir, directory),
dependencies: dependencies.filter((dep) => {
// filter out transient dependencies that don't have native dependencies
return (nativeDependencyData.findIndex((nativeDep) => nativeDep.name === dep) !== -1);
}),
};
});
nativeDependencies = topologicalSortNativeDependencies(nativeDependencies);
const jsonContent = JSON.stringify(nativeDependencies, null, 4);
this.$fs.writeFile(dependenciesJsonPath, jsonContent);
// we sort all the dependencies to respect the topological sorting of the native dependencies
return dependencies.sort(function (a, b) {
return (nativeDependencies.findIndex((n) => n.name === a.name) -
nativeDependencies.findIndex((n) => n.name === b.name));
});
}
static isNativeAndroidDependency({ nativescript, }) {
return (nativescript &&
(nativescript.android ||
(nativescript.platforms && nativescript.platforms.android)));
}
async stopServices(projectRoot) {
const result = await this.$gradleCommandService.executeCommand(["--stop", "--quiet"], {
cwd: projectRoot,
message: "Gradle stop services...",
stdio: "pipe",
});
return result;
}
async cleanProject(projectRoot) {
await this.$gradleBuildService.cleanProject(projectRoot, {
release: false,
});
}
async cleanDeviceTempFolder(deviceIdentifier, projectData) {
const adb = this.$injector.resolve(device_android_debug_bridge_1.DeviceAndroidDebugBridge, {
identifier: deviceIdentifier,
});
const deviceRootPath = `${constants_1.LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${projectData.projectIdentifiers.android}`;
await adb.executeShellCommand(["rm", "-rf", deviceRootPath]);
}
async checkForChanges() {
// Nothing android specific to check yet.
}
getDeploymentTarget(projectData) {
return;
}
copy(projectRoot, frameworkDir, files, cpArg) {
const paths = files.split(" ").map((p) => path.join(frameworkDir, p));
shell.cp(cpArg, paths, projectRoot);
}
validatePackageName(packageName) {
//Make the package conform to Java package types
//Enforce underscore limitation
if (!/^[a-zA-Z]+(\.[a-zA-Z0-9][a-zA-Z0-9_]*)+$/.test(packageName)) {
this.$errors.fail(`Package name must look like: com.company.Name. Got: ${packageName}`);
}
//Class is a reserved word
if (/\b[Cc]lass\b/.test(packageName)) {
this.$errors.fail("class is a reserved word");
}
}
validateProjectName(projectName) {
if (projectName === "") {
this.$errors.fail("Project name cannot be empty");
}
//Classes in Java don't begin with numbers
if (/^[0-9]/.test(projectName)) {
this.$errors.fail("Project name must not begin with a number");
}
}
getLegacyAppResourcesDestinationDirPath(projectData) {
const resourcePath = [
this.$options.hostProjectModuleName,
constants.SRC_DIR,
constants.MAIN_DIR,
constants.RESOURCES_DIR,
];
return path.join(this.getPlatformData(projectData).projectRoot, ...resourcePath);
}
getUpdatedAppResourcesDestinationDirPath(projectData) {
const resourcePath = [
this.$options.hostProjectModuleName,
constants.SRC_DIR,
];
return path.join(this.getPlatformData(projectData).projectRoot, ...resourcePath);
}
/**
* The purpose of this method is to delete the previously prepared user resources.
* The content of the `<platforms>/android/.../res` directory is based on user's resources and gradle project template from android-runtime.
* During preparation of the `<path to user's App_Resources>/Android` we want to clean all the users files from previous preparation,
* but keep the ones that were introduced during `platform add` of the android-runtime.
* Currently the Gradle project template contains resources only in values and values-v21 directories.
* So the current logic of the method is cleaning al resources from `<platforms>/android/.../res` that are not in `values.*` directories
* and that exist in the `<path to user's App_Resources>/Android/.../res` directory
* This means that if user has a resource file in values-v29 for example, builds the project and then deletes this resource,
* it will be kept in platforms directory. Reference issue: `https://github.com/NativeScript/nativescript-cli/issues/5083`
* Same is valid for files in `drawable-<resolution>` directories - in case in user's resources there's drawable-hdpi directory,
* which is deleted after the first build of app, it will remain in platforms directory.
*/
cleanUpPreparedResources(projectData) {
let resourcesDirPath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName);
if (this.$androidResourcesMigrationService.hasMigrated(projectData.appResourcesDirectoryPath)) {
resourcesDirPath = path.join(resourcesDirPath, constants.SRC_DIR, constants.MAIN_DIR, constants.RESOURCES_DIR);
}
const valuesDirRegExp = /^values/;
if (this.$fs.exists(resourcesDirPath)) {
const resourcesDirs = this.$fs
.readDirectory(resourcesDirPath)
.filter((resDir) => !resDir.match(valuesDirRegExp));
const resDestinationDir = this.getResDestinationDir(projectData);
_.each(resourcesDirs, (currentResource) => {
this.$fs.deleteDirectory(path.join(resDestinationDir, currentResource));
});
}
}
async trackKotlinUsage(projectRoot) {
const buildStatistics = this.tryGetAndroidBuildStatistics(projectRoot);
try {
if (buildStatistics && buildStatistics.kotlinUsage) {
const analyticsDelimiter = constants.AnalyticsEventLabelDelimiter;
const hasUseKotlinPropertyInAppData = `hasUseKotlinPropertyInApp${analyticsDelimiter}${buildStatistics.kotlinUsage.hasUseKotlinPropertyInApp}`;
const hasKotlinRuntimeClassesData = `hasKotlinRuntimeClasses${analyticsDelimiter}${buildStatistics.kotlinUsage.hasKotlinRuntimeClasses}`;
await this.$analyticsService.trackEventActionInGoogleAnalytics({
action: "Using Kotlin" /* constants.TrackActionNames.UsingKotlin */,
additionalData: `${hasUseKotlinPropertyInAppData}${analyticsDelimiter}${hasKotlinRuntimeClassesData}`,
});
}
}
catch (e) {
this.$logger.trace(`Failed to track android build statistics. Error is: ${e.message}`);
}
}
tryGetAndroidBuildStatistics(projectRoot) {
const staticsFilePath = path.join(projectRoot, constants.ANDROID_ANALYTICS_DATA_DIR, constants.ANDROID_ANALYTICS_DATA_FILE);
let buildStatistics;
if (this.$fs.exists(staticsFilePath)) {
try {
buildStatistics = this.$fs.readJson(staticsFilePath);
}
catch (e) {
this.$logger.trace(`Unable to read android build statistics file. Error is ${e.message}`);
}
}
return buildStatistics;
}
}
exports.AndroidProjectService = AndroidProjectService;
AndroidProjectService.VALUES_DIRNAME = "values";
AndroidProjectService.VALUES_VERSION_DIRNAME_PREFIX = AndroidProjectService.VALUES_DIRNAME + "-v";
AndroidProjectService.ANDROID_PLATFORM_NAME = "android";
AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE = "1.5.0";
__decorate([
(0, decorators_1.performanceLog)(),
(0, helpers_1.hook)("buildAndroid")
], AndroidProjectService.prototype, "buildProject", null);
yok_1.injector.register("androidProjectService", AndroidProjectService);
//# sourceMappingURL=android-project-service.js.map