diff --git a/lib/definitions/android-plugin-migrator.d.ts b/lib/definitions/android-plugin-migrator.d.ts index fbbd73246e..4ede88b918 100644 --- a/lib/definitions/android-plugin-migrator.d.ts +++ b/lib/definitions/android-plugin-migrator.d.ts @@ -13,3 +13,25 @@ interface IAndroidPluginBuildService { buildAar(options: IBuildOptions): Promise; migrateIncludeGradle(options: IBuildOptions): boolean; } + +/** + * Describes data required for building plugin for Android. + * The data can be consumed in the buildAndroidPlugin hook. + */ +interface IBuildAndroidPluginData { + /** + * Directory where the plugin will be build. + * Usually this is the `/platforms/tempPlugin/` dir. + */ + pluginDir: string; + + /** + * The name of the plugin. + */ + pluginName: string; + + /** + * Information about tools that will be used to build the plugin, for example compile SDK version, build tools version, etc. + */ + androidToolsInfo: IAndroidToolsInfoData; +} diff --git a/lib/services/android-plugin-build-service.ts b/lib/services/android-plugin-build-service.ts index 3e71fd57d1..6532e4bede 100644 --- a/lib/services/android-plugin-build-service.ts +++ b/lib/services/android-plugin-build-service.ts @@ -1,12 +1,20 @@ import * as path from "path"; import { MANIFEST_FILE_NAME, INCLUDE_GRADLE_NAME, ASSETS_DIR, RESOURCES_DIR } from "../constants"; -import { getShortPluginName } from "../common/helpers"; +import { getShortPluginName, hook } from "../common/helpers"; import { Builder, parseString } from "xml2js"; import { ILogger } from "log4js"; export class AndroidPluginBuildService implements IAndroidPluginBuildService { - constructor(private $fs: IFileSystem, + /** + * Required for hooks execution to work. + */ + private get $hooksService(): IHooksService { + return this.$injector.resolve("hooksService"); + } + + constructor(private $injector: IInjector, + private $fs: IFileSystem, private $childProcess: IChildProcess, private $hostInfo: IHostInfo, private $androidToolsInfo: IAndroidToolsInfo, @@ -240,30 +248,9 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { } // finally build the plugin - const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew"; - const localArgs = [ - gradlew, - "-p", - newPluginDir, - "assembleRelease" - ]; - this.$androidToolsInfo.validateInfo({ showWarningsAsErrors: true, validateTargetSdk: true }); - const androidToolsInfo = this.$androidToolsInfo.getToolsInfo(); - const compileSdk = androidToolsInfo.compileSdkVersion; - const buildToolsVersion = androidToolsInfo.buildToolsVersion; - const supportVersion = androidToolsInfo.supportRepositoryVersion; - - localArgs.push(`-PcompileSdk=android-${compileSdk}`); - localArgs.push(`-PbuildToolsVersion=${buildToolsVersion}`); - localArgs.push(`-PsupportVersion=${supportVersion}`); - - try { - await this.$childProcess.exec(localArgs.join(" "), { cwd: newPluginDir }); - } catch (err) { - throw new Error(`Failed to build plugin ${options.pluginName} : \n${err}`); - } + await this.buildPlugin( { pluginDir: newPluginDir, pluginName: options.pluginName, androidToolsInfo }); const finalAarName = `${shortPluginName}-release.aar`; const pathToBuiltAar = path.join(newPluginDir, "build", "outputs", "aar", finalAarName); @@ -318,6 +305,26 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { return false; } + @hook("buildAndroidPlugin") + private async buildPlugin(pluginBuildSettings: IBuildAndroidPluginData): Promise { + const gradlew = this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew"; + + const localArgs = [ + "-p", + pluginBuildSettings.pluginDir, + "assembleRelease", + `-PcompileSdk=android-${pluginBuildSettings.androidToolsInfo.compileSdkVersion}`, + `-PbuildToolsVersion=${pluginBuildSettings.androidToolsInfo.buildToolsVersion}`, + `-PsupportVersion=${pluginBuildSettings.androidToolsInfo.supportRepositoryVersion}` + ]; + + try { + await this.$childProcess.spawnFromEvent(gradlew, localArgs, "close", { cwd: pluginBuildSettings.pluginDir }); + } catch (err) { + throw new Error(`Failed to build plugin ${pluginBuildSettings.pluginName} : \n${err}`); + } + } + private validateOptions(options: IBuildOptions): void { if (!options) { throw new Error("Android plugin cannot be built without passing an 'options' object."); diff --git a/test/services/android-plugin-build-service.ts b/test/services/android-plugin-build-service.ts index da3c77049f..b8dc65f670 100644 --- a/test/services/android-plugin-build-service.ts +++ b/test/services/android-plugin-build-service.ts @@ -12,14 +12,15 @@ temp.track(); describe('androiPluginBuildService', () => { - let execCalled = false; + let spawnFromEventCalled = false; const createTestInjector = (): IInjector => { const testInjector = new Yok(); testInjector.register("fs", FsLib.FileSystem); testInjector.register("childProcess", { - exec: () => { - execCalled = true; + spawnFromEvent: async (command: string, args: string[], event: string, options?: any, spawnFromEventOptions?: ISpawnFromEventOptions): Promise => { + spawnFromEventCalled = command.indexOf("gradlew") !== -1; + return null; } }); testInjector.register("hostInfo", HostInfo); @@ -36,6 +37,10 @@ describe('androiPluginBuildService', () => { testInjector.register("options", {}); testInjector.register("config", {}); testInjector.register("staticConfig", {}); + testInjector.register("hooksService", { + executeBeforeHooks: async (commandName: string, hookArguments?: IDictionary): Promise => undefined, + executeAfterHooks: async (commandName: string, hookArguments?: IDictionary): Promise => undefined + }); return testInjector; }; @@ -107,7 +112,7 @@ dependencies { }); beforeEach(() => { - execCalled = false; + spawnFromEventCalled = false; }); describe('builds aar', () => { @@ -127,7 +132,7 @@ dependencies { /* intentionally left blank */ } - assert.isTrue(execCalled); + assert.isTrue(spawnFromEventCalled); }); it('if android manifest is missing', async () => { @@ -145,7 +150,7 @@ dependencies { /* intentionally left blank */ } - assert.isTrue(execCalled); + assert.isTrue(spawnFromEventCalled); }); it('if there is only an android manifest file', async () => { @@ -163,7 +168,7 @@ dependencies { /* intentionally left blank */ } - assert.isTrue(execCalled); + assert.isTrue(spawnFromEventCalled); }); }); @@ -183,7 +188,7 @@ dependencies { /* intentionally left blank */ } - assert.isFalse(execCalled); + assert.isFalse(spawnFromEventCalled); }); });