From aa5b6899598099deb5bef96ce1977c8377b9c2ce Mon Sep 17 00:00:00 2001 From: Michael Gerullis Date: Thu, 16 Jan 2025 19:22:11 +0100 Subject: [PATCH 1/5] typing, naming --- src/platforms/ios/index.ts | 12 ++++++------ src/tasks/generate.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/platforms/ios/index.ts b/src/platforms/ios/index.ts index 7006f51..2db4e82 100644 --- a/src/platforms/ios/index.ts +++ b/src/platforms/ios/index.ts @@ -63,7 +63,7 @@ export class IosAssetGenerator extends AssetGenerator { throw new BadPipelineError('Sharp instance not created'); } - const iosDir = project.config.ios!.path!; + const iosDir = project.config.ios?.path ?? 'App'; // Generate logos let logos: OutputAsset[] = []; @@ -179,7 +179,7 @@ export class IosAssetGenerator extends AssetGenerator { throw new BadPipelineError('Sharp instance not created'); } - const iosDir = project.config.ios!.path!; + const iosDir = project.config.ios?.path ?? 'App'; const lightDefaultBackground = '#ffffff'; const generated = await Promise.all( icons.map(async (icon) => { @@ -242,7 +242,7 @@ export class IosAssetGenerator extends AssetGenerator { const generated: OutputAsset[] = []; for (const assetMeta of assetMetas) { - const iosDir = project.config.ios!.path!; + const iosDir = project.config.ios?.path ?? 'App'; const dest = join(iosDir, IOS_SPLASH_IMAGE_SET_PATH, assetMeta.name); const outputInfo = await pipe.resize(assetMeta.width, assetMeta.height).png().toFile(dest); @@ -273,7 +273,7 @@ export class IosAssetGenerator extends AssetGenerator { } private async updateIconsContentsJson(generated: OutputAsset[], project: Project) { - const assetsPath = join(project.config.ios!.path!, IOS_APP_ICON_SET_PATH); + const assetsPath = join(project.config.ios?.path ?? 'App', IOS_APP_ICON_SET_PATH); const contentsJsonPath = join(assetsPath, 'Contents.json'); const json = await readFile(contentsJsonPath, { encoding: 'utf-8' }); @@ -304,7 +304,7 @@ export class IosAssetGenerator extends AssetGenerator { } private async updateSplashContentsJson(generated: OutputAsset[], project: Project) { - const contentsJsonPath = join(project.config.ios!.path!, IOS_SPLASH_IMAGE_SET_PATH, 'Contents.json'); + const contentsJsonPath = join(project.config.ios?.path ?? 'App', IOS_SPLASH_IMAGE_SET_PATH, 'Contents.json'); const json = await readFile(contentsJsonPath, { encoding: 'utf-8' }); const parsed = JSON.parse(json); @@ -334,7 +334,7 @@ export class IosAssetGenerator extends AssetGenerator { } private async updateSplashContentsJsonDark(generated: OutputAsset[], project: Project) { - const contentsJsonPath = join(project.config.ios!.path!, IOS_SPLASH_IMAGE_SET_PATH, 'Contents.json'); + const contentsJsonPath = join(project.config.ios?.path ?? 'App', IOS_SPLASH_IMAGE_SET_PATH, 'Contents.json'); const json = await readFile(contentsJsonPath, { encoding: 'utf-8' }); const parsed = JSON.parse(json); diff --git a/src/tasks/generate.ts b/src/tasks/generate.ts index 37b3498..2f20499 100644 --- a/src/tasks/generate.ts +++ b/src/tasks/generate.ts @@ -93,8 +93,8 @@ async function generateAssets(assets: Assets, generators: AssetGenerator[], proj const generated: OutputAsset[] = []; async function generateAndCollect(asset: InputAsset) { - const g = await Promise.all(generators.map((g) => asset.generate(g, project))); - generated.push(...(g.flat().filter((f) => !!f) as OutputAsset[])); + const output = await Promise.all(generators.map((g) => asset.generate(g, project))); + generated.push(...(output.flat().filter((f) => !!f) as OutputAsset[])); } const assetTypes = Object.values(assets).filter((v) => !!v); From a4ccb40ef1bbb51be15bb793ca460bea316a0bf4 Mon Sep 17 00:00:00 2001 From: Michael Gerullis Date: Thu, 16 Jan 2025 19:22:52 +0100 Subject: [PATCH 2/5] fix notification support --- src/definitions.ts | 10 ++++- src/platforms/android/assets.ts | 48 +++++++++++++++++++++ src/platforms/android/index.ts | 76 +++++++++++++++++++++++++++++++-- 3 files changed, 130 insertions(+), 4 deletions(-) diff --git a/src/definitions.ts b/src/definitions.ts index 42160dd..17095be 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -142,12 +142,20 @@ export interface PwaOutputAssetTemplate extends OutputAssetTemplate { } export interface AndroidOutputAssetTemplate extends OutputAssetTemplate { - density: AndroidDensity; + density?: AndroidDensity; } + +export interface AndroidNotificationTemplate extends AndroidOutputAssetTemplate { + kind: AssetKind.NotificationIcon; + width: number; + height: number; +} + export interface AndroidOutputAssetTemplateSplash extends OutputAssetTemplate { density: AndroidDensity; orientation: Orientation; } + export interface AndroidOutputAssetTemplateAdaptiveIcon extends OutputAssetTemplate { density: AndroidDensity; } diff --git a/src/platforms/android/assets.ts b/src/platforms/android/assets.ts index 37592d6..f47b17b 100644 --- a/src/platforms/android/assets.ts +++ b/src/platforms/android/assets.ts @@ -59,6 +59,54 @@ export const ANDROID_XXXHDPI_ICON: AndroidOutputAssetTemplate = { density: AndroidDensity.Xxxhdpi, }; +/** + * Notification icons + */ +export const ANDROID_NOTIFICATION_MDPI_ICON: AndroidOutputAssetTemplate = { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: 24, + height: 24, + density: AndroidDensity.Mdpi, +}; + +export const ANDROID_NOTIFICATION_HDPI_ICON: AndroidOutputAssetTemplate = { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: 36, + height: 36, + density: AndroidDensity.Hdpi, +}; + +export const ANDROID_NOTIFICATION_XHDPI_ICON: AndroidOutputAssetTemplate = { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: 48, + height: 48, + density: AndroidDensity.Xhdpi, +}; + +export const ANDROID_NOTIFICATION_XXHDPI_ICON: AndroidOutputAssetTemplate = { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: 72, + height: 72, + density: AndroidDensity.Xxhdpi, +}; + +export const ANDROID_NOTIFICATION_XXXHDPI_ICON: AndroidOutputAssetTemplate = { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: 144, + height: 144, + density: AndroidDensity.Xxxhdpi, +}; + /** * Adaptive icons */ diff --git a/src/platforms/android/index.ts b/src/platforms/android/index.ts index 8d1b7c3..a84eb49 100644 --- a/src/platforms/android/index.ts +++ b/src/platforms/android/index.ts @@ -10,13 +10,14 @@ import type { AndroidOutputAssetTemplate, AndroidOutputAssetTemplateAdaptiveIcon, AndroidOutputAssetTemplateSplash, + AndroidNotificationTemplate, } from '../../definitions'; -import { AssetKind, Platform } from '../../definitions'; +import { AssetKind, Format, Platform } from '../../definitions'; import { BadPipelineError, BadProjectError } from '../../error'; import type { InputAsset } from '../../input-asset'; import { OutputAsset } from '../../output-asset'; import type { Project } from '../../project'; -import { warn } from '../../util/log'; +import { warn, error } from '../../util/log'; import * as AndroidAssetTemplates from './assets'; @@ -35,7 +36,6 @@ export class AndroidAssetGenerator extends AssetGenerator { if (asset.platform !== Platform.Any && asset.platform !== Platform.Android) { return []; } - switch (asset.kind) { case AssetKind.Logo: case AssetKind.LogoDark: @@ -49,6 +49,8 @@ export class AndroidAssetGenerator extends AssetGenerator { case AssetKind.Splash: case AssetKind.SplashDark: return this.generateSplashes(asset, project); + case AssetKind.NotificationIcon: + return this.generateNotificationIcons(asset, project); } return []; @@ -525,4 +527,72 @@ export class AndroidAssetGenerator extends AssetGenerator { private getResPath(project: Project): string { return join(project.config.android!.path!, 'app', 'src', this.options.androidFlavor ?? 'main', 'res'); } + + private async generateNotificationIcons(asset: InputAsset, project: Project): Promise { + const pipe = asset.pipeline(); + if (!pipe) { + throw new BadPipelineError('Sharp instance not created'); + } + + const notificationTemplates = Object.values(AndroidAssetTemplates).filter( + (a) => a.kind === AssetKind.NotificationIcon, + ) as AndroidNotificationTemplate[]; + const resPath = this.getResPath(project); + const generated: OutputAsset[] = []; + + for (const template of notificationTemplates) { + try { + const drawablePath = join(resPath, `drawable-${template.density}`); + if (!(await pathExists(drawablePath))) { + await mkdirp(drawablePath); + } + + const destFile = join(drawablePath, 'ic_stat_notification.png'); + const outputInfo = await pipe.resize(template.width, template.height).png().toFile(destFile); + + const relPath = relative(resPath, destFile); + generated.push(new OutputAsset(template, asset, project, { [relPath]: destFile }, { [relPath]: outputInfo })); + } catch (err) { + error(`Failed to generate ${template.density} notification icon:`, err); + } + } + + // Generate for main drawable folder + try { + const mainDrawablePath = join(resPath, 'drawable'); + if (!(await pathExists(mainDrawablePath))) { + await mkdirp(mainDrawablePath); + } + + const mainDestFile = join(mainDrawablePath, 'ic_stat_notification.png'); + const outputInfo = await pipe + .resize( + AndroidAssetTemplates.ANDROID_NOTIFICATION_XXXHDPI_ICON.width, + AndroidAssetTemplates.ANDROID_NOTIFICATION_XXXHDPI_ICON.height, + ) + .png() + .toFile(mainDestFile); + + const relPath = relative(resPath, mainDestFile); + generated.push( + new OutputAsset( + { + platform: Platform.Android, + kind: AssetKind.NotificationIcon, + format: Format.Png, + width: AndroidAssetTemplates.ANDROID_NOTIFICATION_XXXHDPI_ICON.width, + height: AndroidAssetTemplates.ANDROID_NOTIFICATION_XXXHDPI_ICON.height, + }, + asset, + project, + { [relPath]: mainDestFile }, + { [relPath]: outputInfo }, + ), + ); + } catch (err) { + error('Failed to generate main notification icon:', err); + } + + return generated; + } } From 60e9b39707596562ba0ba59267b1926bdff28dfe Mon Sep 17 00:00:00 2001 From: Michael Gerullis Date: Thu, 16 Jan 2025 19:24:14 +0100 Subject: [PATCH 3/5] add changeset --- .changeset/notification-icons-support.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/notification-icons-support.md diff --git a/.changeset/notification-icons-support.md b/.changeset/notification-icons-support.md new file mode 100644 index 0000000..4b78476 --- /dev/null +++ b/.changeset/notification-icons-support.md @@ -0,0 +1,11 @@ +--- +'@capacitor/assets': minor +--- + +Added support for Android notification icons: +- Enhanced existing notification icon support with proper template handling +- Added notification icon templates for all Android densities (mdpi through xxxhdpi) +- Generates notification icons in drawable-{density} folders +- Copies highest resolution icon to main drawable folder +- Uses existing asset generation pipeline and OutputAsset system +- Maintains consistent file naming (ic_stat_notification.png) \ No newline at end of file From 80060ed9ae0321f8cee7237824731c178e3c6532 Mon Sep 17 00:00:00 2001 From: Michael Gerullis Date: Thu, 16 Jan 2025 19:26:28 +0100 Subject: [PATCH 4/5] typing --- src/definitions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/definitions.ts b/src/definitions.ts index 17095be..c746a17 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -142,7 +142,7 @@ export interface PwaOutputAssetTemplate extends OutputAssetTemplate { } export interface AndroidOutputAssetTemplate extends OutputAssetTemplate { - density?: AndroidDensity; + density: AndroidDensity; } export interface AndroidNotificationTemplate extends AndroidOutputAssetTemplate { From 61009cd9a5bd394a4e9986fa1f1fb5e535e1a6fd Mon Sep 17 00:00:00 2001 From: Michael Gerullis Date: Thu, 16 Jan 2025 19:34:32 +0100 Subject: [PATCH 5/5] changeset --- .changeset/notification-icons-support.md | 11 ----------- .changeset/proud-ways-compare.md | 5 +++++ 2 files changed, 5 insertions(+), 11 deletions(-) delete mode 100644 .changeset/notification-icons-support.md create mode 100644 .changeset/proud-ways-compare.md diff --git a/.changeset/notification-icons-support.md b/.changeset/notification-icons-support.md deleted file mode 100644 index 4b78476..0000000 --- a/.changeset/notification-icons-support.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@capacitor/assets': minor ---- - -Added support for Android notification icons: -- Enhanced existing notification icon support with proper template handling -- Added notification icon templates for all Android densities (mdpi through xxxhdpi) -- Generates notification icons in drawable-{density} folders -- Copies highest resolution icon to main drawable folder -- Uses existing asset generation pipeline and OutputAsset system -- Maintains consistent file naming (ic_stat_notification.png) \ No newline at end of file diff --git a/.changeset/proud-ways-compare.md b/.changeset/proud-ways-compare.md new file mode 100644 index 0000000..810784f --- /dev/null +++ b/.changeset/proud-ways-compare.md @@ -0,0 +1,5 @@ +--- +'@capacitor/assets': minor +--- + +Added support for Android notification icons