كيفية إصلاح عدم مطابقة معرّف الحزمة Bundle ID ومعرّف التطبيق AASA App ID في روابط آبل الشاملة (iOS Universal Links)

opoinstall
2026-08-18
5 min read

لماذا يتسبب عدم تطابق معرّف الحزمة (Bundle ID) في تعطل روابط آبل الشاملة (Universal Links)؟ يحدث تعطل روابط Universal Links بسبب عدم تطابق معرّف الحزمة عندما لا يتطابق معرّف التطبيق (Application Identifier) الموقع للتطبيق مع مُدخل appID/appIDs المقابل في ملف AASA للنطاق المرتبط، مما يؤدي إلى فشل عملية التحقق من النطاقات المرتبطة (associated-domains).

معرّف الحزمة (CFBundleIdentifier) هو سلسلة نصية فريدة تحدد تطبيق iOS الفردي داخل نظام بيئة Apple. وفي بنيات الروابط الشاملة، يتم دمج معرّف الحزمة مع بادئة معرّف التطبيق (Application Identifier Prefix) لتشكيل معرّف التطبيق (Application Identifier)، والذي يتحقق منه نظام التشغيل مقابل ملف apple-app-site-association المستضاف لترخيص التعامل مع الروابط الأصلية (native URL handling).

المصطلح التعريف
معرّف الحزمة (Bundle ID) معرّف نطاق عكسي فريد مُخصص لهدف تطبيق iOS في Xcode (أي CFBundleIdentifier).
بادئة معرّف التطبيق (Application Identifier Prefix) بادئة معرّف التطبيق المُخصصة في إعدادات حساب مطوري Apple ( وغالباً، وليس دائماً، تتطابق مع معرّف الفريق Team ID).
الروابط الشاملة (Universal Links) آلية Apple القياسية لتوجيه روابط HTTPS الخاصة بالويب مباشرةً إلى واجهات التطبيق الأصلية.
النطاقات المرتبطة (Associated Domains) ترخيص Xcode الذي يوضح النطاقات التي يُصرح للتطبيق بالتعامل معها (applinks:).
ملف AASA ملف JSON (أي apple-app-site-association) المُستضاف على النطاق لترخيص معالجة روابط التطبيق.

سلسلة التشخيص الأساسية

يوضح الرسم البياني أدناه تسلسل التحقق متعدد المستويات الذي يتم تنفيذه أثناء تثبيت التطبيق والتحقق من النطاق:

الطبقة الأولى: حزمة التطبيق الموقعة (Signed App Binary)
       │
       ├── application-identifier (<Prefix>.<BundleID>)
       ├── com.apple.developer.team-identifier
       └── com.apple.developer.associated-domains (applinks:example.com)
                    │
                    ▼
الطبقة الثانية: تسليم ملف AASA واستيعابه عبر شبكة CDN
       │ (البنية التحتية المُدارة من Apple تسترجع ملف AASA الأصلي)
                    ▼
الطبقة الثالثة: مخطط AASA وتطابق الأنماط (Schema & Pattern Matching)
       │ (التحقق من مصفوفة appIDs وقواعد توجيه مكونات/مسارات components/paths)
                    ▼
الطبقة الرابعة: حالة ارتباط الجهاز (Device Association State)
       │ (يسجل نظام التشغيل النطاقات التي تم التحقق منها في قاعدة البيانات المحلية)
                    ▼
الطبقة الخامسة: تنفيذ توجيه التطبيق (Application Routing Execution)
       │ (يوجه النظام الروابط المتطابقة إلى معالجات دورة حياة التطبيق)
مخطط هندسي تقني متقدم من 5 طبقات يوضح سلسلة التحقق من روابط آبل الشاملة (iOS Universal Links) بدءاً من تراخيص الملف الثنائي الموقع وحتى تنفيذ التطبيق الأصلي على خلفية شبكية ذات لون كريمي دافئ.

قائمة التحقق السريعة للإصلاح: روتين تشخيصي في 30 ثانية

