في عالم تطوير التطبيقات الحديثة، أصبحت الأتمتة جزءًا مهمًا جدًا من أي فريق تطوير، خصوصًا عندما يكون الفريق يعمل على تطبيقات يتم تحديثها بشكل مستمر.
بدل ما كل مرة تعمل فيها push على GitHub تقوم ببناء التطبيق يدويًا وترفع ملف APK للفريق، تقدر تخلي العملية كلها تتم تلقائيًا باستخدام GitHub Actions. في المقال ده هنتعلم خطوة بخطوة إزاي نعمل CI/CD لتطبيق Flutter بحيث يتم بناء ملف APK تلقائيًا عند كل Push على فرع معين، وبعدها يتم رفع الملف مباشرة إلى قناة Slack باستخدام Slack API.
المشكلة التي نريد حلها
لو الفريق بتاعك بيعتمد على Slack كأداة أساسية للتواصل ومتابعة سير العمل، فغالبًا هتحتاج تبعت نسخة APK جديدة للفريق بعد كل تحديث مهم. المشكلة هنا إن العملية اليدوية بتكون متكررة ومملة:
تعمل Push على GitHub
تبني التطبيق يدويًا
تدور على ملف APK
ترفعه على Slack
تبلغ الفريق إن فيه نسخة جديدة
مع الوقت، الخطوات دي بتستهلك وقت، وبتزود احتمالية الأخطاء البشرية، خصوصًا لو التحديثات كتير أو الفريق كبير.
الحل باستخدام GitHub Actions
الحل هو إنشاء Workflow داخل GitHub Actions يقوم بكل الخطوات تلقائيًا. يعني بمجرد ما تعمل push على فرع معين مثل dev، GitHub Actions هيبدأ يشغل خطوات البناء، وبعد ما يخلص هيتم رفع ملف APK مباشرة إلى Slack.
لماذا نستخدم CI/CD مع Flutter؟
استخدام CI/CD في تطبيقات Flutter بيوفر مميزات مهمة جدًا لأي فريق تطوير.
تسريع دورة التطوير
تقليل الأخطاء البشرية
تنفيذ نفس خطوات البناء في بيئة نظيفة كل مرة
إرسال النسخ الجديدة للفريق تلقائيًا
سهولة التوسع لاحقًا ورفع التطبيق إلى Google Play أو TestFlight
المتطلبات الأساسية قبل البدء
قبل ما نبدأ، لازم يكون عندك شوية حاجات جاهزة:
مشروع Flutter يعمل بشكل سليم
مستودع GitHub يحتوي على الكود
حساب Slack Workspace
Slack Bot Token
Channel ID للقناة التي سيتم رفع APK عليها
إضافة Secrets داخل GitHub Repository
التأكد من بناء تطبيق Flutter محليًا
قبل ما تستخدم GitHub Actions، لازم تتأكد إن التطبيق بيتبني عندك محليًا بدون مشاكل.
flutter build apk --release
لو الأمر اشتغل بنجاح، هتلاقي ملف APK في المسار التالي:
build/app/outputs/apk/release/app-release.apk
إعداد GitHub Secrets
عشان نحافظ على البيانات الحساسة زي Slack Token، مينفعش نكتبها مباشرة داخل ملف Workflow.
بدل كده، هنضيفها داخل GitHub Secrets. افتح GitHub Repository ثم اذهب إلى:
Settings → Secrets and variables → Actions → New repository secret
بعد كده أضف القيم التالية:
SLACK_BOT_TOKEN: توكن البوت الخاص بـ Slack
SLACK_CHANNEL_ID: رقم القناة التي سيتم رفع الملف إليها
الصلاحيات المطلوبة من Slack Bot
البوت الخاص بك يحتاج إلى بعض الصلاحيات حتى يتمكن من الدخول إلى القناة ورفع الملفات.
files:write لرفع الملفات
channels:read لقراءة بيانات القنوات
channels:join للانضمام إلى القنوات العامة
لو القناة Private، غالبًا ستحتاج إلى دعوة البوت يدويًا داخل القناة.
هنا بنطلب من Slack رابط مؤقت نرفع عليه الملف. الاستجابة بترجع لنا قيمتين مهمتين:
upload_url: الرابط الذي سيتم رفع الملف عليه
file_id: رقم الملف داخل Slack
رفع ملف APK
curl -sS -X POST -F "file=@${APK_PATH}" "$UPLOAD_URL" >/dev/null
في الخطوة دي بنرفع ملف APK فعليًا إلى الرابط الذي حصلنا عليه من Slack.
إكمال الرفع وإرسال الملف للقناة
curl -sS -X POST https://slack.com/api/files.completeUploadExternal \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-H "Content-type: application/json" \
-d "$BODY" | tee /tmp/slack_complete.json
بعد رفع الملف، لازم نستدعي files.completeUploadExternal حتى يظهر الملف داخل قناة Slack مع التعليق المطلوب.
إضافة تعليق مع رقم Commit
في الكود المستخدم، بيتم إرسال تعليق مع الملف يحتوي على رقم الـ Commit الحالي.
COMMENT=$(printf "🚀 New Android build\n• Commit: %s" "$GITHUB_SHA")
وده مفيد جدًا عشان الفريق يعرف النسخة المرفوعة مرتبطة بأي Commit في GitHub.
مشكلة jq في GitHub Actions
الكود يعتمد على أداة jq لمعالجة JSON داخل الـ Shell.
غالبًا jq تكون موجودة بالفعل داخل ubuntu-latest. لكن لو ظهرت لك مشكلة إن jq غير مثبتة، أضف الخطوة التالية قبل رفع الملف:
استخدم GitHub Secrets دائمًا لحماية البيانات الحساسة
مشاكل شائعة وحلولها
APK not found
لو ظهر لك الخطأ التالي:
APK not found at build/app/outputs/apk/release/app-release.apk
تأكد إن أمر البناء نجح، وتأكد من المسار الصحيح للملف الناتج.
not_in_channel
هذا الخطأ معناه إن البوت ليس موجودًا داخل قناة Slack. الحل:
لو القناة Public، استخدم conversations.join
لو القناة Private، قم بدعوة البوت يدويًا
invalid_auth
هذا الخطأ معناه إن Slack Token غير صحيح أو لم يتم إضافته بشكل صحيح داخل GitHub Secrets.
missing_scope
هذا الخطأ معناه إن البوت لا يمتلك الصلاحيات المطلوبة. تأكد من إضافة الصلاحيات التالية:
files:write
channels:read
channels:join
هل يمكن بناء AAB بدل APK؟
نعم، لو هدفك رفع التطبيق إلى Google Play، الأفضل استخدام Android App Bundle بدل APK.
flutter build appbundle --release
وفي هذه الحالة سيكون الملف الناتج غالبًا داخل:
build/app/outputs/bundle/release/app-release.aab
بعدها تحتاج تعديل APK_PATH إلى مسار ملف AAB.
أفضل الممارسات الأمنية
لا تضع أي Token داخل الكود مباشرة
استخدم GitHub Secrets للبيانات الحساسة
استخدم أقل صلاحيات ممكنة للبوت
راجع صلاحيات Slack App بشكل دوري
لا تشارك ملف Keystore داخل المستودع
مميزات هذا الحل
بناء APK تلقائيًا عند كل Push
توفير وقت الفريق
تقليل الأخطاء اليدوية
ربط عملية التطوير مباشرة مع Slack
سهولة معرفة رقم Commit الخاص بكل نسخة
إمكانية التوسع لاحقًا لإضافة اختبارات أو نشر على المتاجر
الخلاصة
استخدام GitHub Actions مع Flutter و Slack API يعتبر حل ممتاز لأي فريق يريد أتمتة عملية بناء التطبيق ومشاركة النسخ الجديدة بسرعة. بدل ما تقوم ببناء ملف APK يدويًا ورفعه على Slack كل مرة، تقدر تخلي GitHub Actions يقوم بالعملية بالكامل بمجرد حدوث Push على فرع معين. الطريقة دي هتوفر وقت كبير، وتقلل الأخطاء، وتخلي الفريق دائمًا على اطلاع بآخر نسخة من التطبيق. ومع الوقت تقدر تطور نفس Workflow بإضافة اختبارات تلقائية، توقيع التطبيق، رفع AAB إلى Google Play، أو إرسال إشعارات أكثر تفصيلًا للفريق.