شارك المقالة

تغيير أيقونة تطبيق Flutter أثناء التشغيل من المميزات الجميلة التي يمكن أن تضيف تجربة مختلفة داخل التطبيق، خصوصًا لو كنت تريد تغيير شكل التطبيق حسب الموسم، العروض، المناسبات، أو وضع معين داخل التطبيق.

بدل ما تكتفي بأيقونة واحدة ثابتة للتطبيق، يمكنك توفير أكثر من أيقونة، ثم تغيير الأيقونة برمجيًا من داخل Flutter باستخدام مكتبة جاهزة تسهّل التعامل مع Android و iOS.

في هذا المقال سنتعلم طريقة تغيير أيقونة تطبيق Flutter بسهولة وبدون تعقيد باستخدام مكتبة dynamic_app_icon_flutter_plus، مع شرح إعدادات Android و iOS خطوة بخطوة، بالإضافة إلى مثال عملي كامل.

ما المقصود بتغيير أيقونة التطبيق أثناء التشغيل؟

تغيير أيقونة التطبيق أثناء التشغيل أو ما يعرف باسم Dynamic App Icon يعني أن التطبيق يمكنه تغيير الأيقونة التي تظهر على شاشة الهاتف بدون الحاجة إلى تثبيت نسخة جديدة من التطبيق.

مثلًا، يمكنك جعل التطبيق يستخدم:

  • أيقونة افتراضية للتطبيق
  • أيقونة للوضع الداكن
  • أيقونة خاصة بشهر رمضان
  • أيقونة خاصة بالعروض والخصومات
  • أيقونة خاصة بالمناسبات أو الحملات التسويقية

الميزة دي مفيدة جدًا لو تريد جعل التطبيق أكثر تفاعلًا مع المستخدمين أو مع الأحداث المختلفة.

لماذا نستخدم dynamic_app_icon_flutter_plus؟

مكتبة dynamic_app_icon_flutter_plus توفر طريقة سهلة لتغيير أيقونة التطبيق داخل Flutter، بدل ما تتعامل يدويًا مع تفاصيل Android و iOS المعقدة.

المكتبة تساعدك في:

  • تغيير أيقونة التطبيق على Android
  • تغيير أيقونة التطبيق على iOS
  • التحقق هل الجهاز يدعم تغيير الأيقونة أم لا
  • الحصول على الأيقونات المتاحة داخل التطبيق
  • الرجوع إلى الأيقونة الأصلية بسهولة
  • التعامل مع الفروق بين Android و iOS بطريقة أبسط

تثبيت مكتبة dynamic_app_icon_flutter_plus

أول خطوة هي إضافة المكتبة داخل ملف pubspec.yaml.

dependencies:
  flutter:
    sdk: flutter

  dynamic_app_icon_flutter_plus: ^1.0.0

بعد إضافة المكتبة، شغل الأمر التالي:

flutter pub get

بعد ذلك نبدأ في إعداد Android و iOS حتى يستطيع التطبيق تغيير الأيقونة بشكل صحيح.

إعدادات Android لتغيير أيقونة تطبيق Flutter

في Android، الطريقة الأصلية لتغيير أيقونة التطبيق تعتمد على استخدام activity-alias داخل ملف AndroidManifest.xml.

الفكرة ببساطة أنك تقوم بتعريف أكثر من Alias لكل أيقونة، وكل Alias يشير إلى نفس MainActivity، لكن بأيقونة مختلفة.

مكان ملف AndroidManifest.xml

افتح الملف التالي داخل مشروع Flutter:

android/app/src/main/AndroidManifest.xml

ثم أضف activity-alias داخل وسم application.

مثال على activity-alias في Android

<activity-alias
    android:name="com.example.yourapp.MainActivity.dark"
    android:targetActivity=".MainActivity"
    android:exported="true"
    android:icon="@mipmap/ic_launcher_dark"
    android:label="@string/app_name"
    android:enabled="false">

    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>

</activity-alias>