عندما تعود الروابط الشاملة بشكل غير متوقع إلى المعالجة عبر الويب، تحقق من هذه العناصر بالترتيب:

  • استخراج المعرّف الموقع (Extract Signed Identifier): افحص الترخيص المضمن في الملف الثنائي المترجم للحصول على معرّف التطبيق الدقيق application-identifier (أي <Prefix>.<BundleID>).
  • التحقق من تنسيق الترخيص (Verify Entitlement Format): تأكد من أن com.apple.developer.associated-domains يحتوي على اسم مضيف دقيق (مثل applinks:subdomain.domain.com) دون مسارات غيرจำเป็นة، أو سلاسل استعلام، أو شرائط مائلة لاحقة (trailing slashes).
  • تدقيق ملف AASA الأصلي (Audit Origin AASA): جلب https://subdomain.domain.com/.well-known/apple-app-site-association وتأكد من إدراج معرّف التطبيق الموقع بحذافيره في الحقل appIDs.
  • التحقق من مطابقة المسار (Validate Path Matching): تأكد من أن عنوان URL المستهدف يطابق أنماط components أو paths المحددة في تكوين AASA.
  • التحقق من نطاق النطاقات (Check Domain Scoping): تأكد من أن ترخيص النطاقات المرتبطة يغطي اسم المضيف المستهدف وأن تكوين AASA المقابل متاح لهذا المضيف. بالنسبة للنطاقات الفرعية، استخدم اسم مضيف صريح أو صيغة النطاق العام البديل *. حسب الاقتضاء.
  • عزل وضع التطوير (Isolate Development Modes): استخدم ?mode=developer على الإصدارات الموقعة لأغراض التطوير لتجاوز التخزين المؤقت لشبكة CDN الخاصة بـ Apple أثناء مرحلة التطوير.

لماذا تُعد دقة معرّف الحزمة ومعرّف التطبيق أمراً بالغ الأهمية

تشريح معرّف التطبيق (Anatomy of an Application Identifier)

لا تقيم عملية التحقق من الروابط الشاملة اسم العرض الخاص بالتطبيق، أو مخطط URL الداخلي، أو اسم الحزمة. ووفقاً لـ وثائق Apple حول تفاصيل applinks.Details، يعتمد نموذج الأمان بشكل صارم على معرّف التطبيق المؤهل بالكامل، والمهيكل بالشكل التالي:

Application Identifier=ApplicationIdentifierPrefix  +  "."  +  CFBundleIdentifier\text{Application Identifier} = \text{ApplicationIdentifierPrefix} \;+\; \text{"."} \;+\; \text{CFBundleIdentifier}

حيث:

  • ApplicationIdentifierPrefix: بادئة معرّف التطبيق المُخصصة في تكوين حساب مطوري Apple الخاص بك (مثل 9JA723G82S). بالنسبة للعديد من حسابات المطورين الحديثة، تتطابق هذه القيمة مع معرّف الفريق (Team ID) المكون من 10 أحرف، ولكن يجب على المهندسين التحقق من البادئة الفعلية في بوابة مطوري Apple بدلاً من افتراض أنهما قابلان للتبديل.
  • CFBundleIdentifier (معرّف الحزمة): سلسلة نطاق عكسي حساسة لحالة الأحرف مُعرفة في إعدادات بناء الهدف (مثل com.example.mobileapp).

في ملف JSON الخاص بـ apple-app-site-association المُستضاف، تظهر هذه السلسلة المركبة داخل مصفوفة appIDs أو مُدخلات قاموس appID (مثل 9JA723G82S.com.example.mobileapp). إذا كان هناك تناقض في الأحرف، أو اختلاف في حالة الأحرف، أو مسافة لاحقة بين الترخيص المضمن في الملف الثنائي المُترجم والمُدخل المُستضاف في ملف AASA، يفشل التحقق من النطاق.

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

كيف تُنشئ النطاقات المرتبطة وملف AASA ارتباطاً ثنائي الاتجاه

على عكس مخططات URL المخصصة، والتي يمكن لأي تطبيق مثبت الإعلان عنها دون التحقق من النطاق، تنشئ الروابط الشاملة ارتباطاً آمناً ثنائي الاتجاه:

  • إعلان التطبيق عن النطاق (App-to-Domain Declaration): يُعلن تطبيق iOS المُترجم عن ملكيته لنطاق ويب معين من خلال تضمين ترخيص com.apple.developer.associated-domains في توقيع الكود الخاص به.
  • تفويض النطاق للتطبيق (Domain-to-App Authorization): يؤكد نطاق الويب أنه يمنح إذن التوجيه لتطبيقات محددة عن طريق استضافة ملف AASA بصيغة JSON على https://<domain>/.well-known/apple-app-site-association أو https://<domain>/apple-app-site-association.

أثناء التثبيت أو تحديثات التطبيق، يتحقق نظام التشغيل من ترخيص النطاقات المرتبطة الموقع للتطبيق مقابل تكوين AASA المسترجع للنطاق. يجب أن يتطابق معرّف التطبيق المستخدم لارتباط التطبيق مع المعرّف المقابل المعلن في تكوين AASA. وبعد تطابق المعرّف، يجب أن يلبي عنوان URL المطلوب أيضاً قواعد components أو paths المُكوّنة.

