Skip to content

Commit d96f008

Browse files
farfromrefugclaude
andcommitted
feat(android): per-plugin abiFilters in the project config
`android.plugins.<name>.abiFilters` passes a fixed `-PabiFilters` list to that plugin's gradle build: ```js android: { plugins: { "@foo/plugin-x": { abiFilters: ["arm64-v8a"] }, }, } ``` What a plugin has native code for does not depend on what is plugged in, so the list wins over the ABIs `--filter-plugins-devices-arch` derives from the connected devices, and applies whether or not that flag is set. An empty list passes nothing, which opts a single plugin out of the narrowing. Nothing in the gradle files the CLI generates for a plugin acts on the property - it is read by a plugin's own `include.gradle`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent c47fb4f commit d96f008

3 files changed

Lines changed: 73 additions & 9 deletions

File tree

lib/definitions/project.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,15 @@ interface INsConfigAndroidPlugin {
195195
* each other - a suffix tells them apart.
196196
*/
197197
aarSuffix?: string;
198+
199+
/**
200+
* The ABIs passed to this plugin's gradle build as `-PabiFilters`, which a
201+
* plugin acts on in its own `include.gradle`. Wins over the ABIs
202+
* `--filter-plugins-devices-arch` derives from the connected devices, and
203+
* applies whether or not that flag is set. An empty array passes nothing,
204+
* which opts this plugin out of the narrowing.
205+
*/
206+
abiFilters?: string[];
198207
}
199208

200209
interface INsConfigHooks {

lib/services/android-project-service.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Configurations, LiveSyncPaths } from "../common/constants";
99
import { hook } from "../common/helpers";
1010
import { performanceLog } from ".././common/decorators";
1111
import {
12+
INsConfigAndroidPlugin,
1213
IProjectData,
1314
IProjectDataService,
1415
IValidatePlatformOutput,
@@ -698,7 +699,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
698699
const options: IPluginBuildOptions = {
699700
gradlePath: this.$options.gradlePath,
700701
gradleArgs: this.$options.gradleArgs,
701-
abiFilters: this.getPluginsAbiFilters(),
702+
abiFilters: this.getPluginsAbiFilters(pluginConfig),
702703
projectDir: projectData.projectDir,
703704
pluginName: pluginData.name,
704705
platformsAndroidDirPath: pluginPlatformsFolderPath,
@@ -716,13 +717,21 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
716717
}
717718

718719
/**
719-
* The ABIs passed to the gradle build of a plugin built from source. Opt-in
720-
* (`--filter-plugins-devices-arch`): nothing in the gradle files the CLI
721-
* generates for a plugin acts on `abiFilters`, so this is only useful for a
722-
* plugin whose own `include.gradle` reads the property - a long native build
723-
* can then skip the ABIs this run is not going to deploy to.
720+
* The ABIs passed to the gradle build of a plugin built from source. Nothing
721+
* in the gradle files the CLI generates for a plugin acts on `abiFilters`,
722+
* so this is only useful for a plugin whose own `include.gradle` reads the
723+
* property - a long native build can then skip the ABIs it is not asked for.
724+
*
725+
* A list in the plugin's config entry always wins: what a plugin has native
726+
* code for does not depend on what is plugged in. Otherwise the ABIs of the
727+
* devices this run is about to deploy to are used, and only when
728+
* `--filter-plugins-devices-arch` asks for it.
724729
*/
725-
private getPluginsAbiFilters(): string[] {
730+
private getPluginsAbiFilters(pluginConfig: INsConfigAndroidPlugin): string[] {
731+
if (pluginConfig.abiFilters) {
732+
return pluginConfig.abiFilters;
733+
}
734+
726735
if (!this.$options.filterPluginsDevicesArch) {
727736
return null;
728737
}

test/services/android-project-service.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
IProjectDir,
2121
} from "../../lib/common/declarations";
2222
import { IPluginBuildOptions } from "../../lib/definitions/android-plugin-migrator";
23+
import { INsConfigAndroidPlugin } from "../../lib/definitions/project";
2324

2425
const createTestInjector = (): IInjector => {
2526
const testInjector = new Yok();
@@ -424,7 +425,8 @@ describe("androidProjectService plugins abi filtering", () => {
424425

425426
const preparePluginNativeCode = async (
426427
options: any,
427-
devices: any[]
428+
devices: any[],
429+
pluginsConfig?: IDictionary<INsConfigAndroidPlugin>
428430
): Promise<IPluginBuildOptions> => {
429431
const testInjector = createTestInjector();
430432
let pluginBuildOptions: IPluginBuildOptions = null;
@@ -452,7 +454,11 @@ describe("androidProjectService plugins abi filtering", () => {
452454
name: "my-plugin",
453455
pluginPlatformsFolderPath: (): string => "pluginPlatformsDir",
454456
},
455-
<any>{ projectDir: "projectDir", platformsDir: "platformsDir" }
457+
<any>{
458+
projectDir: "projectDir",
459+
platformsDir: "platformsDir",
460+
nsConfig: { android: { plugins: pluginsConfig } },
461+
}
456462
);
457463

458464
return pluginBuildOptions;
@@ -490,6 +496,46 @@ describe("androidProjectService plugins abi filtering", () => {
490496
assert.isNull(options.abiFilters);
491497
});
492498

499+
it("passes the abis from the plugin's config entry", async () => {
500+
const options = await preparePluginNativeCode(
501+
{ filterPluginsDevicesArch: true },
502+
[createDevice("device1", ["x86_64"], true)],
503+
{ "my-plugin": { abiFilters: ["arm64-v8a"] } }
504+
);
505+
506+
assert.deepStrictEqual(options.abiFilters, ["arm64-v8a"]);
507+
});
508+
509+
it("passes the abis from the config entry without the option", async () => {
510+
const options = await preparePluginNativeCode(
511+
{},
512+
[createDevice("device1", ["x86_64"], true)],
513+
{ "my-plugin": { abiFilters: ["arm64-v8a"] } }
514+
);
515+
516+
assert.deepStrictEqual(options.abiFilters, ["arm64-v8a"]);
517+
});
518+
519+
it("passes no abis when the config entry is an empty list", async () => {
520+
const options = await preparePluginNativeCode(
521+
{ filterPluginsDevicesArch: true },
522+
[createDevice("device1", ["x86_64"], true)],
523+
{ "my-plugin": { abiFilters: [] } }
524+
);
525+
526+
assert.deepStrictEqual(options.abiFilters, []);
527+
});
528+
529+
it("ignores the config entry of another plugin", async () => {
530+
const options = await preparePluginNativeCode(
531+
{ filterPluginsDevicesArch: true },
532+
[createDevice("device1", ["x86_64"], true)],
533+
{ "other-plugin": { abiFilters: ["arm64-v8a"] } }
534+
);
535+
536+
assert.deepStrictEqual(options.abiFilters, ["x86_64"]);
537+
});
538+
493539
it("passes no abis when no device reports its abis", async () => {
494540
const options = await preparePluginNativeCode(
495541
{ filterPluginsDevicesArch: true },

0 commit comments

Comments
 (0)