.NET MAUIのAndroid通知small iconが灰色になる理由と色を出す実装パターン大全(LocalPushNotification対応)

「色付きのPNGを指定したのに、通知の“小さなアイコン(small icon)”が灰色(単色)で出てしまう」。.NET MAUI/Androidでよく遭遇する疑問です。本記事はその原因を“仕様”から噛み砕いて説明し、実務で取るべき正攻法(white単色のsmall icon+large icon/スタイル活用/カスタムレイアウト)を、コードと作業手順・チェックリスト付きでまとめます。

目次

結論:small icon はアルファ(透明度)だけを見る「単色マスク」。色を維持する方法はない

Androidの通知における small icon(ステータスバーや通知シェード左端に表示される24×24dp相当の小アイコン)は、画像のアルファ(透明度)情報だけを読み取り、OS側が単色で塗りつぶして描画します。したがって、SetSmallIcon(Resource.Drawable.ic_push_notification_solid) のように黄色のPNGを渡しても、通知上では白〜グレーのモノクロに変換されます。これはAndroid 5.0(API 21)以降で一貫した挙動であり、コードや設定で「small iconをカラー表示」にするトグルは存在しません

ではどう見せるか:業務で使える3つの正攻法

目的対応方法備考
通知の規定位置に正しく小アイコンを出したい透過背景+白一色のPNGまたはVectorDrawableを用意し、SetSmallIcon()に指定塗りは白、背景は完全透過。線は太すぎず(1〜2dp目安)。
ブランドカラーや写真を見せたいSetLargeIcon()でカラー画像を渡す/BigPictureStyleカスタム通知レイアウトを使うlarge icon/ビッグピクチャはカラーで出せる。
種類ごとの違いを色で演出したいSetColor()(および通知チャンネルの色)でアクセントを付けるsmall icon自体は白のまま。通知ヘッダーやシェード背景に色が乗る。

.NET MAUI/NotificationCompat での実装例(最小構成)

using Android.App;
using Android.Graphics;
using Android.OS;
using AndroidX.Core.App;

const string CHANNEL_ID = "local_default";

void ShowNotification(Context context)
{
var manager = NotificationManagerCompat.From(context);


if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
    var channel = new NotificationChannel(
        CHANNEL_ID, "Default", NotificationImportance.Default)
    {
        Description = "Local notifications"
    };
    // アクセント(small iconの色ではない)
    channel.EnableLights(true);
    channel.LightColor = Color.Yellow;
    channel.EnableVibration(true);
    var sys = (NotificationManager)context.GetSystemService(Context.NotificationService);
    sys.CreateNotificationChannel(channel);
}

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
    // small icon は白単色。drawable名はすべて小文字・アンダースコア
    .SetSmallIcon(Resource.Drawable.ic_notification_white)
    // large icon はカラーOK
    .SetLargeIcon(BitmapFactory.DecodeResource(
        context.Resources, Resource.Drawable.ic_push_notification_solid))
    .SetContentTitle("タイトル")
    .SetContentText("本文")
    .SetAutoCancel(true)
    // アクセントカラー。通知全体の強調に使われる(small iconは白のまま)
    .SetColor(new Color(0xFF, 0xC1, 0x07)); // #FFC107

manager.Notify(1001, builder.Build());


} 

LocalPushNotification(.NET MAUI向けローカル通知プラグイン)を使う場合

プラグインを利用している場合も考え方は同じです。small iconには白単色のdrawable名、large iconにはカラーのdrawable名を指定します。

using Plugin.LocalNotification;

var request = new NotificationRequest
{
NotificationId = 1002,
Title = "タイトル",
Description = "本文",
Android = new AndroidOptions
{
// small icon(白単色)
IconSmallName = new AndroidIcon("ic_notification_white"),
// large icon(カラーOK)
IconLargeName = new AndroidIcon("ic_push_notification_solid"),
ChannelId = "local_default"
}
};

await LocalNotificationCenter.Current.Show(request); 

※プラグインのプロパティ名はバージョンで差異がありますが、smallは白単色・largeはカラーという原則は変わりません。

small icon のアセット作成ガイド(PNG/VectorDrawable)

