Add capacitorjs runtime

This commit is contained in:
olcxja 2026-05-03 17:09:55 +02:00
commit f90c0e6c40
8362 changed files with 1502407 additions and 1 deletions

View file

@ -0,0 +1,42 @@
import type { AndroidOutputAssetTemplate, AndroidOutputAssetTemplateAdaptiveIcon, AndroidOutputAssetTemplateSplash } from '../../definitions';
export declare const ANDROID_LDPI_ICON: AndroidOutputAssetTemplate;
export declare const ANDROID_MDPI_ICON: AndroidOutputAssetTemplate;
export declare const ANDROID_HDPI_ICON: AndroidOutputAssetTemplate;
export declare const ANDROID_XHDPI_ICON: AndroidOutputAssetTemplate;
export declare const ANDROID_XXHDPI_ICON: AndroidOutputAssetTemplate;
export declare const ANDROID_XXXHDPI_ICON: AndroidOutputAssetTemplate;
/**
* Adaptive icons
*/
export declare const ANDROID_LDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_MDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_HDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_XHDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_XXHDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_XXXHDPI_ADAPTIVE_ICON: AndroidOutputAssetTemplateAdaptiveIcon;
export declare const ANDROID_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_LDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_MDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_HDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XXHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XXXHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_LDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_MDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_HDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XXHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XXXHDPI_SCREEN: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_LDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_MDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_HDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XXHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_LAND_XXXHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_LDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_MDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_HDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XXHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;
export declare const ANDROID_PORT_XXXHDPI_SCREEN_DARK: AndroidOutputAssetTemplateSplash;

View file