عرض الفشل: لماذا تُجبر المعرّفات غير المتطابقة على التراجع إلى الويب

عند حدوث عدم تطابق في معرّف التطبيق، لا يُظهر نظام iOS عادةً عدم تطابق معرّف التطبيق كخطأ استثنائي قاتل في وقت التشغيل (runtime exception). بدلاً من ذلك، ينعكس الفشل في حالة التحقق من النطاق المرتبط، أو تشخيصات الجهاز، أو سلوك الرجوع إلى الويب الناتج:

  • معالجة النظام (System Handling): عندما يفشل ارتباط النطاق، لا يقوم النظام باستدعاء التطبيق عبر مسار الرابط الشامل المُحقق منه. وبناءً على كيفية فتح رابط URL وسياق المتصفح المحيط، يظل الرابط في متصفح الويب أو يتراجع إليه بدلاً من تسليمه إلى التطبيق الأصلي.
  • تأثير تجربة المستخدم (User Experience Impact): عندما ينقر المستخدم على رابط ويب متوافق في الرسائل (Messages)، أو البريد (Mail)، أو المتصفح (Safari)، يفشل النظام في التعرف على تعيين تطبيق أصلي مرخص ويفتح رابط الويب في المتصفح.

انظر أيضاً: معرّف الحزمة ──> بنية الروابط الشاملة

كيف تقوم شبكة CDN الخاصة بـ Apple جلب وتخزين ملفات AASA مؤقتاً

مصافحة التثبيت وآليات شبكة CDN الخاصة بـ Apple

عند تثبيت أو تحديث تطبيق يحتوي على ترخيص com.apple.developer.associated-domains، يقوم النظام بإنشاء أو تحديث علاقة النطاقات المرتبطة:

  • أداة التمشيط الوسيطة عبر شبكة CDN: عندما يقوم النظام بإنشاء أو تحديث علاقة النطاقات المرتبطة، فإنه يحصل على بيانات AASA الخاصة بالنطاق من خلال البنية التحتية للنطاقات المرتبطة الخاصة بـ Apple ويستخدم تلك البيانات للتحقق من الارتباط.
  • دورة حياة التخزين المؤقت المستقلة: تتحكم شبكة CDN المُدارة من قِبل Apple في دورة حياة التحديث والتخزين المؤقت الخاصة بها، لذلك لا ينبغي افتراض أن تحديث المصدر سيصبح مرئياً فوراً من خلال شبكة CDN. عند اختبار التغييرات، استخدم وضع التطوير البديل الموثق حسب الاقتضاء وفحص حالة ارتباط الجهاز.
  • متطلبات خادم المصدر (Origin Server Requirements): يجب أن يخدم خادم الويب الأصلي ملف AASA عبر بروتوكول HTTPS مع شهادة TLS موثوقة وصالحة (يتم رفض الشهادات ذاتية التوقيع)، باستخدام نوع MIME المناسب application/json. يجب ألا تعتمد استضافة AASA على عمليات إعادة توجيه HTTP؛ حيث يجب أن تُرجع نقطة نهاية AASA الملف مباشرةً مع رمز الاستجابة 200 OK من HTTP.

اتساق تنسيق ملف AASA بصيغة JSON

تدعم إصدارات iOS الحديثة بناء جملة القاموس components التفصيلي مع الحفاظ على التوافق مع الإصدارات السابقة لمصفوفات paths القديمة.

وفقاً لـ ملاحظة تقنية TN3155 من مطوري Apple بشأن تصحيح أخطاء الروابط الشاملة، داخل مُدخل details معين، يجب على المطورين استخدام إما هيكل appIDs + components الحديث أو هيكل appID + paths القديم؛ ولا تقم بدمج الهيكلين في نفس المُدخل، حيث قد تنتج التكوينات المدمجة سلوك تحقق غير متوقع.

تضمنت أمثلة AASA الأقدم عادةً "apps": []. وبالنسبة عمليات النشر التي تستهدف إصدارات أنظمة تشغيل Apple الحديثة، فإن هذا المفتاح غير مطلوب؛ احتفظ به فقط عند دعم إصدارات أنظمة التشغيل القديمة التي تتوقعه بشكل خاص.

بروتوكول التشخيص: سير عمل الحل خطوة بخطوة

الخطوة 1: فحص تراخيص التطبيق الموقع باستخدام codesign