في المثال السابق قمنا بتعريف أيقونة بديلة باسم dark، وهي تستخدم الصورة الموجودة داخل:

@mipmap/ic_launcher_dark

شرح خصائص activity-alias

android:name

android:name="com.example.yourapp.MainActivity.dark"

هذا هو اسم الـ Alias الخاص بالأيقونة البديلة.

يفضل أن يكون الاسم واضحًا ويعبّر عن الأيقونة، مثل:

dark
ramadan
new_year
offer

android:targetActivity

android:targetActivity=".MainActivity"

هذا يعني أن الـ Alias سيقوم بتشغيل نفس MainActivity الخاصة بالتطبيق.

android:icon

android:icon="@mipmap/ic_launcher_dark"

هنا نحدد الأيقونة التي ستظهر عندما يتم تفعيل هذا الـ Alias.

android:enabled

android:enabled="false"

نجعل الأيقونة البديلة غير مفعلة في البداية، ثم نقوم بتفعيلها برمجيًا عند الحاجة.

إضافة أكثر من أيقونة في Android

يمكنك إضافة أكثر من activity-alias حسب عدد الأيقونات التي تريد دعمها.

<activity-alias
    android:name="com.example.yourapp.MainActivity.ramadan"
    android:targetActivity=".MainActivity"
    android:exported="true"
    android:icon="@mipmap/ic_launcher_ramadan"
    android:label="@string/app_name"
    android:enabled="false">

    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>

</activity-alias>

في هذا المثال أضفنا أيقونة بديلة باسم ramadan.

مكان وضع أيقونات Android

يجب وضع الأيقونات داخل مجلدات mipmap المختلفة حسب الكثافة.

android/app/src/main/res/mipmap-mdpi/ic_launcher_dark.png
android/app/src/main/res/mipmap-hdpi/ic_launcher_dark.png
android/app/src/main/res/mipmap-xhdpi/ic_launcher_dark.png
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_dark.png
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_dark.png

ويجب أن تكون أسماء الملفات متطابقة مع الاسم المستخدم في android:icon.

يعني لو كتبت:

android:icon="@mipmap/ic_launcher_dark"

لازم يكون اسم الملف:

ic_launcher_dark.png

ملاحظة مهمة حول Android

طريقة activity-alias هي الطريقة الأصلية والموثوقة في Android لتغيير أيقونة التطبيق.

لكن يجب الانتباه أن بعض أجهزة Android قد تحتاج عدة ثوانٍ حتى يظهر تغيير الأيقونة على الشاشة الرئيسية.

وفي بعض الأجهزة، قد لا يظهر التغيير إلا بعد إغلاق التطبيق أو تحديث شاشة اللانشر.

إعدادات iOS لتغيير أيقونة تطبيق Flutter

في iOS، تغيير الأيقونة يتم من خلال تعريف الأيقونات البديلة داخل ملف Info.plist.

النظام يسمح لك بتحديد CFBundlePrimaryIcon للأيقونة الأساسية، و CFBundleAlternateIcons للأيقونات البديلة.

مكان ملف Info.plist

افتح الملف التالي داخل مشروع Flutter:

ios/Runner/Info.plist

ثم أضف إعدادات الأيقونات داخل الملف.

مثال على CFBundleIcons داخل Info.plist

<key>CFBundleIcons</key>
<dict>

  <key>CFBundlePrimaryIcon</key>
  <dict>
    <key>CFBundleIconFiles</key>
    <array>
      <string>default</string>
    </array>
    <key>UIPrerenderedIcon</key>
    <false/>
  </dict>

  <key>CFBundleAlternateIcons</key>
  <dict>

    <key>dark</key>
    <dict>
      <key>CFBundleIconFiles</key>
      <array>
        <string>dark</string>
      </array>
      <key>UIPrerenderedIcon</key>
      <false/>
    </dict>

    <key>ramadan</key>
    <dict>
      <key>CFBundleIconFiles</key>
      <array>
        <string>ramadan</string>
      </array>
      <key>UIPrerenderedIcon</key>
      <false/>
    </dict>

  </dict>