作成ルール(実務の要点)

  • キャンバスは 24×24dp(mdpiなら24×24px)。
  • 塗りは白一色(#FFFFFFFF)。背景は完全透過
  • グリフは最大18dp程度に収め、上下左右に約3dpの余白を取ると視認性が安定。
  • アンチエイリアス前提のなめらかなエッジ、細線は1〜2dpを目安に。
  • リソース名はすべて小文字+アンダースコア(例:ic_notification_white)。

解像度(density)別の推奨ピクセルサイズ

用途mdpihdpixhdpixxhdpixxxhdpi
small icon(キャンバス)24×2436×3648×4872×7296×96
large icon(キャンバス)48×4872×7296×96144×144192×192

VectorDrawable でsmall iconを定義(API 21+)

VectorDrawableを使うと密度ごとのPNGを用意せずに済みます(small iconは単色である点に注意)。

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">


<path
    android:fillColor="#FFFFFFFF"
    android:pathData="M12,2L2,22h20L12,2z" />  <!-- サンプル:三角形 -->


 

配置場所(.NET MAUIの単一プロジェクト)例:

  • Platforms/Android/Resources/drawable-anydpi-v24/ic_notification_white.xml(ビルドアクション:AndroidResource
  • PNGで用意するなら Platforms/Android/Resources/drawable-xxxhdpi/... などdensity別に配置します。

「色を見せたい」を叶える実装パターン

1) Large Icon を併用

smallは白、largeでカラーを見せます。通知が展開されるとlargeが目立ちます。

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
    .SetSmallIcon(Resource.Drawable.ic_notification_white)
    .SetLargeIcon(BitmapFactory.DecodeResource(
        context.Resources, Resource.Drawable.ic_push_notification_solid))
    .SetContentTitle("新着メッセージ")
    .SetContentText("本文…");

2) BigPictureStyle でビジュアル訴求

var picture = BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.banner_hero);
var style = new NotificationCompat.BigPictureStyle()
    .BigPicture(picture)
    .BigLargeIcon(null); // 展開時はlarge iconを隠してビジュアルに集中

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.SetSmallIcon(Resource.Drawable.ic_notification_white)
.SetLargeIcon(BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.ic_push_notification_solid))
.SetStyle(style)
.SetContentTitle("本日のおすすめ")
.SetContentText("詳細はこちら"); 

3) カスタム通知レイアウト(RemoteViews)

より柔軟に色付き画像やブランドカラーを使いたい場合は、カスタムレイアウトを検討します。collapsed/expanded用のRemoteViewsを用意し、そこにカラー画像や装飾を配置します。small icon自体はルール通り白単色のままです。

var collapsed = new RemoteViews(context.PackageName, Resource.Layout.notification_collapsed);
var expanded  = new RemoteViews(context.PackageName, Resource.Layout.notification_expanded);

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.SetSmallIcon(Resource.Drawable.ic_notification_white)
.SetCustomContentView(collapsed)
.SetCustomBigContentView(expanded)
.SetStyle(new NotificationCompat.DecoratedCustomViewStyle()); 

※一部OEMやOSバージョンでレイアウトの余白・行間が異なるため、複数端末での検証が重要です。

アクセントカラーの使い方(SetColor() と通知チャンネル)

  • NotificationCompat.Builder.SetColor(Color) … 通知内の強調(ヘッダーやアクションの背景など)に影響。small iconの色は変わらない
  • Android 8.0+は通知チャンネル単位の設定が優先される場面があるため、色の設計は「チャンネル=文脈」単位で行うのが吉。
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
    var channel = new NotificationChannel(
        "news_alert", "ニュース", NotificationImportance.High)
    {
        Description = "ニュース速報"
    };
    channel.EnableLights(true);
    channel.LightColor = Color.ParseColor("#FF5252"); // チャンネルのアクセント
    var sys = (NotificationManager)context.GetSystemService(Context.NotificationService);
    sys.CreateNotificationChannel(channel);
}

var builder = new NotificationCompat.Builder(context, "news_alert")
.SetSmallIcon(Resource.Drawable.ic_notification_white)
.SetColor(Color.ParseColor("#FF5252")); 

MAUIプロジェクトでのリソース配置とビルド設定

  • 通知アイコンはAndroid固有のリソースのため、Platforms/Android/Resources/ 配下に配置。
  • ビルドアクションはAndroidResource(PNG/XMLいずれも)。
  • リソース名は小文字+アンダースコア。大文字・ハイフンは不可。
  • Adaptive Icon(アプリアイコン用)をsmall iconに流用しない。通知では単色のマスクが必要。

