كيفية حل مشكلة نافذة "العنوان غير صالح" في Safari عند استخدام روابط URL Scheme

opoinstall
2026-10-08
5 min read

لماذا يعرض متصفح Safari رسالة "العنوان غير صالح" عند استخدام URL Scheme؟ يمكن لمتصفح Safari عرض خطأ "عنوان غير صالح" أو "تعذر فتح الصفحة" عندما تحاول صفحة ويب الانتقال إلى رابط مخصص (URL scheme) لا يستطيع النظام العثور على معالج له. يتطلب حل هذه المشكلة الانتقال إلى استخدام روابط Universal Links الموثقة أو تنفيذ آليات رجوع (fallbacks) تعتمد على تفاعل المستخدم لتوجيه المستخدمين الذين لم يثبتوا التطبيق إلى متاجر التطبيقات.

قد يظهر تنبيه "تعذر على Safari فتح الصفحة لأن العنوان غير صالح" عندما يحاول متصفح Safari على الأجهزة المحمولة الانتقال إلى رابط مخصص على جهاز يفتقر إلى التطبيق المستهدف أو معالج مناسب. يتضمن حل هذه المشكلة الانتقال من روابط URI التقليدية إلى روابط Universal Links الموثقة، أو نشر بنيات رجوع متوافقة مع إيماءات المستخدم التي توجه من لم يثبت التطبيق إلى متاجر التطبيقات دون التسبب في أخطاء بروتوكول غير معالجة.

المصطلح التعريف الكيان ذو الصلة دور نية البحث
Custom URL Scheme بروتوكول URI محدد بواسطة التطبيق يسمح لروابط الويب الخارجية بتشغيل التطبيقات الأصلية. توجيه الروابط العميقة (Deep Link Routing) معلوماتي / تجاري
Universal Links آلية HTTPS قياسية تربط نطاقات الويب الموثقة مباشرة بشاشات التطبيقات الأصلية في iOS. الروابط العميقة للجوال تقني / معلوماتي
Web to App العملية الهيكلية لتوجيه زوار متصفح الويب إلى تطبيقات الجوال الأصلية. مسار التحويل (Conversion Funnel) معلوماتي

لماذا يعرض Safari خطأ "العنوان غير صالح" مع الروابط المخصصة

تفشل الروابط المخصصة في Safari عندما لا يوجد معالج أصلي للبروتوكول المطلوب.

السبب الجذري: كيف يستجيب WebKit لبروتوكولات URI غير المسجلة

عندما يتفاعل المستخدم مع رابط على صفحة ويب، يقوم محرك عرض المتصفح بتقييم بروتوكول URI لتحديد بروتوكول النقل المناسب أو معالج التطبيق. في متصفح Safari، الذي يعمل بمحرك WebKit، تتم معالجة بروتوكولات الويب القياسية مثل http:// و https:// داخلياً بواسطة محمل موارد الشبكة.

