はじめに
日常生活や仕事において、スマホアプリを頻繁に利用する方は、iPhoneユーザーが多いように感じます。
それによってAndroid向けの機能が軽視されているというわけではありませんが、優先順位はやや低い傾向にあると思います。
そこで、普段からAndroidを利用している身として、
「対応されていたら嬉しい!」 と思える機能を、Flutterを用いた実現方法も含めていくつかご紹介します。
🔨アイコン - Themed App Icons
テーマ | ライトモード | ダークモード |
---|---|---|
デフォルト | - | |
青系の壁紙 | ||
赤系の壁紙 |
Android13から追加された機能です。
設定を行うことで、壁紙や設定した色、テーマモードに応じてアイコンが切り替わります。
少し前の内容にはなりますが、概要はツルオカさんが記事にまとめて下さっています。
そちらをご覧下さい。
筆者にとっては、アプリをホームに配置する動機となる機能です。
実装
概要は前述した記事で掲載されていますが、
現在ではパッケージ開発が進んだこともあり、flutter_launcher_iconsパッケージでも対応されました。
ただ、私は環境ごと(開発/本番)のThemed App Iconへの対応など、細かい設定が好みでicons_launcherを利用しています。
私の個人開発アプリを例に設定していきます。
1. アプリアイコン画像の作成
まずはアプリアイコンの画像を作成します。
私はFigmaのテンプレートを利用してアプリアイコンを作成しています。
作成する画像は2種類です
- 通常のアプリアイコン
- モノクロ化されたアプリアイコン
通常 | モノクロ |
---|---|
任意のフォルダに作成したアプリアイコンを配置します。
2. icons_launcher
パッケージのセットアップ
セットアップはパッケージに記載されている方法の通り対応していきます。
3. アイコンの配置/生成
Themed App Iconへの対応は、adaptive_monochrome_image:
の記載を追加することで対応できます。
icons_launcher:
image_path: "assets/launcher_icon/icon.png"
platforms:
android:
enable: true
image_path: "assets/launcher_icon/icon.png"
adaptive_background_color: '#FFFFFF'
adaptive_foreground_image: "assets/launcher_icon/icon_adaptive.png"
adaptive_round_image: "assets/launcher_icon/icon_adaptive.png"
# 用意したモノクロ写真の設定を追加
adaptive_monochrome_image: "assets/launcher_icon/icon_adaptive_monochrome.png"
ios:
enable: true
image_path: "assets/launcher_icon/icon.png"
設定が完了したらコマンドを叩いてプラットフォーム別のアイコンを生成します。
dart run icons_launcher:create
Themed App Iconに対応した画像ファイルが生成されました🎉
🎨テーマカラー - Dynamic Color
アプリテーマ | テーマカラー緑 |
---|---|
青系の壁紙 | 赤系の壁紙 |
Android13から追加された機能です。
設定を行うことで、壁紙や設定した色、テーマモードに応じてアプリのテーマカラーが切り替わります。
前述した機能のアプリテーマカラー版です。
こちらの機能は賛否両論あり、
大手ではGoogle製アプリしか対応されていない印象です。
私も 「企業(アプリ)のテーマカラーが定着し辛い」 と思い、最初は躊躇していました。
しかし、monoca2 の影響を受け、今はとても気に入ってます。
monoca2では、テーマカラーを選択でき、その一種としてダイナミックカラーが提供されています。
実装
基本はdynamic_colorパッケージで対応されています。
しかし、Flutter 3.22.0で行われたColorScheme
の変更1に対応されていません。
実際にアプリに組み込むことを想定し、2つの対応を行った例を記載します。
- Flutter 3.22.0で行われた破壊的変更への対応
- テーマカラーの一種として提供する方法
例では状態管理としてriverpodを利用しています。
1. dynamic_color
パッケージの追加
公式の手順を参考にパッケージの追加を行います。
2. アプリのテーマカラーを選択可能にする
まずはアプリのテーマカラーを選択できるように対応します。
テーマカラーをEnum
で定義し、Notifier
によって状態管理を行います。
/// ユーザーが選択可能なテーマカラー
enum ThemeColor {
appColor(null, 'アプリ内テーマ'),
dynamicColor(null, 'デバイスのテーマカラー'),
blue(Colors.blue, 'ブルー'),
purple(Colors.purple, 'パープル'),
pink(Colors.pink, 'ピンク'),
red(Colors.red, 'レッド'),
orange(Colors.orange, 'オレンジ'),
yellow(Colors.yellow, 'イエロー'),
green(Colors.green, 'グリーン');
const ThemeColor(this.seedColor, this.description);
static List<ThemeColor> get colorValues =>
values.where((i) => i.seedColor != null).toList();
static List<ThemeColor> get systemValues =>
values.where((i) => i.seedColor == null).toList();
final Color? seedColor;
final String description;
}
/// アプリ内テーマカラー
/// 本来は`SharedPreferences`などで情報を永続化する
/// サンプルプログラムのためインメモリで保持
@riverpod
class ThemeColorNotifier extends _$ThemeColorNotifier {
@override
ThemeColor build() => ThemeColor.appColor;
void update({required ThemeColor themeColor}) {
state = themeColor;
}
}
今回はインメモリで管理していますが、実際にはshared_preferencesなどを利用して、設定を永続化させます。
3. デバイスのテーマカラーを管理するProviderの定義
テーマカラーの一種として提供するのに管理し辛いため、DynamicBuilder
は利用しません。
DynamicBuilder
の内部実装を参考にします。
デバイスのテーマカラーを取得するためには、DynamicColorPlugin.getCorePalette()
という処理を呼びします。
取得したテーマカラーをProviderで管理します。
/// DynamicColorのCorePaletteを管理
@Riverpod(keepAlive: true)
Future<CorePalette?> dynamicCorePalette(Ref ref) async {
// 未対応のWebでは取得処理を呼び出さない
if (kIsWeb) {
return null;
}
return DynamicColorPlugin.getCorePalette();
}
4. 利用するColorScheme
を管理するProviderを定義する
アプリ内のテーマカラーを切り替えるために、アプリ内のColorScheme
をProviderで管理します。
前述した2つのProviderを用いて、利用されるColorScheme
を決定する役割です。
まずは完成コードを記載します。
/// アプリ内のカラースキーマを管理
@riverpod
ColorScheme appColorScheme(Ref ref, {required Brightness brightness}) {
// 「選択されたテーマカラー」と「デバイスのテーマカラー」を基に設定
final themeColor = ref.watch(themeColorNotifierProvider);
final dynamicCorePalette = ref.watch(dynamicCorePaletteProvider).value;
// テーマカラーに応じたカラースキーマを取得
final colorScheme = _colorScheme(brightness, themeColor, dynamicCorePalette);
// Dynamic Colorに対応している場合、背景色とエラー関連の色を調和する
final isDynamicColorSupported = dynamicCorePalette != null;
return isDynamicColorSupported ? colorScheme.harmonized() : colorScheme;
}
詳細を記載していきます。
ColorSchemeの決定
// テーマカラーに応じたカラースキーマを取得
final colorScheme = _colorScheme(brightness, themeColor, dynamicCorePalette);
ここでは以下の情報を基に利用されるColorScheme
を取得しています。
- テーマモード
- 選択されたテーマカラー
- デバイスのテーマカラー
詳細な条件は下記の通り記載しています。
/// テーマカラーに応じたカラースキーマ
ColorScheme _colorScheme(
Brightness brightness,
ThemeColor themeColor,
CorePalette? dynamicCorePalette,
) {
switch (themeColor) {
case ThemeColor.appColor:
return _defaultColorScheme(brightness);
case ThemeColor.dynamicColor:
// DynamicColorに対応していない場合は、アプリのテーマカラーを設定
if (dynamicCorePalette == null) {
return _defaultColorScheme(brightness);
}
// デバイスのテーマカラーを基にカラースキーマを生成
final dynamicColorScheme =
dynamicCorePalette.toColorScheme(brightness: brightness);
// [暫定対応] Flutter3.22.0で行われた`ColorScheme`の破壊的変更への対応
return generateDynamicColourSchemes(dynamicColorScheme);
case ThemeColor.blue:
case ThemeColor.purple:
case ThemeColor.pink:
case ThemeColor.red:
case ThemeColor.orange:
case ThemeColor.yellow:
case ThemeColor.green:
// テーマカラーが選択された場合は、対応する色を基に生成
return ColorScheme.fromSeed(
seedColor: themeColor.seedColor!,
brightness: brightness,
);
}
}
generateDynamicColourSchemes
は前述した破壊的変更への対応です。
デバイスのテーマカラーとの調和
// Dynamic Colorに対応している場合、エラー色を調和する
final isDynamicColorSupported = dynamicCorePalette != null;
return isDynamicColorSupported ? colorScheme.harmonized() : colorScheme;
最後に行っている処理は、エラー色の調和です。
今回は対応方法の記載なので、詳細は割愛させください。
前述したツルオカさんの記事で説明されていますので、興味のある方はぜひご覧ください。
5. アプリが利用するテーマを変更する
MaterialApp
に対してProviderで管理しているColorScheme
を設定すれば完了です。
class DynamicColorApp extends ConsumerWidget {
const DynamicColorApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final lightColorScheme =
ref.watch(appColorSchemeProvider(brightness: Brightness.light));
final darkColorScheme =
ref.watch(appColorSchemeProvider(brightness: Brightness.dark));
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const SamplePage(),
// Providerで管理した`ColorScheme`を基にアプリテーマを設定
theme: ThemeData(colorScheme: lightColorScheme),
darkTheme:
ThemeData(colorScheme: darkColorScheme, brightness: Brightness.dark),
);
}
}
themeColorNotifierProvider
で管理しているテーマカラーを切り替えることで、アプリの配色が変更されました🎉
🕶️【番外編】色のコントラスト - Color contrast
デフォルト | 中 | 高 |
---|---|---|
Android14から追加された機能です。
設定を行うことで、自分の見やすいコントラストに合わせてアプリのテーマカラーを切り替えることができます。
この機能は対応してほしいというわけではありません。
アクセシビリティのため、今後対応したい機能となります。
現状、Flutterやパッケージなどで対応されていないようですが、ネイティブ機能を呼び出すことで対応可能です。
こちらは別記事でまとめています。
興味のある方はぜひご覧下さい。
🗨️プッシュ通知 - Notification Channels
YouTube | Google Play Store | X (Twitter) |
---|---|---|
Android8から追加された機能です。
対応することで、種類に応じた通知設定をAndroidの設定アプリから切り替えることができます。
通知の種類まで分かれていると理想ですが、対応規模が前述したものと比べて肥大化します。
ユーザーへの通知要件から整理しないといけないですからね。
取り上げたいのは、
「一種類しかなくともユーザーには見える」 という点です。
ユーザーにとって意味が分からない内容を表示することは避け、ユーザーフレンドリーな名称を設定したいです。
私もこちらの記事でハッとさせられました。
実装
今回はカンタンに対応できる後者への対応を例に記載します。
PUSH通知を導入する場合、firebase_messagingパッケージを利用することが多いと思います。
ですが、Androidの通知チャネルやフォアグラウンド通知は多少メンドウです。
そこで、要件を満たすのであればfcm_configパッケージをおすすめします。
通知の設定自体は趣旨が異なりますので、パッケージを参照して下さい。
本題となる通知チャネル名の設定自体は下記の1行で設定可能です。
設定の手間はほぼないので、適当な値を設定することは避けましょう。(自戒)
await FCMConfig.instance.init(
defaultAndroidForegroundIcon: '@mipmap/ic_launcher',
defaultAndroidChannel: AndroidNotificationChannel(
'channel_id',
// 本題となるチャネル名
'[アプリ名]からのお知らせ',
importance: Importance.high,
sound: RawResourceAndroidNotificationSound('notification'),
),
);
🙇あとがき
最後まで読んでいただきありがとうございます!
主観強めの内容ではありましたが、
いちAndroidユーザーの声としてまとめてみました。
他にも「この機能が対応されていると嬉しい!」などあればコメント頂けると幸いです。
教えて頂いた機能についても、実現方法を調べたいと思います。