よくある落とし穴と対処

症状原因対処
アイコンが薄くて見えにくい線が細すぎ/余白が広すぎ線幅1.5〜2dp・余白3dp目安で描き直す。輪郭をはっきりさせる。
黒背景でつぶれる/白背景で埋もれるOSのテーマや通知シェードの色味による白単色+適切な余白に統一。色表現はlarge/スタイルで行う。
VectorDrawableが表示されない配置先やビルドアクションが誤りdrawable-anydpi-v24配下に置き、AndroidResourceに設定。
一部端末でサイズが不自然PNGの密度別リソースが不足mdpi〜xxxhdpiまで用意 or VectorDrawableに統一。
色が付かない(付けたい)仕様smallは単色。色はSetLargeIcon()/BigPicture/カスタムで。

デザイン指針(現場のコツ)

  • 意味が一目で分かる形状:ベル=通知、雲=アップロード、盾=セキュリティなど。
  • 線と面の対比:白塗りの面を主体に、細線は最小限。小サイズで潰れない形。
  • 余白の均等:左右非対称だと小ささの影響で傾いて見える。
  • バリエーション設計:イベント種別ごとにsmall iconの「形」を変える(色で区別は不可)。

「APIやOSバージョン違い」で知っておくと楽になるポイント

  • Android 5.0(API 21)以降:small iconはアルファマスク+単色描画。以降のバージョンでもこの原則は維持。
  • Adaptive Icon/monochromeレイヤー:これはアプリアイコン(ホーム画面)の話で、通知small iconとは無関係。
  • Dynamic Color(Material You):通知UIの色合いには影響し得るが、small icon自体がカラー化されることはない

テストのやり方(品質を落とさない運用)

  1. ライト/ダークテーマを切り替え表示を確認。
  2. 最小〜最大解像度(mdpi〜xxxhdpi)エミュレータで視認性をチェック。
  3. 通知の展開・非展開でレイアウト崩れがないか(large/BigPicture/カスタム)。
  4. 複数チャンネルでSetColor()の効き方を比較。
  5. 長文タイトル・本文・多ボタン配置時の折返し挙動を検証。

運用設計:通知チャンネルとアイコンの関係

通知の設計は「small=白単色(形で識別)」「large/スタイル=色や写真で訴求」という役割分担を前提に、チャンネル(用途)ごとにアイコンとアクセントカラーのペアを定義すると運用が安定します。たとえば「メッセージ」「システム」「キャンペーン」の3種類を用意し、それぞれでsmallの形とSetColor()の色を変える、といった設計です。

実務で使えるテンプレート(コピペ可)

通知ビルダー(.NET MAUI/Android)

public static class Notifier
{
    const string ChannelId = "app_default";


public static void EnsureChannel(Context context)
{
    if (Build.VERSION.SdkInt < BuildVersionCodes.O) return;

    var channel = new NotificationChannel(
        ChannelId, "一般通知", NotificationImportance.Default)
    {
        Description = "アプリの一般通知"
    };
    channel.EnableLights(true);
    channel.LightColor = Android.Graphics.Color.ParseColor("#2962FF");
    channel.EnableVibration(true);

    var sys = (NotificationManager)context.GetSystemService(Context.NotificationService);
    sys.CreateNotificationChannel(channel);
}

public static void SendBasic(Context context, string title, string message)
{
    EnsureChannel(context);

    var builder = new NotificationCompat.Builder(context, ChannelId)
        .SetSmallIcon(Resource.Drawable.ic_notification_white)
        .SetContentTitle(title)
        .SetContentText(message)
        .SetAutoCancel(true)
        .SetColor(Android.Graphics.Color.ParseColor("#2962FF"));

    NotificationManagerCompat.From(context).Notify(Random.Shared.Next(), builder.Build());
}

public static void SendWithLargeIcon(Context context, string title, string message, int largeIconRes)
{
    EnsureChannel(context);

    var builder = new NotificationCompat.Builder(context, ChannelId)
        .SetSmallIcon(Resource.Drawable.ic_notification_white)
        .SetLargeIcon(BitmapFactory.DecodeResource(context.Resources, largeIconRes))
        .SetContentTitle(title)
        .SetContentText(message)
        .SetAutoCancel(true);

    NotificationManagerCompat.From(context).Notify(Random.Shared.Next(), builder.Build());
}

public static void SendBigPicture(Context context, string title, string message, int pictureRes)
{
    EnsureChannel(context);

    var picture = BitmapFactory.DecodeResource(context.Resources, pictureRes);
    var style = new NotificationCompat.BigPictureStyle()
        .BigPicture(picture)
        .BigLargeIcon(null);

    var builder = new NotificationCompat.Builder(context, ChannelId)
        .SetSmallIcon(Resource.Drawable.ic_notification_white)
        .SetStyle(style)
        .SetContentTitle(title)
        .SetContentText(message)
        .SetAutoCancel(true);

    NotificationManagerCompat.From(context).Notify(Random.Shared.Next(), builder.Build());
}


} 