@ -0,0 +1,340 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ANDROID_PORT_XXXHDPI_SCREEN_DARK = exports.ANDROID_PORT_XXHDPI_SCREEN_DARK = exports.ANDROID_PORT_XHDPI_SCREEN_DARK = exports.ANDROID_PORT_HDPI_SCREEN_DARK = exports.ANDROID_PORT_MDPI_SCREEN_DARK = exports.ANDROID_PORT_LDPI_SCREEN_DARK = exports.ANDROID_LAND_XXXHDPI_SCREEN_DARK = exports.ANDROID_LAND_XXHDPI_SCREEN_DARK = exports.ANDROID_LAND_XHDPI_SCREEN_DARK = exports.ANDROID_LAND_HDPI_SCREEN_DARK = exports.ANDROID_LAND_MDPI_SCREEN_DARK = exports.ANDROID_LAND_LDPI_SCREEN_DARK = exports.ANDROID_SCREEN_DARK = exports.ANDROID_PORT_XXXHDPI_SCREEN = exports.ANDROID_PORT_XXHDPI_SCREEN = exports.ANDROID_PORT_XHDPI_SCREEN = exports.ANDROID_PORT_HDPI_SCREEN = exports.ANDROID_PORT_MDPI_SCREEN = exports.ANDROID_PORT_LDPI_SCREEN = exports.ANDROID_LAND_XXXHDPI_SCREEN = exports.ANDROID_LAND_XXHDPI_SCREEN = exports.ANDROID_LAND_XHDPI_SCREEN = exports.ANDROID_LAND_HDPI_SCREEN = exports.ANDROID_LAND_MDPI_SCREEN = exports.ANDROID_LAND_LDPI_SCREEN = exports.ANDROID_SCREEN = exports.ANDROID_XXXHDPI_ADAPTIVE_ICON = exports.ANDROID_XXHDPI_ADAPTIVE_ICON = exports.ANDROID_XHDPI_ADAPTIVE_ICON = exports.ANDROID_HDPI_ADAPTIVE_ICON = exports.ANDROID_MDPI_ADAPTIVE_ICON = exports.ANDROID_LDPI_ADAPTIVE_ICON = exports.ANDROID_XXXHDPI_ICON = exports.ANDROID_XXHDPI_ICON = exports.ANDROID_XHDPI_ICON = exports.ANDROID_HDPI_ICON = exports.ANDROID_MDPI_ICON = exports.ANDROID_LDPI_ICON = void 0;
exports.ANDROID_LDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 36,
height: 36,
density: "ldpi" /* Ldpi */,
};
exports.ANDROID_MDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 48,
height: 48,
density: "mdpi" /* Mdpi */,
};
exports.ANDROID_HDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 72,
height: 72,
density: "hdpi" /* Hdpi */,
};
exports.ANDROID_XHDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 96,
height: 96,
density: "xhdpi" /* Xhdpi */,
};
exports.ANDROID_XXHDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 144,
height: 144,
density: "xxhdpi" /* Xxhdpi */,
};
exports.ANDROID_XXXHDPI_ICON = {
platform: "android" /* Android */,
kind: "icon" /* Icon */,
format: "png" /* Png */,
width: 192,
height: 192,
density: "xxxhdpi" /* Xxxhdpi */,
};
/**
* Adaptive icons
*/
exports.ANDROID_LDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 81,
height: 81,
density: "ldpi" /* Ldpi */,
};
exports.ANDROID_MDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 108,
height: 108,
density: "mdpi" /* Mdpi */,
};
exports.ANDROID_HDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 162,
height: 162,
density: "hdpi" /* Hdpi */,
};
exports.ANDROID_XHDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 216,
height: 216,
density: "xhdpi" /* Xhdpi */,
};
exports.ANDROID_XXHDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 324,
height: 324,
density: "xxhdpi" /* Xxhdpi */,
};
exports.ANDROID_XXXHDPI_ADAPTIVE_ICON = {
platform: "android" /* Android */,
kind: "adaptive-icon" /* AdaptiveIcon */,
format: "png" /* Png */,
width: 432,
height: 432,
density: "xxxhdpi" /* Xxxhdpi */,
};
//
// Splash screens
//
exports.ANDROID_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 320,
height: 480,
density: "" /* Default */,
orientation: "" /* Default */,
};
exports.ANDROID_LAND_LDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 320,
height: 240,
density: "land-ldpi" /* LandLdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_MDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 480,
height: 320,
density: "land-mdpi" /* LandMdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_HDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 800,
height: 480,
density: "land-hdpi" /* LandHdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 1280,
height: 720,
density: "land-xhdpi" /* LandXhdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XXHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 1600,
height: 960,
density: "land-xxhdpi" /* LandXxhdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XXXHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 1920,
height: 1280,
density: "land-xxxhdpi" /* LandXxxhdpi */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_PORT_LDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 240,
height: 320,
density: "port-ldpi" /* PortLdpi */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_MDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 320,
height: 480,
density: "port-mdpi" /* PortMdpi */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_HDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 480,
height: 800,
density: "port-hdpi" /* PortHdpi */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 720,
height: 1280,
density: "port-xhdpi" /* PortXhdpi */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XXHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 960,
height: 1600,
density: "port-xxhdpi" /* PortXxhdpi */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XXXHDPI_SCREEN = {
platform: "android" /* Android */,
kind: "splash" /* Splash */,
format: "png" /* Png */,
width: 1280,
height: 1920,
density: "port-xxxhdpi" /* PortXxxhdpi */,
orientation: "portrait" /* Portrait */,
};
// Dark/night mode splashes
exports.ANDROID_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 320,
height: 240,
density: "night" /* DefaultNight */,
orientation: "" /* Default */,
};
exports.ANDROID_LAND_LDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 320,
height: 240,
density: "land-night-ldpi" /* LandLdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_MDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 480,
height: 320,
density: "land-night-mdpi" /* LandMdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_HDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 800,
height: 480,
density: "land-night-hdpi" /* LandHdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 1280,
height: 720,
density: "land-night-xhdpi" /* LandXhdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XXHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 1600,
height: 960,
density: "land-night-xxhdpi" /* LandXxhdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_LAND_XXXHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 1920,
height: 1280,
density: "land-night-xxxhdpi" /* LandXxxhdpiNight */,
orientation: "landscape" /* Landscape */,
};
exports.ANDROID_PORT_LDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 240,
height: 320,
density: "port-night-ldpi" /* PortLdpiNight */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_MDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 320,
height: 480,
density: "port-night-mdpi" /* PortMdpiNight */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_HDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 480,
height: 800,
density: "port-night-hdpi" /* PortHdpiNight */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 720,
height: 1280,
density: "port-night-xhdpi" /* PortXhdpiNight */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XXHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 960,
height: 1600,
density: "port-night-xxhdpi" /* PortXxhdpiNight */,
orientation: "portrait" /* Portrait */,
};
exports.ANDROID_PORT_XXXHDPI_SCREEN_DARK = {
platform: "android" /* Android */,
kind: "splash-dark" /* SplashDark */,
format: "png" /* Png */,
width: 1280,
height: 1920,
density: "port-night-xxxhdpi" /* PortXxxhdpiNight */,
orientation: "portrait" /* Portrait */,
};

