"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");
function topologicalSortNativeDependencies(dependencies, start = [], depth = 0, total = 0) {
    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));
    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");
            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"],
            };
        }
        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");
        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) {
        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 {
            const appGradleContent = this.$fs.readText(projectData.appGradlePath);
            if (appGradleContent.indexOf(constants.PACKAGE_PLACEHOLDER_NAME) !== -1) {
                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() {
    }
    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;
        }
        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);
            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) {
        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) {
    }
    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];
            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) => {
                    return (nativeDependencyData.findIndex((nativeDep) => nativeDep.name === dep) !== -1);
                }),
            };
        });
        nativeDependencies = topologicalSortNativeDependencies(nativeDependencies);
        const jsonContent = JSON.stringify(nativeDependencies, null, 4);
        this.$fs.writeFile(dependenciesJsonPath, jsonContent);
        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() {
    }
    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) {
        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}`);
        }
        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");
        }
        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);
    }
    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",
                    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);