アセット配置の雛形(プロジェクト構成)

MyMauiApp/
├─ Resources/
│  └─ Images/                        &lt;-- 画面用の通常画像(通知smallには使わない)
├─ Platforms/
│  └─ Android/
│     └─ Resources/
│        ├─ drawable-anydpi-v24/
│        │  └─ ic_notification_white.xml  &lt;-- small icon(白単色Vector)
│        ├─ drawable-xxxhdpi/
│        │  └─ ic_push_notification_solid.png  &lt;-- large icon(カラー)
│        └─ layout/
│           ├─ notification_collapsed.xml
│           └─ notification_expanded.xml

FAQ

Q. small iconを黄色にしたい。非推奨でも良いので方法は?
A. small iconは仕様で単色化されます。回避策はありません。黄色を見せたい場合は SetLargeIcon()・BigPictureStyle・カスタムレイアウトで表現します。

Q. SetColor()でsmallの色を変えられませんか?
A. 変えられません。SetColor()は通知のアクセントで、small icon(アルファマスク)の描画色には直接影響しません。

Q. Adaptive Iconのmonochromeレイヤーは使えますか?
A. それはアプリアイコン(ホーム画面)用です。通知のsmall iconとは別物です。

Q. .NET MAUIで画像をResources/Imagesに置いたが参照できません
A. 通知アイコンはAndroid固有のリソース(Platforms/Android/Resources/drawable...)として配置し、ビルドアクションをAndroidResourceに設定します。

Q. VectorDrawableの色をテーマに合わせて変えられますか?
A. small iconはOS側で単色化されるため、テーマ色での塗り替えは発生しません(小アイコンとしては常にモノクロ)。

チェックリスト(導入前・リリース前に確認)

  • small iconは白単色・透過背景・適切な余白か。
  • densityごとのPNG、またはVectorDrawableで網羅できているか。
  • 通知チャンネルが用途ごとに分かれ、アクセント色が設計されているか。
  • large iconやBigPictureで色表現を補えているか。
  • ライト/ダーク、各density、主要OEMスキンで視認性を確認したか。

サンプル:色付きPNGを渡しても灰色になる再現

以下のコードは、SetSmallIcon()にカラーPNGを指定していますが、通知上ではOSにより白〜グレーで描画されます(仕様)。

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
    .SetSmallIcon(Resource.Drawable.ic_push_notification_solid) // 黄色PNGを渡しても…
    .SetContentTitle("色は付かない")
    .SetContentText("small iconはOSが単色で描画します。");

これを次のように直せば、意図通りの表示になります。

var builder = new NotificationCompat.Builder(context, CHANNEL_ID)
    .SetSmallIcon(Resource.Drawable.ic_notification_white) // 白単色
    .SetLargeIcon(BitmapFactory.DecodeResource(
        context.Resources, Resource.Drawable.ic_push_notification_solid)) // カラーはlargeへ
    .SetContentTitle("正しい使い分け")
    .SetContentText("small=白、large/スタイル=色付きで訴求。");

まとめ

Androidの通知におけるsmall iconは、「アルファだけを読むマスク」+「OSの単色塗り」という厳格な仕様が基本です。色を維持させる回避策は存在しません。代わりに、smallは白単色で形の識別large/BigPicture/カスタムで色表現という役割分担に切り替えましょう。.NET MAUIでも、リソース配置(AndroidResource)、ビルド設定、通知チャンネル設計を押さえれば、見やすく・ブランド感も両立した通知が実装できます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次