View file

@ -0,0 +1,28 @@
import type { AssetGeneratorOptions } from '../../asset-generator';
import { AssetGenerator } from '../../asset-generator';
import type { InputAsset } from '../../input-asset';
import { OutputAsset } from '../../output-asset';
import type { Project } from '../../project';
export declare class AndroidAssetGenerator extends AssetGenerator {
constructor(options?: AssetGeneratorOptions);
generate(asset: InputAsset, project: Project): Promise<OutputAsset[]>;
/**
* Generate from logo combines all of the other operations into a single operation
* from a single asset source file. In this mode, a logo along with a background color
* is used to generate all icons and splash screens (with dark mode where possible).
*/
private generateFromLogo;
private _generateAdaptiveIconsFromLogo;
private _generateSplashesFromLogo;
private generateLegacyIcon;
private generateLegacyLauncherIcon;
private generateRoundLauncherIcon;
private generateAdaptiveIconForeground;
private _generateAdaptiveIconForeground;
private generateAdaptiveIconBackground;
private _generateAdaptiveIconBackground;
private updateManifest;
private generateSplashes;
private generateSplash;
private getResPath;
}

View file

@ -0,0 +1,339 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AndroidAssetGenerator = void 0;
const tslib_1 = require("tslib");
/* eslint-disable @typescript-eslint/no-non-null-assertion */
const utils_fs_1 = require("@ionic/utils-fs");
const path_1 = require("path");
const sharp_1 = (0, tslib_1.__importDefault)(require("sharp"));
const asset_generator_1 = require("../../asset-generator");
const error_1 = require("../../error");
const output_asset_1 = require("../../output-asset");
const log_1 = require("../../util/log");
const AndroidAssetTemplates = (0, tslib_1.__importStar)(require("./assets"));
class AndroidAssetGenerator extends asset_generator_1.AssetGenerator {
constructor(options = {}) {
super(options);
}
async generate(asset, project) {
var _a;
const androidDir = (_a = project.config.android) === null || _a === void 0 ? void 0 : _a.path;
if (!androidDir) {
throw new error_1.BadProjectError('No android project found');
}
if (asset.platform !== "any" /* Any */ && asset.platform !== "android" /* Android */) {
return [];
}
switch (asset.kind) {
case "logo" /* Logo */:
case "logo-dark" /* LogoDark */:
return this.generateFromLogo(asset, project);
case "icon" /* Icon */:
return this.generateLegacyIcon(asset, project);
case "icon-foreground" /* IconForeground */:
return this.generateAdaptiveIconForeground(asset, project);
case "icon-background" /* IconBackground */:
return this.generateAdaptiveIconBackground(asset, project);
case "splash" /* Splash */:
case "splash-dark" /* SplashDark */:
return this.generateSplashes(asset, project);
}
return [];
}
/**
* Generate from logo combines all of the other operations into a single operation
* from a single asset source file. In this mode, a logo along with a background color
* is used to generate all icons and splash screens (with dark mode where possible).
*/
async generateFromLogo(asset, project) {
const pipe = asset.pipeline();
const generated = [];
if (!pipe) {
throw new error_1.BadPipelineError('Sharp instance not created');
}
// Generate adaptive icons
const generatedAdaptiveIcons = await this._generateAdaptiveIconsFromLogo(project, asset, pipe);
generated.push(...generatedAdaptiveIcons);
if (asset.kind === "logo" /* Logo */) {
// Generate legacy icons
const generatedLegacyIcons = await this.generateLegacyIcon(asset, project);
generated.push(...generatedLegacyIcons);
const splashes = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "splash" /* Splash */);
const generatedSplashes = await Promise.all(splashes.map(async (splash) => {
var _a;
return this._generateSplashesFromLogo(project, asset, splash, pipe, (_a = this.options.splashBackgroundColor) !== null && _a !== void 0 ? _a : '#ffffff');
}));
generated.push(...generatedSplashes);
}
// Generate dark splashes
const darkSplashes = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "splash-dark" /* SplashDark */);
const generatedSplashes = await Promise.all(darkSplashes.map(async (splash) => {
var _a;
return this._generateSplashesFromLogo(project, asset, splash, pipe, (_a = this.options.splashBackgroundColorDark) !== null && _a !== void 0 ? _a : '#111111');
}));
generated.push(...generatedSplashes);
return [...generated];
}
// Generate adaptive icons from the source logo
async _generateAdaptiveIconsFromLogo(project, asset, pipe) {
var _a, _b;
// Current versions of Android don't appear to support night mode icons (13+ might?)
// so, for now, we only generate light mode ones
if (asset.kind === "logo-dark" /* LogoDark */) {
return [];
}
// Create the background pipeline for the generated icons
const backgroundPipe = (0, sharp_1.default)({
create: {
width: asset.width,
height: asset.height,
channels: 4,
background: asset.kind === "logo" /* Logo */
? (_a = this.options.iconBackgroundColor) !== null && _a !== void 0 ? _a : '#ffffff'
: (_b = this.options.iconBackgroundColorDark) !== null && _b !== void 0 ? _b : '#111111',
},
});
const icons = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "adaptive-icon" /* AdaptiveIcon */);
const backgroundImages = await Promise.all(icons.map(async (icon) => {
return await this._generateAdaptiveIconBackground(project, asset, icon, backgroundPipe);
}));
const foregroundImages = await Promise.all(icons.map(async (icon) => {
return await this._generateAdaptiveIconForeground(project, asset, icon, pipe);
}));
return [...foregroundImages, ...backgroundImages];
}
async _generateSplashesFromLogo(project, asset, splash, pipe, backgroundColor) {
var _a, _b, _c, _d, _e, _f, _g;
// Generate light splash
const resPath = this.getResPath(project);
let drawableDir = `drawable`;
if (splash.density) {
drawableDir = `drawable-${splash.density}`;
}
const parentDir = (0, path_1.join)(resPath, drawableDir);
if (!(await (0, utils_fs_1.pathExists)(parentDir))) {
await (0, utils_fs_1.mkdirp)(parentDir);
}
const dest = (0, path_1.join)(resPath, drawableDir, 'splash.png');
const targetLogoWidthPercent = (_a = this.options.logoSplashScale) !== null && _a !== void 0 ? _a : 0.2;
let targetWidth = (_b = this.options.logoSplashTargetWidth) !== null && _b !== void 0 ? _b : Math.floor(((_c = splash.width) !== null && _c !== void 0 ? _c : 0) * targetLogoWidthPercent);
if (targetWidth > splash.width || targetWidth > splash.height) {
targetWidth = Math.floor(((_d = splash.width) !== null && _d !== void 0 ? _d : 0) * targetLogoWidthPercent);
}
if (targetWidth > splash.width || targetWidth > splash.height) {
(0, log_1.warn)(`Logo dimensions exceed dimensions of splash ${splash.width}x${splash.height}, using default logo size`);
targetWidth = Math.floor(((_e = splash.width) !== null && _e !== void 0 ? _e : 0) * 0.2);
}
const canvas = (0, sharp_1.default)({
create: {
width: (_f = splash.width) !== null && _f !== void 0 ? _f : 0,
height: (_g = splash.height) !== null && _g !== void 0 ? _g : 0,
channels: 4,
background: backgroundColor,
},
});
const resized = await (0, sharp_1.default)(asset.path).resize(targetWidth).toBuffer();
const outputInfo = await canvas
.composite([{ input: resized, gravity: sharp_1.default.gravity.center }])
.png()
.toFile(dest);
const splashOutput = new output_asset_1.OutputAsset(splash, asset, project, {
[dest]: dest,
}, {
[dest]: outputInfo,
});
return splashOutput;
}
async generateLegacyIcon(asset, project) {
const icons = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "icon" /* Icon */);
const pipe = asset.pipeline();
if (!pipe) {
throw new error_1.BadPipelineError('Sharp instance not created');
}
const collected = await Promise.all(icons.map(async (icon) => {
const [dest, outputInfo] = await this.generateLegacyLauncherIcon(project, asset, icon);
return new output_asset_1.OutputAsset(icon, asset, project, { [`mipmap-${icon.density}/ic_launcher.png`]: dest }, { [`mipmap-${icon.density}/ic_launcher.png`]: outputInfo });
}));
collected.push(...(await Promise.all(icons.map(async (icon) => {
const [dest, outputInfo] = await this.generateRoundLauncherIcon(project, asset, icon);
return new output_asset_1.OutputAsset(icon, asset, project, { [`mipmap-${icon.density}/ic_launcher_round.png`]: dest }, { [`mipmap-${icon.density}/ic_launcher_round.png`]: outputInfo });
}))));
await this.updateManifest(project);
return collected;
}
async generateLegacyLauncherIcon(project, asset, template) {
const resPath = this.getResPath(project);
const parentDir = (0, path_1.join)(resPath, `mipmap-${template.density}`);
if (!(await (0, utils_fs_1.pathExists)(parentDir))) {
await (0, utils_fs_1.mkdirp)(parentDir);
}
const destRound = (0, path_1.join)(resPath, `mipmap-${template.density}`, 'ic_launcher.png');
// This pipeline is trick, but we need two separate pipelines
// per https://github.com/lovell/sharp/issues/2378#issuecomment-864132578
const padding = 8;
const resized = await (0, sharp_1.default)(asset.path)
.resize(template.width, template.height)
// .composite([{ input: Buffer.from(svg), blend: 'dest-in' }])
.toBuffer();
const composited = await (0, sharp_1.default)(resized)
.resize(Math.max(0, template.width - padding * 2), Math.max(0, template.height - padding * 2))
.extend({
top: padding,
bottom: padding,
left: padding,
right: padding,
background: { r: 0, g: 0, b: 0, alpha: 0 },
})
.toBuffer();
const outputInfo = await (0, sharp_1.default)(composited).png().toFile(destRound);
return [destRound, outputInfo];
}
async generateRoundLauncherIcon(project, asset, template) {
const svg = `<svg width="${template.width}" height="${template.height}"><circle cx="${template.width / 2}" cy="${template.height / 2}" r="${template.width / 2}" fill="#ffffff"/></svg>`;
const resPath = this.getResPath(project);
const destRound = (0, path_1.join)(resPath, `mipmap-${template.density}`, 'ic_launcher_round.png');
// This pipeline is tricky, but we need two separate pipelines
// per https://github.com/lovell/sharp/issues/2378#issuecomment-864132578
const resized = await (0, sharp_1.default)(asset.path).resize(template.width, template.height).toBuffer();
const composited = await (0, sharp_1.default)(resized)
.composite([{ input: Buffer.from(svg), blend: 'dest-in' }])
.toBuffer();
const outputInfo = await (0, sharp_1.default)(composited).png().toFile(destRound);
return [destRound, outputInfo];
}
async generateAdaptiveIconForeground(asset, project) {
const icons = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "icon" /* Icon */);
const pipe = asset.pipeline();
if (!pipe) {
throw new error_1.BadPipelineError('Sharp instance not created');
}
return Promise.all(icons.map(async (icon) => {
return await this._generateAdaptiveIconForeground(project, asset, icon, pipe);
}));
}
async _generateAdaptiveIconForeground(project, asset, icon, pipe) {
const resPath = this.getResPath(project);
// Create the foreground and background images
const destForeground = (0, path_1.join)(resPath, `mipmap-${icon.density}`, 'ic_launcher_foreground.png');
const parentDir = (0, path_1.dirname)(destForeground);
if (!(await (0, utils_fs_1.pathExists)(parentDir))) {
await (0, utils_fs_1.mkdirp)(parentDir);
}
const outputInfoForeground = await pipe.resize(icon.width, icon.height).png().toFile(destForeground);
// Create the adaptive icon XML
const icLauncherXml = `
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background>
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
</background>
<foreground>
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
</foreground>
</adaptive-icon>
`.trim();
const mipmapAnyPath = (0, path_1.join)(resPath, `mipmap-anydpi-v26`);
if (!(await (0, utils_fs_1.pathExists)(mipmapAnyPath))) {
await (0, utils_fs_1.mkdirp)(mipmapAnyPath);
}
const destIcLauncher = (0, path_1.join)(mipmapAnyPath, `ic_launcher.xml`);
const destIcLauncherRound = (0, path_1.join)(mipmapAnyPath, `ic_launcher_round.xml`);
await (0, utils_fs_1.writeFile)(destIcLauncher, icLauncherXml);
await (0, utils_fs_1.writeFile)(destIcLauncherRound, icLauncherXml);
// Return the created files for this OutputAsset
return new output_asset_1.OutputAsset(icon, asset, project, {
[`mipmap-${icon.density}/ic_launcher_foreground.png`]: destForeground,
'mipmap-anydpi-v26/ic_launcher.xml': destIcLauncher,
'mipmap-anydpi-v26/ic_launcher_round.xml': destIcLauncherRound,
}, {
[`mipmap-${icon.density}/ic_launcher_foreground.png`]: outputInfoForeground,
});
}
async generateAdaptiveIconBackground(asset, project) {
const icons = Object.values(AndroidAssetTemplates).filter((a) => a.kind === "icon" /* Icon */);
const pipe = asset.pipeline();
if (!pipe) {
throw new error_1.BadPipelineError('Sharp instance not created');
}
return Promise.all(icons.map(async (icon) => {
return await this._generateAdaptiveIconBackground(project, asset, icon, pipe);
}));
}
async _generateAdaptiveIconBackground(project, asset, icon, pipe) {
const resPath = this.getResPath(project);
const destBackground = (0, path_1.join)(resPath, `mipmap-${icon.density}`, 'ic_launcher_background.png');
const parentDir = (0, path_1.dirname)(destBackground);
if (!(await (0, utils_fs_1.pathExists)(parentDir))) {
await (0, utils_fs_1.mkdirp)(parentDir);
}
const outputInfoBackground = await pipe.resize(icon.width, icon.height).png().toFile(destBackground);
// Create the adaptive icon XML
const icLauncherXml = `
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background>
<inset android:drawable="@mipmap/ic_launcher_background" android:inset="16.7%" />
</background>
<foreground>
<inset android:drawable="@mipmap/ic_launcher_foreground" android:inset="16.7%" />
</foreground>
</adaptive-icon>
`.trim();
const mipmapAnyPath = (0, path_1.join)(resPath, `mipmap-anydpi-v26`);
if (!(await (0, utils_fs_1.pathExists)(mipmapAnyPath))) {
await (0, utils_fs_1.mkdirp)(mipmapAnyPath);
}
const destIcLauncher = (0, path_1.join)(mipmapAnyPath, `ic_launcher.xml`);
const destIcLauncherRound = (0, path_1.join)(mipmapAnyPath, `ic_launcher_round.xml`);
await (0, utils_fs_1.writeFile)(destIcLauncher, icLauncherXml);
await (0, utils_fs_1.writeFile)(destIcLauncherRound, icLauncherXml);
// Return the created files for this OutputAsset
return new output_asset_1.OutputAsset(icon, asset, project, {
[`mipmap-${icon.density}/ic_launcher_background.png`]: destBackground,
'mipmap-anydpi-v26/ic_launcher.xml': destIcLauncher,
'mipmap-anydpi-v26/ic_launcher_round.xml': destIcLauncherRound,
}, {
[`mipmap-${icon.density}/ic_launcher_background.png`]: outputInfoBackground,
});
}
async updateManifest(project) {
var _a, _b;
(_b = (_a = project.android) === null || _a === void 0 ? void 0 : _a.getAndroidManifest()) === null || _b === void 0 ? void 0 : _b.setAttrs('manifest/application', {
'android:icon': '@mipmap/ic_launcher',
'android:roundIcon': '@mipmap/ic_launcher_round',
});
await project.commit();
}
async generateSplashes(asset, project) {
const pipe = asset.pipeline();
if (!pipe) {
throw new error_1.BadPipelineError('Sharp instance not created');
}
const splashes = (asset.kind === "splash" /* Splash */
? Object.values(AndroidAssetTemplates).filter((a) => a.kind === "splash" /* Splash */)
: Object.values(AndroidAssetTemplates).filter((a) => a.kind === "splash-dark" /* SplashDark */));
const resPath = this.getResPath(project);
const collected = await Promise.all(splashes.map(async (splash) => {
const [dest, outputInfo] = await this.generateSplash(project, asset, splash, pipe);
const relPath = (0, path_1.relative)(resPath, dest);
return new output_asset_1.OutputAsset(splash, asset, project, { [relPath]: dest }, { [relPath]: outputInfo });
}));
return collected;
}
async generateSplash(project, asset, template, pipe) {
const drawableDir = template.density ? `drawable-${template.density}` : 'drawable';
const resPath = this.getResPath(project);
const parentDir = (0, path_1.join)(resPath, drawableDir);
if (!(await (0, utils_fs_1.pathExists)(parentDir))) {
await (0, utils_fs_1.mkdirp)(parentDir);
}
const dest = (0, path_1.join)(resPath, drawableDir, 'splash.png');
const outputInfo = await pipe.resize(template.width, template.height).png().toFile(dest);
return [dest, outputInfo];
}
getResPath(project) {
var _a;
return (0, path_1.join)(project.config.android.path, 'app', 'src', (_a = this.options.androidFlavor) !== null && _a !== void 0 ? _a : 'main', 'res');
}
}
exports.AndroidAssetGenerator = AndroidAssetGenerator;