عندما تطلب صفحة ويب من Safari الانتقال إلى رابط مخصص (مثل myapp://product/detail/1024)، يحاول نظام التشغيل تحديد موقع تطبيق مثبت قام بتسجيل هذا البروتوكول المحدد ضمن إعدادات حزمة CFBundleURLTypes الخاصة به. إذا كان التطبيق موجوداً، يمكن لنظام iOS تشغيل التطبيق الأصلي. أما إذا لم يكن التطبيق مثبتاً على الجهاز، فلا يمكن حل الرابط عبر طبقات DNS أو نقل الويب القياسية. ونظراً لأن Safari لا يمتلك معالج ويب داخلي للروابط المخصصة، فإن محاولة الانتقال إلى بروتوكول مخصص غير معالج قد تؤدي إلى ظهور مربع حوار تنبيه يفيد بأن Safari لا يمكنه فتح الصفحة لأن العنوان غير صالح.

حاجز الحماية (Sandbox): لماذا لا تستطيع JavaScript الاستعلام عن حالة تثبيت التطبيق

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

يفرض متصفح Safari حماية صارمة (Sandbox) بين محتوى الويب ونظام التشغيل المضيف. يُمنع كود JavaScript الخاص بصفحة الويب من الاستعلام عن سجلات نظام الملفات المحلي، أو فحص حزم التطبيقات المثبتة، أو التحقق مما إذا كان رابط URI خارجي لديه معالج نشط. ونظراً لأن المتصفح لا يستطيع فحص حالة التثبيت مسبقاً، فإن تنفيذ رابط مخصص غير معالج على جهاز لا يحتوي على التطبيق المطابق يهدد بظهور تنبيه فشل WebKit.

الإضرار بتجربة المستخدم: كيف تؤدي تنبيهات النظام الأصلية إلى زيادة معدلات الارتداد في صفحات الهبوط

إن مواجهة رسالة نظام تفيد بأن "العنوان غير صالح" تضر بثقة المستخدم وتعطل مسارات التحويل:

  • القلق الأمني: قد يفسر المستخدمون تنبيهات "العنوان غير صالح" كمؤشرات على موقع ويب معطل، أو برامج غير موثوقة، أو تحذيرات أمنية.
  • مقاطعة المسار: يتطلب التنبيه من المستخدم الاعتراف وإغلاق نافذة حوار مانعة قبل التفاعل مع الصفحة مرة أخرى، مما يزيد من معدل المغادرة الفوري.
  • تعثر الانتقال للمتجر: إذا ظهر تنبيه غير معالج بالتزامن مع سكربتات إعادة التوجيه الثانوية للمتجر، فسيظهر الانتقال إلى متجر التطبيقات بشكل غير متسق.

لماذا تفشل الحلول البديلة التاريخية في إصدارات WebKit الحديثة

قيود فحص الـ Iframe المخفي في Safari الحديث

في إصدارات iOS السابقة، كان المطورون غالباً يستخدمون فحص الـ iframe المخفي. يقوم سكربت بحقن عنصر <iframe> غير مرئي في DOM وتعيين مصدره إلى الرابط المخصص (myapp://)، مع تشغيل مؤقت JavaScript متزامن. كان الهدف هو أن يتم تشغيل التطبيق المثبت دون التنقل في النافذة الرئيسية، بينما يفشل التطبيق غير المثبت بصمت داخل الإطار.

في متصفحات الجوال المعاصرة، هذا النهج غير موثوق به:

  • يطبق WebKit الحديث قيود التنقل والحماية التي قد تحد من تسليم البروتوكولات الخارجية من الـ iframes، خاصة في الإطارات المحمية.
  • محاولة تحميل بروتوكولات غير مسجلة داخل iframes لا تزال تؤدي إلى ظهور مربعات حوار خطأ على مستوى المتصفح أو الفشل بصمت دون توفير بديل نظيف.
  • نظراً لأن فحص الـ iframe غير متسق عبر إصدارات iOS وسياقات الحماية، فلا يجب التعامل معه كآلية موثوقة لتقييم وجود التطبيق.

تخلق مؤقتات الروابط المخصصة القديمة ظروف سباق بين محاولات تشغيل التطبيق وإعادة التوجيه للمتجر.

سلاسل window.location المعتمدة على المؤقتات: لماذا تقيد المتصفحات الحديثة عمليات إعادة التوجيه التلقائية

تضمن أسلوب قديم آخر تنفيذ سلسلة معتمدة على المؤقت باستخدام window.location.href:

// نمط قديم: هش ومقيد في المتصفحات الحديثة
window.location.href = "myapp://product/detail";
setTimeout(function() {
    window.location.href = "https://apps.apple.com/app/id123456789";
}, 2000);

يخلق هذا النهج أوضاع فشل متعددة في تجربة المستخدم والأداء التقني:

  1. تنبيهات متزامنة: إذا لم يكن التطبيق مثبتاً، يمكن لـ Safari عرض نافذة "العنوان غير صالح" عند تقييم الرابط المخصص، مما يجبر المستخدم على إغلاق التنبيه بينما يبدأ المؤقت في الخلفية عملية تنقل ثانوية.
  2. إعادة توجيه غير مقصودة: إذا كان التطبيق مثبتاً وفتح بنجاح، فقد يقوم المتصفح مع ذلك بتنفيذ المؤقت المعلق عند العودة إلى المتصفح، مما يعيد توجيه المستخدم إلى متجر التطبيقات دون داعٍ عند عودته إلى Safari.

تنشيط المستخدم وسياسات التنقل في المتصفح

تفرض متصفحات الجوال الحديثة سياسات تنشيط المستخدم التي تقيد التنقلات غير المطلوبة. يحد WebKit من عمليات إعادة توجيه النوافذ الآلية وتسليم البروتوكولات الناشئة عن مؤقتات الخلفية أو نداءات الاستدعاء غير المتزامنة أو سكربتات التحميل دون تفاعل حديث من المستخدم.

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

لماذا صممت Apple روابط Universal Links كالحل المفضل

للقضاء على أوضاع الفشل في روابط URL الخاصة، قدمت Apple روابط Universal Links في نظام iOS 9. تستبدل هذه الروابط البروتوكولات المخصصة (myapp://) بروابط ويب HTTPS قياسية وموثقة (https://app.example.com/product/1024).

من خلال تثبيت الروابط العميقة في بنية HTTPS القياسية، أزالت Apple وضع الفشل للبروتوكول غير المسجل. إذا كان التطبيق مثبتاً ومرتبطاً ومؤهلاً في سياق التنقل الحالي، يقوم نظام iOS بتوجيه الرابط مباشرة إلى المعالجات الأصلية؛ أما إذا لم يكن التطبيق مثبتاً، يواصل Safari التنقل في رابط HTTPS كمورد ويب عادي، مما يؤدي إلى تحميل صفحة ويب أو بديل للمتجر دون تنبيهات بروتوكول.

كيف تقضي Universal Links على تنبيه "العنوان غير صالح"

تستخدم Universal Links بروتوكول HTTPS موثق بحيث يتحول فشل التسليم الأصلي إلى وجهة ويب صالحة.

أساس HTTPS: إزالة وضع فشل البروتوكول غير المسجل

يكمن الاختلاف الرئيسي بين رابط URL مخصص ورابط Universal Link في كيفية تقييم مكدس شبكة المتصفح للرابط المطلوب:

  • Custom Scheme (myapp://): بروتوكول غير قياسي. لا يمكن لـ WebKit حله عبر DNS أو نقل الويب القياسي. إذا لم يوجد تطبيق مسجل يعالج البروتوكول، فقد يؤدي الطلب إلى ظهور خطأ عنوان غير صالح.
  • Universal Link (https://app.example.com): رابط HTTPS قياسي وكامل. يقوم WebKit بحل وتحميل عناوين HTTPS بشكل طبيعي.

ونظراً لأن Universal Link هو أساساً رابط ويب صالح، لا يواجه Safari أبداً بروتوكولاً غير مسجل. إذا لم يحدث التسليم للتطبيق الأصلي، يقوم Safari ببساطة بتحميل محتوى الويب المستضاف في ذلك العنوان.

الارتباط ثنائي الاتجاه: تنسيق استحقاقات التطبيق مع ملف AASA المستضاف

تؤسس Universal Links توجيهاً موثقاً من خلال ارتباط بين ثنائي تطبيق الجوال ونطاق موقع الويب:

  1. استحقاق التطبيق: يعلن تطبيق iOS عن استحقاق Associated Domains يحتوي على سلسلة النطاق المستهدف: applinks:app.example.com.
  2. إعلان الخادم: يستضيف نطاق الموقع ملف JSON في https://app.example.com/.well-known/apple-app-site-association (AASA). يحدد هذا الملف معرفات التطبيقات المصرح لها ومكونات مطابقة المسار.
  3. الحل على مستوى نظام التشغيل: عند تثبيت المستخدم للتطبيق، يتحقق iOS من ارتباط النطاق. عند النقر على رابط مرتبط، يقيم نظام التشغيل ما إذا كان بإمكان تطبيق مؤهل معالجة الوجهة.

التدهور الرشيق للويب: ماذا يحدث عندما لا يكون التطبيق مثبتاً

عندما ينقر مستخدم لم يثبت التطبيق على Universal Link:

  1. يقيم نظام تشغيل iOS الرابط مقابل سجل ارتباطاته الموثقة.
  2. بسبب عدم العثور على تطبيق مثبت يطابق النطاق، يفوض iOS الرابط إلى Safari كتنقل ويب قياسي.
  3. يحمل Safari صفحة الويب المستضافة في ذلك الرابط دون عرض أي تنبيهات خطأ من النظام.
  4. يمكن لصفحة الويب المستضافة عرض محتوى المنتج ذي الصلة، أو تقديم زر تحميل من متجر التطبيقات، أو تنسيق استعادة المعلمات المؤجلة.

إدارة تحذير التنقل في نفس النطاق في Safari باستخدام نطاقات فرعية مخصصة

عند نشر Universal Links على صفحات الويب، يجب على الفرق مراعاة سلوك التنقل في نفس النطاق في Safari، كما هو موثق في وثائق مطوري Apple حول السماح للتطبيقات ومواقع الويب بالربط بمحتواك.

إذا تصفح المستخدم صفحة ويب مستضافة على https://example.com/promo ونقر على Universal Link يشير إلى نفس النطاق تماماً (https://example.com/product/1024)، يفترض Safari أن المستخدم ينوي متابعة تصفح الموقع ويحمل صفحة الويب بدلاً من فتح التطبيق الأصلي.

استخدام مضيف توجيه مرتبط بشكل منفصل يتجنب حالة الاستمرار في نفس النطاق الموثقة ويسمح بتقييم Universal Link للتوجيه الأصلي عندما يكون ارتباط النطاق الخاص به صالحاً:

  • استضف الموقع الأساسي على نطاق الجذر أو نطاق الويب الفرعي: https://www.example.com.
  • قم بتهيئة توجيه Universal Link من خلال نطاق فرعي مخصص ومرتبط بشكل منفصل: https://app.example.com.

النقر عبر حدود النطاقات الفرعية المميزة يرضي استدلالات التنقل في Safari، مما يدعم تنفيذ التطبيق الأصلي مباشرة.

تنفيذ عمليات تسليم الويب إلى التطبيق المرنة باستخدام SDKs

هيكلة بدائل متعددة المستويات: Universal Links أولاً، ثم البديل الصريح

تنشر بنيات الويب إلى التطبيق في بيئة الإنتاج سلسلة إعادة توجيه متعددة المستويات:

  • المستوى 1 (Universal Links): يستدعي زر الدعوة لاتخاذ إجراء (CTA) الرئيسي Universal Link موثقاً يشير إلى نطاق فرعي مرتبط. على الأجهزة التي تحتوي على التطبيق، يتيح ذلك توجيهاً أصلياً دون وضع التنبيه الخاص بالرابط المخصص غير المسجل.
  • المستوى 2 (بديل الويب السياقي): إذا لم يكن التطبيق مثبتاً، ينتقل Universal Link بسلاسة إلى صفحة هبوط الويب المستضافة، مع تقديم زر تحميل من متجر التطبيقات.
  • المستوى 3 (بديل الرابط المخصص): حيث يتم الحفاظ على الروابط المخصصة القديمة (myapp://) لإصدارات نظام التشغيل الأقدم أو حاويات مضمنة معينة، يتم استدعاؤها كبديل يجب أن ينشأ عموماً من تفاعل مستخدم صريح بدلاً من السكربتات الآلية.

يجب أن تظل بدائل البروتوكول القديمة مُشغلة من قبل المستخدم وتستخدم الرؤية فقط كاستدلال للقمع.

استخدام Page Visibility API كإشارة قمع استدلالية

عند تنفيذ مؤقتات بديلة جنباً إلى جنب مع الروابط المخصصة، تقوم سكربتات العميل بتقييم ما إذا كان المستند قد فقد رؤية المقدمة من أجل إلغاء عمليات إعادة التوجيه المعلقة للمتجر. ونظراً لأن JavaScript لا يمكنها فحص تنفيذ العملية الأصلية مباشرة، تستخدم بنيات الواجهة الأمامية معيار WHATWG HTML حول رؤية الصفحة.

عندما تنتقل علامة تبويب المتصفح إلى الخلفية بعد تسليم خارجي، يكتشف السكربت تغيير الرؤية:

// تأخير بديل توضيحي؛ عايره بناءً على متطلبات تجربة مستخدم التطبيق
var fallbackTimer = setTimeout(function() {
    if (!document.hidden) {
        // ظل المستند مرئياً في المقدمة؛ تابع مع زر الـ CTA البديل
        window.location.href = "https://apps.apple.com/app/id123456789";
    }
}, 2000);

document.addEventListener("visibilitychange", function() {
    if (document.hidden) {
        // أصبح المستند مخفياً؛ اقمع مؤقت البديل المعلق
        clearTimeout(fallbackTimer);
    }
});

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

ربط إيماءات المستخدم بعناصر Universal Link التراكمية

بالنسبة لتوجيه الروابط المباشر، يربط مطورو الواجهات الأمامية عناصر الارتباط التراكمية مباشرة بنقاط نهاية Universal Link الموثقة. عند حدوث نقرات المستخدم، يتنقل المتصفح عبر رابط HTTPS، مما يسمح لنظام iOS باعتراض المسار.

في مسارات الاستحواذ المتقدمة، تدعم منصات مثل OpoInstall استعادة المعلمات المؤجلة كقناة إدخال مساعدة منفصلة. من خلال تسجيل سياق الويب وقت النقر وربطه بإشارات التشغيل بعد التثبيت عبر خطافات SDK الأصلية، يمكن للتطبيق الأصلي استرداد معلمات الحملة المخصصة عند التشغيل الأولي دون تغيير التحقق القياسي من رابط Universal Link. راجع وثائق تكامل SDK للحصول على تفاصيل حول دمج مستمعات الإسناد المؤجل بجانب معالجات Universal Link الأصلية.

[المستخدم ينقر على زر الـ CTA للويب]
             │
             ▼
[تقييم بدائية التوجيه]
   ┌─────────┴─────────┐
   ▼                   ▼
[Custom Scheme: myapp://] [Universal Link: https://]
   │                           │
   ▼                           ▼
[Safari يحاول الحل]   [نظام التشغيل يقيم الارتباط]
├─ التطبيق يحل -> يفتح التطبيق   ├─ التطبيق مثبت + مؤهل -> التطبيق الأصلي
└─ لا يوجد معالج / محظور ->     └─ غير مثبت ->
   قد يظهر تنبيه نظام           يحمل صفحة هبوط الويب برشاقة
   "العنوان غير صالح"          │
                                  ▼
                                  [يعرض المتجر أو بديل الويب]

التنفيذ من جانب العميل: توجيه Universal Link ومعالجة البدائل

تهيئة سكربتات إعادة توجيه Universal Link الحديثة في HTML/JavaScript

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

الاستقبال الأصلي على iOS في بنيات دورة الحياة المعتمدة على المشهد (Scene)

بالنسبة لتطبيقات iOS المعتمدة على المشاهد، تتم معالجة Universal Links التي يسلمها Safari من خلال دورة حياة UIWindowSceneDelegate: scene(_:willConnectTo:options:) عند التشغيل البارد و scene(_:continue:) عندما يكون التطبيق قيد التشغيل أو معلقاً في الذاكرة. يتحقق التنفيذ الأصلي من أن NSUserActivity الواردة لديها نوع نشاط NSUserActivityTypeBrowsingWeb، ويستخرج webpageURL، ويتحقق من المسار.

يوضح التنفيذ التقني أدناه كيفية تهيئة ارتباط الواجهة الأمامية التراكمي ومعالجة روابط Universal Link الواردة بشكل آمن في Swift الأصلي.

// الويب: تسليم Universal Link للواجهة الأمامية مع بديل الرابط التراكمي
// يهيئ وجهة HTTPS Universal Link نظيفة مع تنقية الاستعلام من جانب العميل.
(function() {
    var ctaButton = document.getElementById("openAppBtn");
    if (!ctaButton) return;

    // 1. الحالة الأولية: Universal Link موثق على نطاق فرعي مخصص يتجنب استمرار Safari في نفس النطاق
    var targetBaseUrl = "https://app.example.com/detail/1024";

    // 2. استخراج وتنقية معلمات الاستعلام الديناميكية من URL الصفحة الحالية
    var urlParams = new URLSearchParams(window.location.search);
    var rawId = urlParams.get("id") || "";
    var rawPromo = urlParams.get("promo_code") || "";
    var rawSource = urlParams.get("utm_source") || "web_landing";

    var idRegex = /^[A-Za-z0-9_-]{1,64}$/;
    var targetId = idRegex.test(rawId) ? rawId : "";
    var promoCode = idRegex.test(rawPromo) ? rawPromo : "";
    var utmSource = idRegex.test(rawSource) ? rawSource : "web_landing";

    var finalUrl = targetBaseUrl + "?utm_source=" + encodeURIComponent(utmSource);
    if (targetId.length > 0) {
        finalUrl += "&id=" + encodeURIComponent(targetId);
    }
    if (promoCode.length > 0) {
        finalUrl += "&promo_code=" + encodeURIComponent(promoCode);
    }

    // تعزيز تراكمي: رابط href يوفر تنقل Universal Link مباشر وخالٍ من التنبيهات
    if (ctaButton.tagName.toLowerCase() === "a") {
        ctaButton.setAttribute("href", finalUrl);
    } else {
        ctaButton.addEventListener("click", function(e) {
            e.preventDefault();
            window.location.assign(finalUrl);
        });
    }
})();
// iOS: SceneDelegate.swift - معالجة Universal Link وتنقية المسار
// مثال تكامل مرجعي. تحقق من توقيعات الأسلوب والتوجيه مقابل بنيتك المنشورة.
import UIKit

struct ValidatedAppRoute {
    let path: String
    let queryParams: [String: String]
}

class AppRouteValidator {
    private static let allowedHosts = Set(["app.example.com"])
    private static let allowedPathPrefixes = ["/detail/", "/promo/"]
    private static let allowedKeys = Set(["id", "promo_code", "utm_source"])

    static func validate(url: URL) -> ValidatedAppRoute? {
        guard let scheme = url.scheme?.lowercased(), scheme == "https" else {
            return nil
        }
        guard let host = url.host?.lowercased(), allowedHosts.contains(host) else {
            return nil
        }

        let path = url.path
        guard allowedPathPrefixes.contains(where: { path.hasPrefix($0) }) else {
            return nil
        }

        var sanitizedParams: [String: String] = [:]
        var seenKeys = Set<String>()

        if let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
           let queryItems = components.queryItems {
            let validChars = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")
            for item in queryItems {
                // التحقق من خلال الفشل المغلق: ارفض URL إذا كانت هناك مفاتيح استعلام غير معروفة
                guard allowedKeys.contains(item.name), !seenKeys.contains(item.name) else {
                    return nil
                }
                seenKeys.insert(item.name)

                let value = item.value ?? ""
                if value.count <= 64 && value.rangeOfCharacter(from: validChars.inverted) == nil {
                    sanitizedParams[item.name] = value
                } else {
                    return nil
                }
            }
        }

        return ValidatedAppRoute(path: path, queryParams: sanitizedParams)
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let _ = (scene as? UIWindowScene) else { return }

        // معالجة التشغيل البارد عبر Universal Link
        if let userActivity = connectionOptions.userActivities.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }),
           let webpageURL = userActivity.webpageURL {
            processIncomingUniversalLink(url: webpageURL)
        }
    }

    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        // معالجة استئناف التطبيق الدافئ عبر Universal Link
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let webpageURL = userActivity.webpageURL {
            processIncomingUniversalLink(url: webpageURL)
        }
    }

    private func processIncomingUniversalLink(url: URL) {
        // فرض القائمة البيضاء الصارمة والتنقية على Universal Link الوارد
        if let route = AppRouteValidator.validate(url: url) {
            DispatchQueue.main.async {
                AppNavigator.shared.navigateTo(path: route.path, params: route.queryParams)
            }
        } else {
            DispatchQueue.main.async {
                AppNavigator.shared.navigateToDefaultHome()
            }
        }
    }
}

// منسق تنقل التطبيق (ليس API لـ SDK)
class AppNavigator {
    static let shared = AppNavigator()

    func navigateTo(path: String, params: [String: String]) {
        // تنفيذ انتقال وحدة تحكم عرض الواجهة الداخلية بناءً على المسار ومعلمات الاستعلام
    }

    func navigateToDefaultHome() {
        // العودة بأمان إلى الشاشة الرئيسية عند وجود روابط عميقة مشوهة أو غير معروفة
    }
}

تنقية المعلمات الواردة: فرض تصفية القائمة البيضاء الصارمة على المسارات الأصلية

وفقاً لـ توجيهات دليل اختبار أمان تطبيقات الجوال من OWASP بشأن الروابط العميقة غير الآمنة، يجب التعامل مع جميع المعلمات التي يتم تسليمها عبر Universal Links كمدخلات غير موثوقة:

  • التحقق من المسار: تحقق من أن مسار URL يطابق قائمة بيضاء مصرح بها لوحدات التحكم في العرض (/detail/، /promo/).
  • تصفية الاستعلام: فرض مفاتيح استعلام مسموح بها (id، promo_code، utm_source) وتجاهل المفاتيح غير المتوقعة.
  • حدود الطول والحروف: تقييد قيم المعلمات بمجموعات الحروف الأبجدية الرقمية (≤64\le 64 حرفاً).

مصفوفة بروتوكول الروابط العميقة في Safari وتخفيف الأخطاء

قائمة مراجعة شاملة لمقارنة البروتوكول ومنع الأخطاء

اختيار بروتوكول الروابط العميقة المناسب أمر بالغ الأهمية لمنع أخطاء تنقل WebKit. تقارن المصفوفة أدناه آليات الروابط العميقة الأساسية عبر سلوكيات الأخطاء ومتطلبات النظام:

مقارنة الروابط المخصصة، وUniversal Links، ولافتات التطبيقات الذكية عبر سلوكيات الخطأ

بروتوكول التوجيه البروتوكول الأساسي السلوك عند تثبيت التطبيق السلوك عند عدم تثبيت التطبيق مخاطر تنبيه "العنوان غير صالح"
Custom URL Scheme myapp:// يشغل التطبيق الأصلي إذا كان مسجلاً يمكن أن يثير تنبيه "العنوان غير صالح" في Safari محتمل (يحدث عند عدم وجود تطبيق يعالج البروتوكول)
Universal Link https:// يفتح التطبيق المرتبط عند التأهل في السياق الحالي يواصل تنقل الويب إلى صفحة الهبوط المستضافة منخفض (يلغي وضع خطأ البروتوكول غير المسجل)
Apple Smart App Banner WebKit <meta> أصلي يعرض خياراً أصلياً لفتح التطبيق يعرض خياراً أصلياً لعرض متجر التطبيقات لا ينطبق على فشل الرابط المخصص غير المسجل
Custom Web Banner JavaScript + Universal Link ينفذ تنبيه التطبيق المباشر عبر SDK يثير إعادة توجيه المتجر أو دعوة ويب (CTA) منخفض (يستخدم توجيه HTTPS موثق)

الأسئلة الشائعة (FAQ)

هل يمكنني اكتشاف ما إذا كان تطبيق iOS مثبتاً باستخدام JavaScript قبل تشغيل URL scheme؟
لا. بموجب بنية الأمان والخصوصية لنظام تشغيل Apple، لا يمكن لـ JavaScript الخاص بصفحة الويب التي تعمل في Safari فحص التطبيقات المثبتة أو الاستعلام عن سجلات البروتوكول المحلية. محاولة الانتقال مباشرة إلى رابط مخصص غير معالج قد تتسبب في عرض WebKit لخطأ عنوان غير صالح إذا لم يستجب أي تطبيق مسجل.
كيف تمنع روابط Universal Links خطأ العنوان غير صالح في Safari؟
تستخدم Universal Links عناوين URL قياسية بنظام HTTPS (`https://app.example.com/...`) موثقة من خلال ملف Apple App Site Association (AASA). ونظراً لأن الرابط هو عنوان ويب قياسي، فإذا لم يكن التطبيق مثبتاً، يواصل Safari التنقل إلى وجهة الويب أو إعادة التوجيه إلى المتجر دون مواجهة بروتوكول غير معترف به.
لماذا يفتح رابط Universal Link أحياناً الموقع بدلاً من التطبيق في Safari؟
إذا نقر المستخدم على Universal Link موجود على نفس النطاق بالضبط لصفحة الويب المعروضة حالياً، يفترض Safari أن المستخدم ينوي متابعة تصفح الموقع ويحمل صفحة الويب. لتجنب سلوك الاستمرار في نفس النطاق الموثق في Safari، قم بتهيئة Universal Links على نطاق فرعي مخصص (مثل `app.example.com`) متميز عن موقعك الأساسي.

الملخص وإطار اتخاذ القرار

تنبيه "لا يمكن لـ Safari فتح الصفحة لأن العنوان غير صالح" هو نتيجة تشغيلية لاستخدام روابط URI مخصصة على أجهزة لا يوجد بها معالج تطبيق مطابق. الاعتماد على فحص iframe المخفي القديم أو سلاسل المؤقتات الآلية يقدم هشاشة في التنقل ويضر بمسارات تحويل الويب إلى التطبيق.

الانتقال إلى Universal Links الموثقة يزيل وضع فشل البروتوكول المخصص غير المسجل ويوفر مسار رجوع موثق عبر HTTPS. من خلال الجمع بين ارتباطات HTTPS الموثقة وأنماط تكامل الويب المتوافقة مع إيماءات المستخدم، تقلل فرق الهندسة من تنبيهات المتصفح المزعجة، وتحافظ على معلمات التسويق عبر تنزيلات المتجر، وتدعم تجارب إعداد موثوقة عبر مسارات الويب للجوال.

لمعرفة كيفية تنفيذ Universal Links وتمرير المعلمات الآلي، راجع وثائق تكامل SDK.

مواد ذات صلة

Share this article