لتحديد ما إذا كانت حزمة IPA مُصدّرة أو نسخة بناء مخصصة للتطوير تحتوي على معرّف التطبيق والنطاقات المرتبطة المتوقعة بالضبط، افحص توقيع الكود الخاص بالملف الثنائي مباشرةً باستخدام أداة سطر الأوامر codesign الخاصة بنظام macOS. تحقق من application-identifier، وcom.apple.developer.team-identifier، وcom.apple.developer.associated-domains معاً.

يوضح ملف التعريف (provisioning profile) الإمكانيات والنطاقات التي يسمح بها ملف التعريف؛ بينما يُظهر الملف الثنائي الموقع (عبر codesign) ما يحتويه الملف الثنائي الفعلي المشحون.

الخطوة 2: تدقيق مخطط AASA بصيغة JSON المُستضاف

تأكد من أن خادم المصدر يستضيف ملف AASA صالحاً ويمكن الوصول إليه علناً دون الحاجة إلى مصادقة أو عمليات إعادة توجيه. لاحظ أن أمثلة AASA الأقدم كانت تتضمن عادةً "apps": []، بينما تتخلى عنها التكوينات الحديثة التي تستهدف إصدارات iOS المعاصرة.

يوضح مخطط JSON القياسي لـ AASA أدناه توجيه المسار الصحيح باستخدام هيكل appIDs وcomponents الحديث:


