أصدرت بناءً جديدًا، وانتقلت إلى VPN، فتوقفت الشاشة نفسها عن التحميل. على Android 9 وما بعده يكون التفسير الأكثر شيوعًا أقل إثارة: النظام يرفض HTTP العادي للتطبيقات التي تستهدف API 28 أو أعلى، ولم يغيّر VPN من السياق إلا ما يكفي لكشف ذلك. يعتمد الخطأ الذي تراه على عميل HTTP، ولهذا نادرًا ما يقول cleartext صراحة.

ما هذا الفشل في الحقيقة

ابتداءً من Android 9 يحجب النظام cleartext افتراضيًا بمجرد أن يستهدف التطبيق مستوى API 28 أو أعلى. يرفض النظام الطلب إلى عنوان HTTP عادي قبل أن تغادر أي حزمة واحدة الجهاز. أما الخطأ الذي تراه فيعتمد على مكتبة HTTP: قد يكون فشل شبكة عامًا، وقد يكون مهلة انتظار، وقد يكون رسالة تذكر cleartext صراحة. لكنه لا يصل أبدًا إلى خادمك. يوثّق Android السلوك الافتراضي والبديل المقيّد بالنطاق في دليل إعداد الأمان.

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

لماذا يُلام VPN

ثلاثة أمور تتغير عادةً في وقت واحد. قد يحلّ التطبيق اسم مضيف مختلفًا بعد اتصال VPN، وقد يكون الجهاز جديدًا وببناء أحدث، أو قد يكون البناء نفسه قد انتقل إلى مستوى API مستهدف يشغّل السلوك الافتراضي. VPN مرئي ومستوى SDK المستهدف ليس كذلك، لذلك يحصل VPN على التذكرة.

قارن مستويات الاستهداف في البناء القديم والجديد قبل أن تمسّ إعداد الشبكة. التطبيق الذي يستهدف 27 أو أقل معفى، وهذا يفسّر كل تقرير يقول إن الأمر يعمل على هاتفي الأقدم.

أين تستقر راية Expo فعليًا

في مشروع Expo المُدار، إضافة إعداد إلى app.json لا تعدّل بيان Android، لأن prebuild وبناءات التطوير هي ما ينتج البيان. إضافة الإعداد هي التي تكتب الإعداد في تلك المرحلة. المسار المدعوم هو expo-build-properties، يُضبط في إعداد التطبيق مع خيار cleartext تحت android.

{
  "plugins": [
    ["expo-build-properties", {
      "android": { "usesCleartextTraffic": true }
    }]
  ]
}

المقتطف يضبط خيار الإضافة فقط؛ أما البيان فيُنتج لاحقًا. شغّل prebuild أو بناء عميل تطوير جديدًا، ثم افحص ملف AndroidManifest.xml الناتج بحثًا عن android:usesCleartextTraffic قبل إعادة الاختبار، لأن إعادة التحميل بـ JS وحدها تبقي البيان القديم. طابق إصدار الإضافة مع Expo SDK الذي يعمل عليه المشروع. خيارات الإضافة تتحرك بين الإصدارات، والمقتطف المنسوخ من SDK مختلف مصدر موثوق لعمليات لا تفعل شيئًا بصمت.

سير عمل bare والخيار الأضيق

في React Native العادي يكون المكافئ android:usesCleartextTraffic على عنصر application، أو إعداد أمان شبكة يسمح بـ cleartext لنطاقات محددة فقط. الصيغة المقيّدة بالنطاق هي المفضّلة، لأنها تسمح بـ API الداخلي وتُبقي كل شيء آخر على HTTPS. وهي توثّق أيضًا قائمة استثناءاتها، وهذا هو الجزء الذي سيسأل عنه المراجع.

لا يغيّر أي من الأسلوبين السلوك الافتراضي للمنصة لأي شيء لم تسمّه.

أثبته من سجل الجهاز أولًا

قبل تعديل الإعداد، احصل على الفشل الدقيق. adb logcat على جهاز موصول يُظهر رفض النظام لـ cleartext ويسمّي المكوّن الذي أطلقه. المقبس المرفوض، أو الاسم الذي لا يُحلّ، أو مصافحة TLS الفاشلة تشير إلى مكان آخر تمامًا، وتمكين cleartext لن يفعل سوى إضعاف التطبيق بلا مقابل.

ثم أبقِ الإنتاج صادقًا. cleartext مقبول لنقطة نهاية مخبرية لا تستطيع تقديم TLS، ولمدة أقصر ما يمكنك جدولته فقط. إذا كان API قادرًا على إنهاء TLS داخل الشبكة الخاصة، فضع الشهادة في مخزن الثقة بالجهاز واترك cleartext معطّلًا، لأن النفق يشفّر المسار إلى مخرجه ولا شيء بعده.

بمجرد أن تستجيب نقطة النهاية على HTTPS، أزل الإذن وأعد البناء واختبر على VPN وعلى Wi-Fi العادي في الجلسة نفسها. قد يختلف تحليل الأسماء بين المسارين، والزوج وحده يخبرك أيهما يقول الحقيقة.

مقالات ذات صلة