Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: only install corresponding abi package when possible #5635

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
6 changes: 5 additions & 1 deletion lib/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ export abstract class BuildCommandBase extends ValidatePlatformCommandBase {
const buildData = this.$buildDataService.getBuildData(
this.$projectData.projectDir,
platform,
this.$options
{
...this.$options.argv,
// we disable buildFilterDevicesArch for build only to ensure we dont use it in production builds
buildFilterDevicesArch: false
}
);
const outputPath = await this.$buildController.prepareAndBuild(buildData);

Expand Down
6 changes: 6 additions & 0 deletions lib/common/definitions/mobile.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ declare global {
* For iOS simulators - same as the identifier.
*/
imageIdentifier?: string;

/**
* Optional property describing the architecture of the device
* Available for Android only
*/
abis?: string[];
}

interface IDeviceError extends Error, IDeviceIdentifier {}
Expand Down
4 changes: 4 additions & 0 deletions lib/common/mobile/android/android-device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ interface IAndroidDeviceDetails {
name: string;
release: string;
brand: string;
'cpu.abi': string;
'cpu.abilist64': string;
'cpu.abilist32': string;
}

interface IAdbDeviceStatusInfo {
Expand Down Expand Up @@ -96,6 +99,7 @@ export class AndroidDevice implements Mobile.IAndroidDevice {
identifier: this.identifier,
displayName: details.name,
model: details.model,
abis: details['cpu.abilist64'].split(',').concat(details['cpu.abilist32'].split(',')),
version,
vendor: details.brand,
platform: this.$devicePlatformsConstants.Android,
Expand Down
2 changes: 1 addition & 1 deletion lib/controllers/build-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class BuildController extends EventEmitter implements IBuildController {
);

if (buildData.copyTo) {
this.$buildArtifactsService.copyLatestAppPackage(
this.$buildArtifactsService.copyAppPackages(
buildData.copyTo,
platformData,
buildData
Expand Down
5 changes: 2 additions & 3 deletions lib/controllers/deploy-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ export class DeployController {
},
};
await this.$prepareController.prepare(prepareData);
const packageFilePath = await deviceDescriptor.buildAction();
await deviceDescriptor.buildAction();
await this.$deviceInstallAppService.installOnDevice(
device,
{ ...deviceDescriptor.buildData, buildForDevice: !device.isEmulator },
packageFilePath
{ ...deviceDescriptor.buildData, buildForDevice: !device.isEmulator }
);
};

Expand Down
21 changes: 5 additions & 16 deletions lib/controllers/run-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,6 @@ export class RunController extends EventEmitter implements IRunController {
deviceDescriptors: ILiveSyncDeviceDescriptor[]
): Promise<void> {
const rebuiltInformation: IDictionary<{
packageFilePath: string;
platform: string;
isEmulator: boolean;
}> = {};
Expand Down Expand Up @@ -508,8 +507,6 @@ export class RunController extends EventEmitter implements IRunController {
);

try {
let packageFilePath: string = null;

// Case where we have three devices attached, a change that requires build is found,
// we'll rebuild the app only for the first device, but we should install new package on all three devices.
if (
Expand All @@ -520,25 +517,20 @@ export class RunController extends EventEmitter implements IRunController {
rebuiltInformation[platformData.platformNameLowerCase]
.isEmulator === device.isEmulator)
) {
packageFilePath =
rebuiltInformation[platformData.platformNameLowerCase]
.packageFilePath;
await this.$deviceInstallAppService.installOnDevice(
device,
buildData,
packageFilePath
buildData
);
} else {
const shouldBuild =
prepareResultData.hasNativeChanges ||
buildData.nativePrepare.forceRebuildNativeApp ||
(await this.$buildController.shouldBuild(buildData));
if (shouldBuild) {
packageFilePath = await deviceDescriptor.buildAction();
await deviceDescriptor.buildAction();
rebuiltInformation[platformData.platformNameLowerCase] = {
isEmulator: device.isEmulator,
platform: platformData.platformNameLowerCase,
packageFilePath,
platform: platformData.platformNameLowerCase
};
} else {
await this.$analyticsService.trackEventActionInGoogleAnalytics({
Expand All @@ -550,8 +542,7 @@ export class RunController extends EventEmitter implements IRunController {

await this.$deviceInstallAppService.installOnDeviceIfNeeded(
device,
buildData,
packageFilePath
buildData
);
}

Expand Down Expand Up @@ -713,9 +704,7 @@ export class RunController extends EventEmitter implements IRunController {

await this.$deviceInstallAppService.installOnDevice(
device,
deviceDescriptor.buildData,
rebuiltInformation[platformData.platformNameLowerCase]
.packageFilePath
deviceDescriptor.buildData
);
await platformLiveSyncService.syncAfterInstall(device, watchInfo);
await this.refreshApplication(
Expand Down
2 changes: 2 additions & 0 deletions lib/data/build-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class BuildData extends PrepareData implements IBuildData {
public emulator?: boolean;
public clean: boolean;
public buildForDevice?: boolean;
public buildFilterDevicesArch?: boolean;
public buildOutputStdio?: string;
public outputPath?: string;
public copyTo?: string;
Expand Down Expand Up @@ -58,6 +59,7 @@ export class AndroidBuildData extends BuildData {
this.keyStoreAliasPassword = data.keyStoreAliasPassword;
this.keyStorePassword = data.keyStorePassword;
this.androidBundle = data.androidBundle || data.aab;
this.buildFilterDevicesArch = !this.androidBundle && data.filterDevicesArch !== false ;
this.gradlePath = data.gradlePath;
this.gradleArgs = data.gradleArgs;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/definitions/android-plugin-migrator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ interface IAndroidBuildOptions {
pluginName: string;
aarOutputDir: string;
tempPluginDirPath: string;
gradlePath?: string;
gradleArgs?: string;
gradlePath?: string;
}

interface IAndroidPluginBuildService {
Expand Down
3 changes: 2 additions & 1 deletion lib/definitions/build.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface IAndroidBuildData
extends IBuildData,
IAndroidSigningData,
IHasAndroidBundle {
buildFilterDevicesArch?: boolean;
gradlePath?: string;
gradleArgs?: string;
}
Expand Down Expand Up @@ -61,7 +62,7 @@ interface IBuildArtifactsService {
platformData: IPlatformData,
buildOutputOptions: IBuildOutputOptions
): Promise<string>;
copyLatestAppPackage(
copyAppPackages(
targetPath: string,
platformData: IPlatformData,
buildOutputOptions: IBuildOutputOptions
Expand Down
6 changes: 2 additions & 4 deletions lib/definitions/run.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ declare global {
interface IDeviceInstallAppService {
installOnDevice(
device: Mobile.IDevice,
buildData: IBuildData,
packageFile?: string
buildData: IBuildData
): Promise<void>;
installOnDeviceIfNeeded(
device: Mobile.IDevice,
buildData: IBuildData,
packageFile?: string
buildData: IBuildData
): Promise<void>;
shouldInstall(
device: Mobile.IDevice,
Expand Down
1 change: 1 addition & 0 deletions lib/helpers/deploy-command-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class DeployCommandHelper {
{
...this.$options.argv,
outputPath,
buildFilterDevicesArch: false,
buildForDevice: !d.isEmulator,
skipWatcher: !this.$options.watch,
nativePrepare: {
Expand Down
1 change: 1 addition & 0 deletions lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export class Options {
gradlePath: { type: OptionType.String, hasSensitiveValue: false },
gradleArgs: { type: OptionType.String, hasSensitiveValue: false },
aab: { type: OptionType.Boolean, hasSensitiveValue: false },
filterDevicesArch: { type: OptionType.Boolean, hasSensitiveValue: false },
performance: { type: OptionType.Object, hasSensitiveValue: true },
appleApplicationSpecificPassword: {
type: OptionType.String,
Expand Down
40 changes: 38 additions & 2 deletions lib/services/android-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ import {
import { IInjector } from "../common/definitions/yok";
import { injector } from "../common/yok";
import { INotConfiguredEnvOptions } from "../common/definitions/commands";
import { IProjectChangesInfo } from "../definitions/project-changes";
import { AndroidPrepareData } from "../data/prepare-data";
import { AndroidBuildData } from "../data/build-data";

interface NativeDependency {
name: string;
Expand Down Expand Up @@ -148,6 +151,8 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
private $androidPluginBuildService: IAndroidPluginBuildService,
private $platformEnvironmentRequirements: IPlatformEnvironmentRequirements,
private $androidResourcesMigrationService: IAndroidResourcesMigrationService,
private $liveSyncProcessDataService: ILiveSyncProcessDataService,
private $devicesService: Mobile.IDevicesService,
private $filesHashService: IFilesHashService,
private $gradleCommandService: IGradleCommandService,
private $gradleBuildService: IGradleBuildService,
Expand Down Expand Up @@ -826,8 +831,39 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
await adb.executeShellCommand(["rm", "-rf", deviceRootPath]);
}

public async checkForChanges(): Promise<void> {
// Nothing android specific to check yet.
public async checkForChanges(
changesInfo: IProjectChangesInfo,
prepareData: AndroidPrepareData,
projectData: IProjectData
): Promise<void> {
//we need to check for abi change in connected device vs last built
const deviceDescriptors = this.$liveSyncProcessDataService.getDeviceDescriptors(
projectData.projectDir
);
const platformData = this.getPlatformData(projectData);
deviceDescriptors.forEach(deviceDescriptor=>{
const buildData = deviceDescriptor.buildData as AndroidBuildData;
if (buildData.buildFilterDevicesArch) {
const outputPath = platformData.getBuildOutputPath(deviceDescriptor.buildData);
const apkOutputPath = path.join(outputPath, prepareData.release ? "release" : "debug");
if (!this.$fs.exists(outputPath)) {
return;
}
// check if we already build this arch
// if not we need to say native has changed
const device = this.$devicesService.getDevicesForPlatform(deviceDescriptor.buildData.platform).filter(d=>d.deviceInfo.identifier === deviceDescriptor.identifier)[0];
const abis = device.deviceInfo.abis.filter(a=>!!a && a.length)[0];

const directoryContent = this.$fs.readDirectory(apkOutputPath);
const regexp = new RegExp(`${abis}.*\.apk`);
const files = _.filter(directoryContent, (entry: string) => {
return regexp.test(entry);
});
if (files.length === 0) {
changesInfo.nativeChanged = true;
}
}
})
}

public getDeploymentTarget(projectData: IProjectData): semver.SemVer {
Expand Down
1 change: 0 additions & 1 deletion lib/services/android/gradle-build-args-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export class GradleBuildArgsService implements IGradleBuildArgsService {
) {
args.push("-PgatherAnalyticsData=true");
}

// allow modifying gradle args from a `before-build-task-args` hook
await this.$hooksService.executeBeforeHooks("build-task-args", {
hookArgs: { args },
Expand Down
14 changes: 13 additions & 1 deletion lib/services/android/gradle-build-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export class GradleBuildService
constructor(
private $childProcess: IChildProcess,
private $gradleBuildArgsService: IGradleBuildArgsService,
private $gradleCommandService: IGradleCommandService
private $gradleCommandService: IGradleCommandService,
private $devicesService: Mobile.IDevicesService
) {
super();
}
Expand All @@ -28,6 +29,17 @@ export class GradleBuildService
const buildTaskArgs = await this.$gradleBuildArgsService.getBuildTaskArgs(
buildData
);
if (buildData.buildFilterDevicesArch) {
let devices = this.$devicesService.getDevicesForPlatform(buildData.platform);
if(buildData.emulator) {
devices = devices.filter(d=>d.isEmulator);
}
const abis = devices.map(d=>d.deviceInfo.abis[0]);
if (abis.length > 0) {
buildTaskArgs.push(`-PabiFilters=${abis.join(',')}`);
}
}
console.log('buildTaskArgs', buildTaskArgs);
const spawnOptions = {
emitOptions: { eventName: constants.BUILD_OUTPUT_EVENT_NAME },
throwError: true,
Expand Down
34 changes: 23 additions & 11 deletions lib/services/build-artifacts-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class BuildArtifactsService implements IBuildArtifactsService {
return [];
}

public copyLatestAppPackage(
public copyAppPackages(
targetPath: string,
platformData: IPlatformData,
buildOutputOptions: IBuildOutputOptions
Expand All @@ -85,31 +85,43 @@ export class BuildArtifactsService implements IBuildArtifactsService {
const outputPath =
buildOutputOptions.outputPath ||
platformData.getBuildOutputPath(buildOutputOptions);
const applicationPackage = this.getLatestApplicationPackage(
const applicationPackages = this.getAllAppPackages(
outputPath,
platformData.getValidBuildOutputData(buildOutputOptions)
);
const packageFile = applicationPackage.packageName;

this.$fs.ensureDirectoryExists(path.dirname(targetPath));

let filterRegex: RegExp;
let targetIsDirectory = false;
if (
this.$fs.exists(targetPath) &&
this.$fs.getFsStats(targetPath).isDirectory()
) {
const sourceFileName = path.basename(packageFile);
this.$logger.trace(
`Specified target path: '${targetPath}' is directory. Same filename will be used: '${sourceFileName}'.`
);
targetPath = path.join(targetPath, sourceFileName);
targetIsDirectory = true;
} else if (targetPath.match(/\.(ipa|aab|apk)/)){
if (applicationPackages.length > 1){
filterRegex = new RegExp('universal');
this.$logger.trace(
`Multiple packages were built but only the universal one will be copied if existing'.`
);
}
} else {
targetIsDirectory = true;
}
this.$fs.copyFile(packageFile, targetPath);
this.$logger.info(`Copied file '${packageFile}' to '${targetPath}'.`);
applicationPackages.forEach(pack => {
const targetFilePath = targetIsDirectory ? path.join(targetPath, path.basename(pack.packageName)) : targetPath;
if (!filterRegex || filterRegex.test(pack.packageName)) {
this.$fs.copyFile(pack.packageName, targetFilePath);
this.$logger.info(`Copied file '${pack.packageName}' to '${targetFilePath}'.`);
}
});
}

private getLatestApplicationPackage(
buildOutputPath: string,
validBuildOutputData: IValidBuildOutputData
validBuildOutputData: IValidBuildOutputData,
abis?: string[]
): IApplicationPackage {
let packages = this.getAllAppPackages(
buildOutputPath,
Expand Down
Loading