</dict>

في المثال السابق عندنا أيقونة أساسية باسم default، وأيقونتين بديلتين:

  • dark
  • ramadan

وضع أيقونات iOS داخل Assets

يجب وضع ملفات الأيقونات داخل Assets الخاصة بمشروع iOS.

غالبًا ستحتاج إلى توفير الأحجام المناسبة مثل:

  • @2x
  • @3x

ويجب أن تطابق أسماء الأيقونات الأسماء الموجودة داخل Info.plist.

يعني لو كتبت:

<string>dark</string>

لازم تكون ملفات الأيقونة معرفة باسم dark داخل أصول iOS.

تحذير مهم بخصوص iOS

عند تغيير أيقونة التطبيق في iOS، قد يظهر تنبيه نظامي للمستخدم يخبره أن التطبيق يريد تغيير الأيقونة.

بعض المكتبات توفر خيارًا مثل showAlert لإخفاء هذا التنبيه، لكن يجب استخدامه بحذر لأنه يعتمد على حلول غير رسمية، وقد يتغير سلوك iOS في المستقبل.

التحقق هل الجهاز يدعم تغيير الأيقونة

قبل تغيير الأيقونة، من الأفضل التأكد أن الجهاز يدعم هذه الميزة.

final isSupported = await DynamicAppIconFlutterPlus.isSupported();

if (isSupported) {
  print("Dynamic app icon is supported");
} else {
  print("Dynamic app icon is not supported");
}

هذه الخطوة مهمة حتى لا تحاول تغيير الأيقونة على جهاز أو نظام لا يدعم الميزة.

الحصول على الأيقونات المتاحة

يمكنك الحصول على قائمة الأيقونات المتاحة داخل التطبيق باستخدام:

final icons = await DynamicAppIconFlutterPlus.getAlternateIconNames();

print(icons);

الميزة دي مفيدة لأنها تساعدك على عرض الأيقونات المتاحة للمستخدم داخل شاشة إعدادات مثلًا.

تعيين أيقونة بديلة في Flutter

لتغيير أيقونة التطبيق إلى أيقونة بديلة مثل الوضع الداكن، استخدم:

await DynamicAppIconFlutterPlus.setAlternateIconName('dark');

هنا يجب أن يكون الاسم dark مطابقًا للاسم الموجود في إعدادات Android و iOS.

مثال آخر لتغيير الأيقونة إلى أيقونة رمضان:

await DynamicAppIconFlutterPlus.setAlternateIconName('ramadan');

الرجوع إلى الأيقونة الأصلية

للرجوع إلى الأيقونة الافتراضية للتطبيق، أرسل قيمة null.

await DynamicAppIconFlutterPlus.setAlternateIconName(null);

بهذا الشكل يعود التطبيق إلى الأيقونة الأساسية.

مثال عملي كامل لتغيير أيقونة تطبيق Flutter

في المثال التالي سننشئ شاشة بسيطة تحتوي على أزرار لتغيير أيقونة التطبيق إلى الوضع الداكن أو أيقونة رمضان أو الرجوع للأيقونة الأصلية.

import 'package:flutter/material.dart';
import 'package:dynamic_app_icon_flutter_plus/dynamic_app_icon_flutter_plus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ChangeAppIconScreen(),
    );
  }
}

class ChangeAppIconScreen extends StatefulWidget {
  const ChangeAppIconScreen({super.key});

  @override
  State<ChangeAppIconScreen> createState() => _ChangeAppIconScreenState();
}

class _ChangeAppIconScreenState extends State<ChangeAppIconScreen> {
  bool isSupported = false;
  String currentStatus = "Checking support...";

  @override
  void initState() {
    super.initState();
    checkSupport();
  }

  Future<void> checkSupport() async {
    final supported = await DynamicAppIconFlutterPlus.isSupported();

    setState(() {
      isSupported = supported;
      currentStatus = supported
          ? "تغيير الأيقونة مدعوم على هذا الجهاز"
          : "تغيير الأيقونة غير مدعوم على هذا الجهاز";
    });
  }