```json
{
  "applinks": {
    "details": [
      {
        "appIDs": [
          "9JA723G82S.com.example.mobileapp",
          "9JA723G82S.com.example.mobileapp.staging"
        ],
        "components": [
          {
            "/": "/product/*",
            "comment": "يُطابق مسارات تفاصيل المنتجات"
          },
          {
            "/": "/invite/*",
            "?": { "ref": "?*" },
            "comment": "يُطابق روابط الإحالة مع معلمات الاستعلام المخصصة"
          },
          {
            "/": "/help/*",
            "exclude": true,
            "comment": "يستثني عنوان URL الخاص بدعم العملاء من التوجيه الأصلي"
          }
        ]
      }
    ]
  }
}

الخطوة 3: تشغيل أدوات سطر الأوامر التشخيصية (codesign، swcutil، curl)

على إصدارات macOS التي توفر تشخيصات swcutil، استخدم الأداة لفحص أو التحقق من بيانات النطاقات المرتبطة. نظراً لأن خيارات الأوامر يمكن أن تختلف عبر إصدارات نظام التشغيل وأدوات التطوير، تحقق من الخيارات المتاحة باستخدام الأمر swcutil --help قبل تشغيل سير عمل التشخيص أدناه:

# 0. تأكد من الخيارات المتاحة (قد يختلف بناء الجملة حسب نظام التشغيل وإصدار أداة التطوير)
swcutil --help

# 1. إلغاء ضغط أرشيف IPA المُصدّر
unzip -q YourApp.ipa -d UnpackedApp

# 2. استخراج وفحص التراخيص الموقعة مباشرةً من الملف الثنائي التنفيذي
codesign -d --entitlements :- "UnpackedApp/Payload/YourApp.app" > signed-entitlements.plist 2>/dev/null
/usr/libexec/PlistBuddy -c "Print" signed-entitlements.plist

# 3. التحقق مما إذا كان يمكن تنزيل بيانات AASA للنطاق باستخدام swcutil (أداة تشخيص macOS)
sudo swcutil dl -d custom.opwakeup.com

# 4. التحقق من مطابقة نمط AASA مقابل عنوان URL محدد باستخدام swcutil
sudo swcutil verify -d custom.opwakeup.com -j ./apple-app-site-association -u https://custom.opwakeup.com/product/123

# 5. الاستعلام مباشرة عن نقطة نهاية التشخيص لشبكة CDN للنطاقات المرتبطة المُدارة من Apple
curl -i https://app-site-association.cdn-apple.com/a/v1/custom.opwakeup.com

افحص نقطة نهاية شبكة CDN للنطاقات المرتبطة المُدارة من Apple عند استكشاف أخطاء بيانات AASA التي يتم تسليمها عبر الحافة (edge-delivered) وإصلاحها. تعامل مع نقطة النهاية هذه كبنية تشخيصية تحتية وليست كواجهة برمجة تطبيقات عامة (API contract).

الخطوة 4: استخدام وضع تطوير النطاقات المرتبطة (Associated Domains Developer Mode) لاختبار AASA

وفقاً لـ وثائق Apple حول تكوين النطاقات المرتبطة، توفر Apple وضعاً بديلاً للتطوير. يتيح وضع المطور (?mode=developer) لأجهزة التطوير المؤهلة تجاوز شبكة CDN المُدارة من قِبل Apple وجلب ملف AASA مباشرة من خادم الويب الأصلي عبر بروتوكول HTTPS.

يوضح التكوين أدناه كيفية الإعلان عن وضع المطور في تكوينات ترخيص Xcode منفصلة:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>applinks:custom.opwakeup.com</string>
    </array>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.developer.associated-domains</key>
    <array>
        <string>applinks:custom.opwakeup.com?mode=developer</string>
    </array>
</dict>
</plist>

بمجرد أن ينشئ نظام التشغيل ارتباط النطاق، يتولى التوجيه على مستوى التطبيق التعامل مع حمولات URL الواردة باستخدام تفويضات دورة الحياة القياسية لـ UIKit أو SwiftUI:

import UIKit

// ----------------------------------------------------------------------------
// 1. تنفيذ UIKit AppDelegate
// ----------------------------------------------------------------------------
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        return true
    }

    // رد اتصال متابعة الرابط الشامل القياسي من Apple
    func application(
        _ application: UIApplication,
        continue userActivity: NSUserActivity,
        restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
    ) -> Bool {
        
        guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
              let incomingURL = userActivity.webpageURL else {
            return false
        }
        
        print("جارٍ معالجة الرابط الشامل الذي تم التحقق منه: \(incomingURL.absoluteString)")
        
        // إرسال incomingURL إلى الموجه الداخلي أو طبقة SDK لاستخراج المعلمات
        return handleIncomingRoute(incomingURL)
    }

    private func handleIncomingRoute(_ url: URL) -> Bool {
        // منطق توجيه الوجهة على مستوى التطبيق
        // ملاحظة: إرجاع true يشير إلى أن التطبيق قد تعامل مع النشاط، وليس إلى نجاح تحليل عنوان URL.
        return true
    }
}

// ----------------------------------------------------------------------------
// 2. تنفيذ دورة حياة SceneDelegate (إصدار iOS 13+)
// ----------------------------------------------------------------------------
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if let userActivity = connectionOptions.userActivities.first(where: { $0.activityType == NSUserActivityTypeBrowsingWeb }),
           let incomingURL = userActivity.webpageURL {
            print("الرابط الشامل عند التشغيل البارد: \(incomingURL.absoluteString)")
        }
    }

    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let incomingURL = userActivity.webpageURL {
            print("الرابط الشامل في الواجهة الأمامية: \(incomingURL.absoluteString)")
        }
    }
}

تمكين وضع المطور من جانب العميل على الأجهزة الفعلية:

  1. على نظام iOS 16+، انتقل إلى الإعدادات > الخصوصية والأمان > وضع المطور (Settings > Privacy & Security > Developer Mode) وقم بتبديله إلى وضع التشغيل ON (يتطلب إعادة تشغيل الجهاز).
  2. انتقال إلى الإعدادات > المطور > تطوير النطاقات المرتبطة (Settings > Developer > Associated Domains Development) وقم بتفعيل المفتاح ON.
  3. قم بتثبيت نسخة التطوير الموقعة بملف تعريف توفير تطويري يحتوي على ترخيص ?mode=developer.
  4. ملاحظة الإنتاج: حافظ على تقييد ?mode=developer لبيئات التطوير والاختبار الداخلي فقط، ولا تقم بتضمينه في ترخيص النطاقات المرتبطة الخاصة بالإنتاج ما لم يكن نشرك يتطلب هذا التكوين ويدعمه بشكل صريح.

شجرة قرارات السبب الجذري

يتراجع الرابط الشامل إلى المعالجة عبر الويب
        │
        ├── هل يتطابق معرّف التطبيق الموقع application-identifier مع AASA appIDs؟
        │       ├── لا ──> تصحيح بادئة معرّف التطبيق أو معرّف الحزمة في ملف AASA
        │       └── نعم
        │
        ├── هل يسرد ترخيص النطاقات المرتبطة associated-domains النطاق بدقة؟
        │       ├── لا ──> إضافة applinks:<domain> إلى تراخيص التطبيق المستهدف
        │       └── نعم
        │
        ├── هل ينجح الأمر sudo swcutil dl -d <domain>؟
        │       ├── لا ──> إصلاح بروتوكول HTTPS للمصدر، أو شهادات TLS، أو عمليات إعادة التوجيه 301/302
        │       └── نعم
        │
        ├── هل يتطابق الأمر sudo swcutil verify مع مسار عنوان URL المستهدف؟
        │       ├── لا ──> تصحيح بناء جملة components أو paths في ملف AASA
        │       └── نعم
        │
        └── تحقق من حالة ارتباط الجهاز ومعالجات توجيه التطبيق الداخلية
شجرة قرارات مخطط تقني لتشخيص الأسباب الجذرية لتراجع الروابط الشاملة إلى الويب عبر تراخيص الملف الثنائي، ومخططات AASA، والتخزين المؤقت لشبكة CDN على خلفية شبكية ذات لون كريمي دافئ.

مصفوفة التشخيص: الأسباب الجذرية لفشل الروابط الشاملة

نمط الفشل السبب الجذري الأساسي سلوك النظام الملاحظ المعالجة الموصى بها
خطأ إملائي في معرّف الحزمة حساسية حالة الأحرف أو عدم تطابق الحروف في appIDs داخل ملف AASA يفتح الرابط المتصفح بدلاً من التطبيق الأصلي تصحيح النص في ملف JSON لـ AASA وإعادة النشر إلى المصدر
عدم تطابق بادئة معرّف التطبيق استخدام بادئة غير صحيحة بدلاً من بادئة معرّف التطبيق الفعلية للمطور يفشل ارتباط النطاق أثناء التثبيت التحقق من بادئة معرّف التطبيق في مركز أعضاء Apple
عدم تطابق النطاق الفرعي يشير الترخيص إلى www.example.com بينما ملف AASA موجود على example.com يفشل التطبيق في المطالبة بالروابط من النطاق الفرعي استضافة ملف AASA مخصص على كل نطاق فرعي مطلوب أو تكوين النطاق العام البديل (wildcard)
إعادة توجيه HTTP على نقطة النهاية يقوم خادم المصدر بإرجاع إعادة توجيه 301 أو 302 لرابط AASA تَرفض أداة تمشيط شبكة CDN الخاصة بـ Apple ملف AASA تكوين خادم الويب لإرجاع رمز الاستجابة 200 OK مباشرة
تناقض تنسيق ملف AASA الجمع بين هيكل appID/paths القديم وهيكل appIDs/components الحديث مطابقة مسارات غير متسقة أو جزئية توحيد بناء الجملة باستخدام هياكل appIDs + components الحديثة
عدم تطابق نمط عنوان URL يتم تنزيل ملف AASA بنجاح ولكن عنوان URL المطلوب لا يطابق الأنماط يفتح الرابط في متصفح الويب التحقق من بناء جملة المسار والمكونات باستخدام الأمر swcutil verify
بقاء وضع المطور في إصداره النهائي تحتفظ نسخة التوزيع بوضع التطوير البديل ترخيص غير قياسي في نسخة التوزيع النهائية إزالة ?mode=developer من تكوين بناء الإصدار النهائي (Release)

مخطط مصفوفة مقارنة للمؤسسات الدولية يوضح أنماط فشل روابط آبل الشاملة (iOS Universal Links)، والأسباب الجذرية، وسلوكيات النظام، وخطوات المعالجة مع شارات حالة مميزة على خلفية شبكية ذات لون كريمي دافئ.

تنفيذ التكوين ثنائي البيئة في Xcode

إدارة تكوينات البناء المتعددة (التطوير Debug، المرحلي Staging، الإنتاج Production)

غالباً ما تدير خطوط إنتاج تطوير المؤسسات معرّفات حزمة مميزة عبر بيئات البناء المختلفة (مثل com.example.app.debug، وcom.example.app.staging، وcom.example.app).

للحفاظ على عمل روابط Universal Links بكفاءة عبر جميع تكوينات البناء:

  • إعلانات AASA الصريحة: يجب أن يسرد ملف AASA المُستضاف بوضوح معرّف التطبيق المؤهل بالكامل لكل بيئة داخل مصفوفة appIDs الخاصة به:

    "appIDs": [
      "9JA723G82S.com.example.app",
      "9JA723G82S.com.example.app.staging",
      "9JA723G82S.com.example.app.debug"
    ]
    
    
  • التراخيص الخاصة بالهدف (Target-Specific Entitlements): استخدم إعدادات تكوين بناء Xcode لربط ملفات تراخيص .entitlements منفصلة لكل تكوين بناء، مما يضمن عدم الاستعلام عن نطاقات الإنتاج بواسطة إصدارات التطوير الداخلية (Debug).

إدارة معرّفات الأهداف (Target Identifiers)

لاستكشاف أخطاء روابط Universal Links وإصلاحها، استخدم معرّف الحزمة الدقيق وبادئة معرّف التطبيق من النسخة المبنية الموقعة بدلاً من الاعتماد على المعرّفات التي تحتوي على رموز عامة بديلة (wildcard identifiers). تعامل مع كل اسم مضيف بشكل صريح: إذا كان التطبيق يطالب بالنطاقين example.com وwww.example.com، فقم بتكوين مُدخلات النطاقات المرتبطة المقابلة وتأكد من أن كل اسم مضيف يخدم بيانات AASA المناسبة. تأكد من تكوين الترخيص على الهدف الذي يتعامل فعلياً مع الروابط الشاملة، وتحقق من أي أهداف ملحقة بالتطبيق (app-extension) أو أهداف watchOS بشكل منفصل عند الاقتضاء.

التحقق من ملفات تعريف التوفير المضمنة والملفات الثنائية الموقعة في عمليات CI/CD

قم بأتمتة التحقق من الترخيص ومعرّف التطبيق داخل نصوص بناء التكامل المستمر (CI) قبل رفع الملفات الثنائية إلى TestFlight:

# نص التحقق الآلي لعمليات التكامل المستمر (CI)
security cms -D -i /path/to/embedded.mobileprovision > provision.plist

# 1. فحص تراخيص ملف التعريف للنطاقات المرتبطة المسموح بها
/usr/libexec/PlistBuddy -c "Print :Entitlements:com.apple.developer.associated-domains" provision.plist

# 2. استخراج التراخيص الفعلية الموقعة من الملف الثنائي التنفيذي المترجم
codesign -d --entitlements :- "UnpackedApp/Payload/YourApp.app" > signed-entitlements.plist 2>/dev/null
SIGNED_APP_ID=$(/usr/libexec/PlistBuddy -c "Print :application-identifier" signed-entitlements.plist)
echo "معرّف التطبيق الموقع المستخرج: $SIGNED_APP_ID"

# 3. التحقق من أن النطاقات المرتبطة الموقعة تتطابق مع النطاق المستهدف
/usr/libexec/PlistBuddy -c "Print :com.apple.developer.associated-domains" signed-entitlements.plist

# 4. التحقق من وجود معرّف التطبيق الموقع في ملف AASA المستضاف عبر بايثون (Python)
python3 -c "
import json, sys
signed_id = sys.argv[1]
data = json.load(open('apple-app-site-association'))
app_ids = [app for detail in data.get('applinks', {}).get('details', []) for app in detail.get('appIDs', [])]
if signed_id not in app_ids:
    print(f'AASA mismatch: {signed_id} not found in AASA appIDs: {app_ids}')
    sys.exit(1)
print(f'AASA consistency check passed: {signed_id} registered')
" "$SIGNED_APP_ID"

إذا خرج برنامج نصي للتحقق برمز خطأ، قم بإلغاء خط أنابيب البناء لمنع شحن ملفات ثنائية لروابط عميقة غير معطلة إلى بيئة الإنتاج.

مخطط سير عمل مطور دولي من 4 خطوات لأتمتة التحقق من معرّف التطبيق وملف AASA لروابط آبل الشاملة في خطوط بناء التكامل المستمر (CI/CD) على خلفية شبكية ذات لون كريمي دافئ وناعم.

معايير مطابقة الروابط الشاملة (Universal Link Matching Criteria)

لضمان موثوقية التوجيه، يجب استيفاء الشروط التالية في وقت واحد:

تكوين التطبيق الموقع:
application-identifier = <ApplicationIdentifierPrefix>.<CFBundleIdentifier>
com.apple.developer.associated-domains = applinks:<hostname>

تكوين AASA:
appIDs = [..., "<ApplicationIdentifierPrefix>.<CFBundleIdentifier>", ...]
components / paths = مطابقة مسارات URL المستهدفة ومعلمات الاستعلام

أهلية النظام:
1. يحتوي ترخيص النطاقات المرتبطة صراحة على اسم المضيف المستهدف.
2. يتطابق معرّف التطبيق الموقع مع مُدخل مرخص في حقل appIDs الخاص بالنطاق.
3. يلبي عنوان URL الوارد أنماط توجيه ملف AASA.
4. تسمح حالة ارتباط الجهاز وسياق المستخدم/المتصفح بتفويض التطبيق الأصلي.

حتى عندما يتطابق الترخيص، وارتباط AASA، ونمط URL تماماً، يظل التوجيه الملاحظ معتمداً على حالة الجهاز وسياق المستخدم أو المتصفح. على سبيل المثال، عندما ينقر المستخدم على رابط شامل أثناء تصفح نفس النطاق بالفعل في متصفح Safari، قد يحترم نظام التشغيل رغبة المستخدم في البقاء داخل Safari.

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

ما هو التنسيق الدقيق لمعرّف التطبيق (application identifier) في ملف AASA؟
ي يجب تنسيق معرّف التطبيق بدقة بالشكل التالي `<ApplicationIdentifierPrefix>.<CFBundleIdentifier>`، حيث `<ApplicationIdentifierPrefix>` هي بادئة معرّف التطبيق المرتبطة بالتطبيق في حساب مطوري Apple الخاص بك (مثل `9JA723G82S`) و `<CFBundleIdentifier>` هو معرّف الحزمة (مثل `com.example.app`)، مما ينتج عنه `9JA723G82S.com.example.app`. لا تفترض أن البادئة متطابقة دائماً مع معرّف الفريق (Team ID)؛ بل تحقق من القيمة من ملف تعريف التوفير الخاص بالتطبيق.
لماذا يعمل الرابط الشامل الخاص بي في وضع المطور (Developer Mode) ولكنه يفشل في بيئة الإنتاج؟
يتيح وضع المطور (`?mode=developer`) لأجهزة التطوير المؤهلة تجاوز شبكة CDN المُدارة من قِبل Apple وجلب ملف AASA مباشرةً من خادم الويب الأصلي عبر بروتوكول HTTPS. وإذا فشلت الروابط الشاملة في بيئة الإنتاج، فتشمل الأسباب الشائعة شهادة TLS غير صالحة على خادم المصدر الخاص بك، أو إعادة توجيه HTTP على نقطة نهاية AASA، أو احتواء حمولة AASA في الإنتاج على خطأ تنسيق تم رفضه بواسطة أداة تمشيط شبكة CDN الخاصة بـ Apple.
هل يمكنني استخدام علامات النجمة البديلة (wildcard asterisks) في مصفوفة appIDs بملف AASA؟
لاستكشاف أخطاء الروابط الشاملة وإصلاحها، استخدم معرّف التطبيق الصريح من التطبيق الموقع (`<App ID Prefix>.<Bundle ID>`) وأعلن عن هذا المعرّف في تكوين AASA. لا تستخدم علامة النجمة كبديل للمعرّف الفعلي للتطبيق.

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

تعتمد موثوقية توجيه الروابط الشاملة على التوافق الدقيق على مستوى الأحرف عبر ثلاث عقد: تكوين معرّف التطبيق في بوابة مطوري Apple، وترخيص com.apple.developer.associated-domains في Xcode، وملف JSON الخاص بـ apple-app-site-association المستضاف. لا يمكن لشبكة SDK تابعة لجهة خارجية أو إطار عمل توجيه إصلاح ارتباط نطاق فشل نظام التشغيل في إنشائه؛ بل يمكنه فقط معالجة عنوان URL بعد أن يقوم نظام التشغيل بتسليم الرابط الشامل بنجاح إلى التطبيق. إذا كانت الروابط الشاملة مرتبطة بشكل صحيح على مستوى نظام التشغيل ولكن استخراج المعلمات فشل، فقم بفحص طبقة التوجيه على مستوى التطبيق بشكل منفصل عن طبقة ارتباط النطاق.

إذا كان تطبيقك يتطلب أيضاً استعادة معلمات الروابط الديناميكية وتوجيه عملية الانضمام (onboarding) بعد نجاح ارتباط الرابط الشامل، توفر منصة OpoInstall طبقة SDK اختيارية لهذا العمل الموجه على مستوى التطبيق.

لمعرفة المزيد حول أنماط تكوين النطاقات وتكامل الروابط العميقة، راجع وثائق الروابط العميقة من OpoInstall.

المواد ذات الصلة

  • المفاهيم: التحقق من معرّف التطبيق، والتحقق من مخطط AASA، والتخزين المؤقت لشبكة CDN من Apple، واستخراج التراخيص

  • التقنيات: روابط آبل الشاملة (iOS Universal Links)، وتراخيص Xcode، وبوابة مطوري Apple، وبيانات اعتماد الويب المشتركة (Shared Web Credentials)

  • المعايير: معيار IETF RFC 8259 (تبادل بيانات JSON)، ومواصفات TLS 1.3

  • أدوات التشخيص: أداة سطر الأوامر codesign من Apple، وأداة swcutil في نظام macOS، والاستعلام عن التخزين المؤقت لشبكة CDN المُدارة من Apple

الوثائق الرسمية

Share this article