توقيع الكود في iOS: الشهادات وملفات التوفير
توقيع الكود في iOS: الشهادات وملفات التوفير
قبل أن يتمكن تطبيق iOS من العمل على جهاز حقيقي أو توزيعه عبر متجر التطبيقات، تشترط Apple أن يكون موقعاً تشفيرياً. تُثبت سلسلة التوقيع هذه أن الملف الثنائي صادر من مطوّر شرعي ولم يُعدَّل منذ بنائه. يُعدّ فهم آلية عمل التوقيع أمراً أساسياً لكل مطوّر Flutter يستهدف iOS، إذ تُعدّ أخطاء عدم تطابق التوقيع السبب الأكثر شيوعاً لفشل عمليات البناء ورفض متجر التطبيقات.
سلسلة التوقيع: كيف تتحقق Apple من تطبيقك
تستخدم Apple نموذج ثقة هرمياً يتكون من ثلاثة مكوّنات رئيسية يجب أن تتوافق جميعها قبل أن يقوم الجهاز بتشغيل تطبيقك:
- شهادة المطوّر — تُصدرها Apple بعد انضمامك إلى برنامج المطوّرين. تُثبت هويتك. يوجد نوعان: شهادة التطوير (لإصدارات التصحيح على الأجهزة المسجّلة) وشهادة التوزيع (لإصدارات TestFlight ومتجر التطبيقات).
- معرّف التطبيق / معرّف الحزمة — سلسلة نصية فريدة بتنسيق نطاق عكسي (مثل
com.yourcompany.yourapp) مسجّلة في حساب مطوّري Apple. تُعرّف التطبيق الذي يجري توقيعه. - ملف التوفير — ملف موقَّع من Apple يربط شهادتك ومعرّف حزمتك وقائمة UDIDs الأجهزة المصرَّح بها (في التطوير). يُجيب على السؤال: أي شهادة يمكنها توقيع هذا التطبيق، على أي أجهزة، وبأي صلاحيات؟
pubspec.yaml لا يتطابق مع معرّف التطبيق في الملف، فسيفشل التوقيع أثناء البناء.شهادات المطوّرين
الشهادات هي شهادات رقمية بتنسيق X.509 مخزّنة في سلسلة مفاتيح macOS. تُنشئ طلب توقيع شهادة (CSR) على جهاز Mac، وترفعه إلى بوابة مطوّري Apple، ثم تُنزّل ملف .cer الناتج. النقر المزدوج عليه يُثبّته في Keychain Access إلى جانب المفتاح الخاص الذي أُنشئ عند توليد CSR.
- Apple Development — يستخدمه Xcode لتوقيع إصدارات التصحيح. مرتبط بحساب مطوّرك الشخصي.
- Apple Distribution — يُستخدم لتوقيع الإصدارات المرفوعة إلى App Store Connect (لـ TestFlight والإنتاج). تحتفظ الفِرق عادةً بهذه الشهادة مشتركةً عبر مخزن آمن.
.p12 أولاً (File > Export Items في Keychain Access). إذا فقدت المفتاح الخاص، تصبح الشهادة عديمة الفائدة وعليك إلغاؤها وإنشاء شهادة جديدة، مما يُبطل ملفات التوفير الحالية الموقّعة بالشهادة القديمة.ملفات التوفير
ملف التوفير (.mobileprovision) هو الرابط الذي يجمع شهادتك ومعرّف حزمتك والأجهزة معاً. توجد أربعة أنواع رئيسية من الملفات:
- iOS App Development — إصدارات التصحيح على UDIDs أجهزة مسجّلة محددة.
- Ad Hoc — التوزيع على ما يصل إلى 100 جهاز مسجّل دون متجر التطبيقات.
- App Store — الإصدارات المُقدَّمة إلى App Store Connect؛ لا تتطلب قائمة أجهزة.
- Enterprise — التوزيع الداخلي للمؤسسات التي تمتلك برنامج Apple Enterprise (يتطلب عضوية منفصلة).
فحص ملف التوفير من الطرفية
// فكّ تشفير ملف .mobileprovision لقراءة محتوياته
// شغّل هذا في طرفية macOS (ليس كود Dart):
//
// security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/<UUID>.mobileprovision
//
// الحقول الرئيسية للتحقق منها:
// <key>AppIDName</key> -- الاسم المقروء للإنسان
// <key>application-identifier</key> -- TeamID.BundleID
// <key>DeveloperCertificates</key> -- الشهادة (الشهادات) المضمّنة بترميز base64
// <key>ProvisionedDevices</key> -- معرّفات UDID (للتطوير/Ad Hoc فقط)
// <key>ExpirationDate</key> -- تاريخ انتهاء صلاحية الملف
// في مشروع Flutter، يمكنك أيضاً الفحص من مجلد ios/:
// open ios/Runner.xcworkspace
التوقيع التلقائي مقابل التوقيع اليدوي في Xcode
يوفّر Xcode وضعَين للتوقيع، يمكن الوصول إليهما عبر Xcode > هدف Runner > Signing & Capabilities:
التوقيع التلقائي
عند تفعيل خيار Automatically manage signing، يقوم Xcode بإنشاء الشهادات وملفات التوفير وتحديثها نيابةً عنك. يُعدّ هذا نقطة البداية الموصى بها للمشاريع الجديدة. يُسجّل Xcode الأجهزة الجديدة وينشئ الملفات المفقودة ويجدّد المنتهية تلقائياً. الجانب السلبي هو أنه يتطلب اتصالاً مستمراً بخوادم Apple وقد يتصرف بشكل غير متوقع في بيئات CI التي لا تحتوي على Apple ID نشط.
التوقيع اليدوي
يتيح لك التوقيع اليدوي تحديد ملف التوفير والشهادة الدقيقَين لكل تهيئة بناء (Debug وRelease وProfile). يُعدّ هذا ضرورياً لمسارات CI/CD التي لا توجد فيها جلسة Apple ID. تُنزّل الملفات من بوابة مطوّري Apple وتُخزّنها كملفات (غالباً مُشفَّرة بـ base64 في متغيرات البيئة) وتُشير إليها صراحةً.
ضبط معرّف الحزمة والفريق في مشروع Flutter لـ Xcode (إعداد من جانب Dart)
// لا يمتلك Flutter واجهة برمجة Dart لتوقيع الكود —
// يتم إعداد التوقيع في Xcode. ومع ذلك، يمكن أتمتة
// المهام الشائعة بسكريبت بناء يُستدعى من pubspec.yaml:
// pubspec.yaml (قسم السكريبتات — مفاهيمي، ليس معياراً في Flutter):
// scripts:
// set_bundle_id: |
// cd ios
// /usr/libexec/PlistBuddy -c \
// "Set :CFBundleIdentifier com.example.myApp" \
// Runner/Info.plist
// الطريقة المعتمدة في Flutter: تعديل ios/Runner.xcodeproj/project.pbxproj
// أو استخدام واجهة Xcode الرسومية. إعداد PRODUCT_BUNDLE_IDENTIFIER يحدد
// ملف التوفير المُختار عند استخدام التوقيع التلقائي.
// سكريبت Dart مساعد للتحقق من تطابق معرّف الحزمة مع الملف:
import 'dart:io';
void main() async {
final result = await Process.run('xcodebuild', [
'-showBuildSettings',
'-workspace', 'ios/Runner.xcworkspace',
'-scheme', 'Runner',
]);
final lines = result.stdout.toString().split('\n');
final bundleLine = lines.firstWhere(
(l) => l.contains('PRODUCT_BUNDLE_IDENTIFIER'),
orElse: () => 'Not found',
);
print('Bundle ID setting: $bundleLine');
}
الصلاحيات والقدرات
الصلاحيات (Entitlements) هي أزواج مفتاح-قيمة تمنح تطبيقك الوصول إلى خدمات Apple المحددة — إشعارات الدفع، iCloud، Sign in with Apple، App Groups، وغيرها. يتم الإعلان عنها في ios/Runner/Runner.entitlements ويجب أن تتطابق مع القدرات المُفعَّلة في معرّف تطبيقك على بوابة المطوّرين. يُضمّن ملف التوفير الصلاحيات المسموح بها؛ إذا طلب ثنائيك صلاحيةً غير موجودة في الملف، فسيفشل التوقيع أو تثبيت التطبيق على الجهاز.
flutter build ios --release محلياً مرةً واحدة على الأقل قبل إعداد CI. يُظهر هذا أخطاء التوقيع برسائل أوضح من سجلات CI، وسيُنشئ بناء Xcode المحلي الشهادات تلقائياً إذا كان التوقيع التلقائي مُفعَّلاً.ملخّص
تتطلب سلسلة توقيع كود Apple ثلاثة مكوّنات متوافقة: شهادة المطوّر (هويتك)، ومعرّف الحزمة (ما هو التطبيق)، وملف التوفير (أي شهادة + أي أجهزة + أي صلاحيات). تُستخدم شهادات التطوير لإصدارات التصحيح، وشهادات التوزيع لعمليات الإرسال إلى TestFlight ومتجر التطبيقات. يتعامل التوقيع التلقائي في Xcode مع التطوير الاعتيادي بسلاسة، بينما يُعدّ التوقيع اليدوي الخيار الموثوق لمسارات CI/CD. الاحتفاظ بنسخة احتياطية من مفتاحك الخاص كملف .p12 وفهم كيفية تضمين الصلاحيات في ملفات التوفير سيوفّر عليك ساعات من التصحيح في بيئة الإنتاج.