  Future<void> changeIcon(String? iconName) async {
    if (!isSupported) {
      setState(() {
        currentStatus = "الجهاز لا يدعم تغيير الأيقونة";
      });
      return;
    }

    try {
      await DynamicAppIconFlutterPlus.setAlternateIconName(iconName);

      setState(() {
        currentStatus = iconName == null
            ? "تم الرجوع إلى الأيقونة الأصلية"
            : "تم تغيير الأيقونة إلى: $iconName";
      });
    } catch (e) {
      setState(() {
        currentStatus = "حدث خطأ أثناء تغيير الأيقونة: $e";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("تغيير أيقونة التطبيق"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Text(
              currentStatus,
              textAlign: TextAlign.center,
              style: const TextStyle(fontSize: 16),
            ),

            const SizedBox(height: 24),

            ElevatedButton(
              onPressed: () => changeIcon('dark'),
              child: const Text("تفعيل أيقونة الوضع الداكن"),
            ),

            const SizedBox(height: 12),

            ElevatedButton(
              onPressed: () => changeIcon('ramadan'),
              child: const Text("تفعيل أيقونة رمضان"),
            ),

            const SizedBox(height: 12),

            ElevatedButton(
              onPressed: () => changeIcon(null),
              child: const Text("الرجوع للأيقونة الأصلية"),
            ),
          ],
        ),
      ),
    );
  }
}

شرح المثال العملي

في البداية قمنا باستدعاء المكتبة:

import 'package:dynamic_app_icon_flutter_plus/dynamic_app_icon_flutter_plus.dart';

ثم تحققنا هل الجهاز يدعم تغيير الأيقونة:

final supported = await DynamicAppIconFlutterPlus.isSupported();

وبعد ذلك استخدمنا الدالة التالية لتغيير الأيقونة:

await DynamicAppIconFlutterPlus.setAlternateIconName(iconName);

لو كانت قيمة iconName تساوي dark، سيتم تعيين أيقونة الوضع الداكن.

ولو كانت القيمة null، سيتم الرجوع إلى الأيقونة الأصلية.

أسماء الأيقونات يجب أن تكون متطابقة

من أكثر الأخطاء الشائعة عند تغيير أيقونة تطبيق Flutter أن أسماء الأيقونات تكون مختلفة بين Flutter و Android و iOS.

لازم تتأكد أن الاسم المستخدم في الكود:

setAlternateIconName('dark')

يطابق الاسم الموجود في:

  • AndroidManifest.xml
  • Info.plist
  • ملفات الأيقونات داخل المشروع

مثال على أسماء متطابقة

في Flutter:

await DynamicAppIconFlutterPlus.setAlternateIconName('dark');

في Android:

android:name="com.example.yourapp.MainActivity.dark"
android:icon="@mipmap/ic_launcher_dark"

في iOS:

<key>dark</key>

هذا التوافق في الأسماء يقلل المشاكل أثناء التشغيل.

مشاكل شائعة عند تغيير أيقونة تطبيق Flutter

الأيقونة لا تتغير على Android

تأكد من أنك أضفت activity-alias داخل AndroidManifest.xml، وأن الأيقونة موجودة داخل مجلدات mipmap.

ثم جرّب حذف التطبيق من الجهاز وإعادة تثبيته.

ظهور أكثر من أيقونة للتطبيق

هذا يحدث غالبًا إذا كانت أكثر من activity-alias مفعلة في نفس الوقت.

تأكد أن الأيقونات البديلة تكون:

android:enabled="false"

وأن المكتبة تقوم بتفعيل أيقونة واحدة فقط عند التغيير.

الأيقونة لا تتغير على iOS

تأكد من إضافة الأيقونات داخل Info.plist بشكل صحيح، وتأكد أن أسماء الملفات مطابقة لأسماء الأيقونات.

iOS يظهر تنبيه عند تغيير الأيقونة

