Guideline 2.3.1: الميزات المخفية وتحديثات OTA في iOS
بقلم Mehdi Azizi
نُشر في ، 9 د
ترفض Apple في Guideline 2.3.1 أي ميزة مخفية أو خاملة أو غير مذكورة في ملاحظات المراجعة. إليك ما يمكنك تغييره عن بُعد وما يحتاج إلى build جديد.
تمنع Guideline 2.3.1 الميزات المخفية أو الخاملة أو غير الموثقة: كل ما يفعله تطبيقك يجب أن يكون واضحًا للمستخدم وللمراجع. وكل ميزة جديدة يجب وصفها بدقة في ملاحظات المراجعة. التحديث عن بُعد يمكنه إصلاح ما رأته Apple، لكنه لا يضيف أبدًا شيئًا لم تره Apple.
أنشر تطبيقات iOS الخاصة بي باستخدام Expo، وكل تطبيق منها يتضمن EAS Update منذ أول build له لتوصيل الإصلاحات. قاعدتي: لا تحديث عن بُعد ما دام هناك إصدار قيد المراجعة. يعتمد هذا الدليل على نص Apple واتفاقية الترخيص ووثائق Expo وحالات رفض منشورة.
ماذا تقول Guideline 2.3.1؟
تفتتح 2.3.1 الجزء 2.3 «Accurate Metadata» من App Review Guidelines، ضمن القسم 2 «Performance». يبدأ النص هكذا: «Don't include any hidden, dormant, or undocumented features in your app; your app's functionality should be clear to end users and App Review.» بعبارة بسيطة: لا شيء مخفي أو خامل أو غير موثق.
ثم يتناول النص كل عملية إرسال: «All new features, functionality, and product changes must be described with specificity in the Notes for Review section of App Store Connect (generic descriptions will be rejected) and accessible for review.» يجب وصف كل ميزة جديدة بدقة في ملاحظات المراجعة، ويجب أن يتمكن المراجع من الوصول إليها. لذلك لا تكفي عبارة «إصلاح أخطاء وتحسينات».
والفقرة نفسها تستهدف التسويق المضلل: أن تعد بمحتوى أو خدمة غير موجودة، أو أن تعرض سعرًا غير صحيح، سواء في App Store أو في أي مكان آخر.
استفدت من هذا الجانب في Nolera. عند مراجعة صفحة التطبيق قبل الإطلاق، وجدت جملتين لا يمكن التحقق منهما: «الواجهة بالفرنسية فقط»، وقد أصبحت غير صحيحة، و«الباقة الأكثر اختيارًا»، لتطبيق لم يُنشر قط. كما كانت الملاحظات الموجهة إلى المراجع تصف حالة قديمة من المنتج. هذا تحديدًا ما يستهدفه هذا الجانب. أما 2.3.10 فتستهدف صفحة التطبيق أساسًا.
ماذا تعني رسالة الرفض 2.3.1؟
يحمل الرفض عنوان «Guideline 2.3.1 - Performance»، ويليه أحيانًا «Hidden Features». إليك رسالتين نشرهما مطورو React Native:
- مارس 2024، في تذكرة GitHub الخاصة بـ CodePush: «The app contains hidden features.»، دون أي تفاصيل أخرى. طلب المطور توضيحًا فتلقى إضافة بموجب 2.5.2: «Your app, extension, or linked framework appears to contain code designed explicitly with the capability to change the app's behavior or functionality after App Review approval.» ولا تذكر التذكرة إن كان التطبيق قد قُبل بعد ذلك.
- فبراير 2023، في تذكرة أخرى، استهدفت Apple ما سمّته «CodePush-related remote code downloading/updating support» في الملف التنفيذي.
قراءتي: المراجع لا يرى تحديثاتك، بل يرى الكود القادر على استقبالها. كلتا الحالتين تخص CodePush. لم أجد حالة رفض علنية حديثة تخص EAS Update، وهذا لا يثبت شيئًا.
التحديثات عن بُعد: ما تسمح به 2.5.2 واتفاقية الترخيص
تمنع القاعدة 2.5.2، التي أتناولها أيضًا في دليل أوضاع الخلفية، التطبيق من أن «download, install, or execute code which introduces or changes features or functionality of the app».
تمنع المادة 3.3.1(B) من Apple Developer Program License Agreement الكود التنفيذي المُنزَّل، لكنها توضح: «Interpreted code may be downloaded to an Application». وذلك بثلاثة شروط: ألا يغير هذا الكود الغرض الأساسي للتطبيق، وألا يتحايل على التوقيع أو البيئة المعزولة أو أنظمة الأمان، وألا ينشئ متجرًا لتطبيقات أخرى.
كود JavaScript في تطبيق Expo هو كود مُفسَّر: في رأيي، يقع EAS Update ضمن هذا الإطار. تذكّر وثائقه بأن التحديثات تخضع لقواعد App Store، وبأن «changes to your app's behavior need to be reviewed». ولمعالجة خطأ حرج، تقترح Expo الإصلاح عن بُعد، ثم إرسال إصدار جديد يتضمنه.
خطي: إصلاح ما هو موجود وتعديله، نعم. تغيير ماهية التطبيق أو ما يبيعه، لا.
ما يمكنك تغييره عن بُعد، وما يحتاج إلى build جديد
هذا الجدول الذي أطبقه، مستخلص من صفحات Apple وExpo المذكورة هنا. سطر «المجاني الذي يصبح مدفوعًا» والسطران الأخيران هي قراءتي الشخصية.
| التغيير | الطريقة | السبب |
|---|---|---|
| خطأ في JavaScript | تحديث عن بُعد | استخدام تتوقعه Expo |
| نص، ترجمة، تنسيق | تحديث عن بُعد | استخدام تتوقعه Expo |
| سعر اشتراك | App Store Connect | لا تعديل في الكود |
| النص الترويجي | App Store Connect | دون إرسال جديد |
| شراء من نوع سبق قبوله | مراجعة الشراء وحده | قاعدة App Store Connect |
| أول شراء من نوع ما | إصدار جديد | قاعدة App Store Connect |
| ميزة جديدة | إصدار جديد | 2.3.1 و2.5.2 |
| المجاني الذي يصبح مدفوعًا | إصدار جديد | الصفحة والملاحظات تحتاج مراجعة |
| إذن، Info.plist | build جديد | ملف داخل الملف التنفيذي |
| وحدة أصلية، Expo SDK | build جديد | تغيّر الكود الأصلي |
| مفتاح يُعطّل | إعداد عن بُعد | مقبول إن كان مؤقتًا |
| مفتاح يكشف | ممنوع | ميزة لم تُراجع قط |
يمكن تغيير النص الترويجي «without requiring an updated submission»، حسب صفحة Apple عن معلومات الإصدار. أول شراء من كل نوع يُرسل مع إصدار جديد، والمشتريات اللاحقة تُرسل وحدها، حسب صفحة المساعدة عن إرسال المشتريات. تصنّف Expo الكود الأصلي والأذونات وإصدار SDK ضمن ما يحتاج إلى ملف تنفيذي جديد، كما في حالة ITMS-90683. والمفتاح الذي يعطّل ميزة معطوبة لا يضيف شيئًا جديدًا، ما دام لا يسحب ما دفع المشتركون مقابله.
المفاتيح عن بُعد دون رفض
المفتاح عن بُعد، أو feature flag، ليس ممنوعًا في حد ذاته: كل شيء يتوقف على ما يخفيه. قواعدي:
- كل ما يمكن للمفتاح عرضه موجود ومُفعّل للمراجع، ومذكور بالاسم في ملاحظات المراجعة.
- اختبار A/B يقارن بين نسختين يستطيع المراجع رؤيتهما، ولا يقارن أبدًا بين نسخة مُراجعة وأخرى لم يرها أحد.
- لا يوجد أي كود يكتشف المراجعة ليتصرف بشكل مختلف. هذا هو تعريف الميزة المخفية بالضبط.
- شاشة الدفع (paywall) المُدارة عن بُعد لا تعرض إلا منتجات مقبولة، وكل نسخة منها تحترم القاعدة 3.1.2.
وضع العرض التجريبي وحسابات الاختبار
تطلب Guideline 2.1 حساب عرض تجريبي إذا كان تطبيقك يتطلب تسجيل الدخول، مع تشغيل الخادم. إذا منعتك التزامات قانونية أو أمنية من توفيره، يمكن لوضع عرض تجريبي مدمج أن يحل محله، لكن فقط «with prior approval by Apple»، ويجب أن يعرض جميع الميزات. وتضيف صفحة Apple عن معلومات الإصدار: الحساب لا تنتهي صلاحيته، والحسابات الإضافية توضع في الملاحظات، المحدودة بـ 4000 بايت.
العلاقة مع 2.3.1: وضع العرض التجريبي أو حساب الاختبار الذي يفتح شاشات لا تظهر بطريقة أخرى يجب وصفه. إيماءة سرية، أو رمز، أو حساب خاص غير مُعلن، كلها ميزة مخفية. اذكر كل وصول خاص في الملاحظات، مع ما يفتحه.
قاعدتي: لا تحديث عن بُعد أثناء المراجعة
لماذا يوجد EAS Update في كل تطبيقاتي: في Solys، تطبيق المنبه الخاص بي، كان خطأ في JavaScript يجعل التطبيق صامتًا بمجرد فشل مؤثر صوتي مرة واحدة. الإصلاح كان ثلاثة أسطر، لكن توصيله احتاج build كاملًا ومراجعة. منذ ذلك الحين، كل تطبيقاتي تتضمن expo-updates منذ أول build: إنها وحدة أصلية، والملف التنفيذي المُجمّع من دونها لن يستقبل أي شيء أبدًا. إعداداتي في app.json:
{
"expo": {
"runtimeVersion": { "policy": "fingerprint" },
"updates": { "fallbackToCacheTimeout": 0, "checkAutomatically": "ON_LOAD" }
}
}
مع fingerprint، لا يصل التحديث إلا إلى الملفات التنفيذية التي يتطابق كودها الأصلي (إصدارات التشغيل). لكن ما دام هناك إصدار ينتظر المراجعة أو يخضع لها، لا أنشر شيئًا. لسببين.
- المراجع لن يرى الإصلاح. مع ضبط
fallbackToCacheTimeoutعلى 0، يبدأ التثبيت الجديد بالكود المدمج ويطبق التحديث عند التشغيل التالي (وثائق expo-updates). المراجع يثبّت التطبيق ويشغّله مرة واحدة ويختبر الملف التنفيذي. رُفض Nolera بينما كان الإصلاح قد وُزّع عن بُعد بالفعل: أروي ذلك في دليل 2.1. - ما يختبره المراجع يجب أن يبقى هو ما يتلقاه المستخدمون. تغيير السلوك أثناء المراجعة يخلق فجوة بين النسخة التي رآها المراجع والنسخة الموزعة.
ملاحظات مراجعة دقيقة
ترفض 2.3.1 الأوصاف العامة. هذا النموذج الذي أستخدمه، بالإنجليزية:
What's new in this version:
- [Feature]: [where to find it, how to test it].
Remote configuration:
- "[flag]" controls [feature]. It is ON for review.
Over-the-air updates:
- The app uses expo-updates for bug fixes only.
No update will be published during this review.
Demo account: see Sign-in information. It never expires.
كيف ترد على رفض 2.3.1؟
رُدّ من داخل App Store Connect، حيث ترد على رسالة App Review.
- الرسالة غامضة: اسأل عن الميزة المقصودة، كما فعل مطور تذكرة 2024.
- ميزة حقيقية موصوفة بشكل سيئ: قدّم المسار الدقيق وفيديو قصيرًا، ثم أكمل الملاحظات.
- مفتاح يكشف شيئًا جديدًا: احذفه، أو فعّله وصِفه، ثم أعد الـ build.
- كود التحديث هو المشكلة: اشرح أنه مخصص للإصلاحات، ضمن إطار المادة 3.3.1(B). في تذكرة 2023، طلبت Apple حذفه.
قائمة التحقق لـ 2.3.1 قبل الإرسال
- كل ميزة جديدة في الإصدار موصوفة في الملاحظات، مع مسارها.
- كل مفتاح عن بُعد مُفعّل للمراجعة ومذكور بالاسم في الملاحظات.
- لا يوجد كود يغير سلوكه من أجل المراجع.
- الوصول الخاص موصوف: وضع العرض التجريبي، حساب الاختبار، الإيماءة.
- صفحة التطبيق وشاشة الدفع لا تعدان بشيء لا يفعله الـ build.
- لا يُنشر أي تحديث عن بُعد أثناء المراجعة.
راجع ملفك قبل الإرسال
يجمع Review Kit قائمة التحقق التي أستخدمها قبل الإرسال، ونماذج ملاحظات للمختبِر، وskills لـ Claude Code تراجع مشروعك. وإن أردت نظرة بشرية، احجز ساعة معي: نراجع معًا ملاحظات المراجعة وإعدادات التحديثات، عبر مكالمة فيديو. الخطوات الكاملة موجودة في صفحة تطبيق رفضته Apple.
هل تستعد لإطلاقك الأول؟ أجرِ التشخيص المجاني: يرتب لك الخطوات ويرسل إليك قائمة التحقق التي أستخدمها لتجنب رفض Apple.
الأسئلة الشائعة
ماذا تعني «Guideline 2.3.1 - Performance - Hidden Features»؟
ترى Apple أن تطبيقك يحتوي على ميزة مخفية أو خاملة أو غير مذكورة في ملاحظات المراجعة. وقد تستهدف الرسالة أيضًا كودًا قادرًا على تغيير التطبيق بعد المراجعة، أحيانًا مع رفض بموجب 2.5.2.
هل تسمح Apple باستخدام EAS Update؟
تسمح اتفاقية الترخيص بالكود المُفسَّر المُنزَّل ما دام لا يغير الغرض الأساسي للتطبيق. الإصلاح، نعم. إضافة ميزة لم تُراجع، لا.
هل يمكن استخدام feature flags في تطبيق iOS؟
نعم، إذا كان كل ما يمكنها عرضه قد خضع للمراجعة. فعّل كل مفتاح أثناء المراجعة وصِفه في الملاحظات.
هل يجب إبلاغ المراجع بوضع العرض التجريبي؟
نعم. وضع العرض التجريبي المدمج يحتاج إلى موافقة مسبقة من Apple، ويجب أن يعرض جميع الميزات.
هل يمكن نشر تحديث عن بُعد أثناء المراجعة؟
لا يوجد نص صريح يمنع ذلك. لكن المراجع لن يراه عند التشغيل الأول، وهو يخلق فجوة مع النسخة التي خضعت للمراجعة. أنا أمتنع عن ذلك دائمًا.