هذا سلوك طبيعي في iOS. بعض المكتبات توفر خيارًا لإخفاء التنبيه، لكن الأفضل استخدامه بحذر.

الأيقونة لا تظهر مباشرة بعد التغيير

بعض أنظمة التشغيل أو واجهات اللانشر تحتاج وقت بسيط حتى تحدث الأيقونة.

انتظر قليلًا أو أغلق التطبيق وافتحه مرة أخرى.

أفضل الممارسات عند تغيير أيقونة التطبيق

  • استخدم أسماء واضحة للأيقونات مثل dark و ramadan
  • تأكد من تطابق أسماء الأيقونات بين Flutter و Android و iOS
  • وفر جميع مقاسات الأيقونات المطلوبة لكل منصة
  • لا تغيّر الأيقونة بشكل متكرر ومزعج للمستخدم
  • استخدم الميزة في حالات واضحة مثل المواسم أو الإعدادات
  • اختبر الميزة على أجهزة حقيقية وليس المحاكي فقط
  • تأكد من الرجوع للأيقونة الأصلية عند الحاجة

متى تستخدم Dynamic App Icon؟

ميزة تغيير أيقونة التطبيق مفيدة في حالات كثيرة، مثل:

  • تطبيقات المتاجر أثناء العروض
  • تطبيقات التعليم في المواسم الدراسية
  • تطبيقات دينية في رمضان أو المناسبات
  • تطبيقات الأخبار وقت الأحداث الخاصة
  • تطبيقات تدعم الوضع الداكن
  • تطبيقات تسمح للمستخدم بتخصيص شكل التطبيق

هل تغيير أيقونة التطبيق يعمل على كل الأجهزة؟

الميزة مدعومة على Android و iOS، لكن السلوك قد يختلف قليلًا حسب الجهاز ونظام التشغيل واللانشر المستخدم.

لذلك من الأفضل دائمًا استخدام:

DynamicAppIconFlutterPlus.isSupported()

قبل محاولة تغيير الأيقونة.

مميزات dynamic_app_icon_flutter_plus

  • واجهة استخدام بسيطة داخل Flutter
  • دعم Android و iOS
  • إمكانية الرجوع للأيقونة الأصلية
  • التحقق من دعم الجهاز للميزة
  • تقليل التعامل المباشر مع أكواد Native
  • مناسبة للتطبيقات التي تحتاج تخصيص بصري

عيوب أو ملاحظات قبل الاستخدام

  • تحتاج إعدادات Native في Android و iOS
  • يجب تجهيز الأيقونات بأحجام صحيحة
  • قد يظهر تنبيه في iOS عند تغيير الأيقونة
  • قد يتأخر ظهور التغيير على بعض أجهزة Android
  • تحتاج اختبار جيد قبل إطلاق التطبيق

الخلاصة

تغيير أيقونة تطبيق Flutter أصبح أسهل باستخدام مكتبة dynamic_app_icon_flutter_plus، حيث يمكنك تغيير الأيقونة برمجيًا على Android و iOS بدون كتابة الكثير من الأكواد المعقدة.

على Android ستحتاج إلى إعداد activity-alias داخل AndroidManifest.xml، وعلى iOS ستحتاج إلى تعريف الأيقونات البديلة داخل Info.plist.

بعد ذلك يمكنك استخدام دالة بسيطة مثل:

await DynamicAppIconFlutterPlus.setAlternateIconName('dark');

أو الرجوع إلى الأيقونة الأصلية باستخدام:

await DynamicAppIconFlutterPlus.setAlternateIconName(null);

في النهاية، إذا كنت تريد تخصيص تجربة المستخدم أو تغيير شكل التطبيق في المناسبات والعروض، فإن تغيير أيقونة تطبيق Flutter باستخدام dynamic_app_icon_flutter_plus يعتبر حلًا عمليًا وسهل التنفيذ.


مزيد من المقالات : اجعل تطبيقات Flutter الخاصة بك تنبض بالحياة مع الوسائط المتعددة
شاهد أيضًا
مقالات ذات صلة

🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع