Cách khắc phục lỗi không khớp Bundle ID và AASA App ID trong Universal Links trên iOS

opoinstall
2026-08-18
5 min read

Tại sao việc không khớp bundle ID lại làm hỏng iOS Universal Links? Tình trạng không khớp Bundle ID làm hỏng Universal Links khi Định danh Ứng dụng đã ký của ứng dụng không khớp với mục nhập appID/appIDs tương ứng trong AASA cho miền liên kết, khiến quá trình xác minh miền liên kết thất bại.

Bundle ID (CFBundleIdentifier) là một chuỗi duy nhất định danh một ứng dụng iOS cụ thể trong hệ sinh thái của Apple. Trong kiến trúc Universal Link, Bundle ID được kết hợp với Tiền tố Định danh Ứng dụng để tạo thành Định danh Ứng dụng, mà hệ điều hành sẽ xác thực dựa trên tệp apple-app-site-association được lưu trữ để ủy quyền xử lý URL gốc.

Thuật ngữ Định nghĩa
Bundle ID Mã định danh đảo ngược DNS duy nhất được gán cho một mục tiêu ứng dụng iOS trong Xcode (CFBundleIdentifier).
Tiền tố Định danh Ứng dụng (Application Identifier Prefix) Tiền tố Mã ứng dụng được gán trong cài đặt tài khoản Nhà phát triển Apple (thường, nhưng không phải luôn luôn, giống với Team ID).
Universal Links Cơ chế chuẩn của Apple để định tuyến URL HTTPS web trực tiếp đến các giao diện ứng dụng gốc.
Miền liên kết (Associated Domains) Quyền hạn trong Xcode khai báo miền web nào mà ứng dụng được ủy quyền xử lý (applinks:).
Tệp AASA Tệp JSON (apple-app-site-association) được lưu trữ trên một miền để ủy quyền xử lý URL của ứng dụng.

Chuỗi chẩn đoán chuẩn

Biểu đồ dưới đây minh họa trình tự xác minh nhiều tầng được thực thi trong quá trình cài đặt ứng dụng và xác thực miền:

Tầng 1: Tệp nhị phân ứng dụng đã ký
       │
       ├── application-identifier (<Prefix>.<BundleID>)
       ├── com.apple.developer.team-identifier
       └── com.apple.developer.associated-domains (applinks:example.com)
                    │
                    ▼
Tầng 2: Phân phối AASA & Ingestion qua CDN
       │ (Hạ tầng do Apple quản lý truy xuất AASA gốc)
                    ▼
Tầng 3: Lược đồ AASA & Khớp mẫu
       │ (Xác thực mảng appIDs và các quy tắc định tuyến components/paths)
                    ▼
Tầng 4: Trạng thái liên kết thiết bị
       │ (Hệ điều hành đăng ký các miền đã xác minh trong cơ sở dữ liệu cục bộ)
                    ▼
Tầng 5: Thực thi định tuyến ứng dụng
       │ (Hệ thống định tuyến các URL khớp đến các trình xử lý vòng đời ứng dụng)
Sơ đồ kiến trúc kỹ thuật 5 tầng nâng cao minh họa chuỗi xác minh iOS Universal Links từ quyền hạn nhị phân đã ký đến việc thực thi ứng dụng gốc trên nền lưới màu kem ấm áp.

Danh sách kiểm tra sửa lỗi nhanh: Quy trình chẩn đoán 30 giây

Khi Universal Links bất ngờ quay lại xử lý dạng web, hãy xác minh các mục sau theo thứ tự:

  • Trích xuất Định danh đã ký: Kiểm tra quyền hạn được nhúng trong tệp nhị phân đã biên dịch để lấy chính xác application-identifier (<Prefix>.<BundleID>).
  • Xác minh định dạng quyền hạn: Xác nhận rằng com.apple.developer.associated-domains chứa chính xác tên máy chủ (ví dụ: applinks:subdomain.domain.com) mà không có đường dẫn thừa, chuỗi truy vấn hoặc dấu gạch chéo ở cuối.
  • Kiểm tra AASA gốc: Tải về https://subdomain.domain.com/.well-known/apple-app-site-association và đảm bảo Định danh Ứng dụng đã ký được liệt kê đầy đủ trong phần appIDs.
  • Xác thực khớp đường dẫn: Xác nhận rằng URL mục tiêu khớp với các mẫu components hoặc paths được định nghĩa trong cấu hình AASA.
  • Kiểm tra phạm vi miền: Đảm bảo rằng quyền miền liên kết bao gồm tên máy chủ mục tiêu và cấu hình AASA tương ứng có sẵn cho tên máy chủ đó. Đối với các tên miền phụ, hãy sử dụng tên máy chủ rõ ràng hoặc dạng ký tự đại diện *. được hỗ trợ khi phù hợp.
  • Cô lập chế độ phát triển: Sử dụng ?mode=developer trên các bản dựng được ký cho mục đích phát triển để bỏ qua việc lưu vào bộ nhớ đệm CDN của Apple trong quá trình lặp lại.

Tại sao độ chính xác của Bundle ID và Định danh Ứng dụng lại quan trọng

Giải phẫu một Định danh Ứng dụng

Quá trình xác minh Universal Link không đánh giá tên hiển thị của ứng dụng, lược đồ URL nội bộ hoặc tên gói. Theo tài liệu của Apple về applinks.Details, mô hình bảo mật phụ thuộc hoàn toàn vào Định danh Ứng dụng đủ điều kiện, được cấu trúc như sau:

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

Trong đó:

  • ApplicationIdentifierPrefix: Tiền tố Mã ứng dụng được gán trong cấu hình tài khoản Nhà phát triển Apple của bạn (ví dụ: 9JA723G82S). Đối với nhiều tài khoản nhà phát triển hiện đại, giá trị này khớp với Team ID gồm 10 ký tự, nhưng các kỹ sư nên xác minh tiền tố thực tế trong Cổng thông tin Nhà phát triển Apple thay vì giả định hai giá trị này có thể thay thế cho nhau.
  • CFBundleIdentifier (Bundle ID): Chuỗi đảo ngược DNS phân biệt chữ hoa chữ thường được xác định trong cài đặt bản dựng của mục tiêu (ví dụ: com.example.mobileapp).

Trong tệp JSON apple-app-site-association (AASA) được lưu trữ, chuỗi tổng hợp này xuất hiện bên trong mảng appIDs hoặc các mục từ điển appID (ví dụ: 9JA723G82S.com.example.mobileapp). Nếu có sự khác biệt về ký tự, sự khác biệt về chữ hoa chữ thường hoặc khoảng trắng thừa giữa quyền được nhúng của tệp nhị phân đã biên dịch và mục nhập AASA được lưu trữ, quá trình xác minh miền sẽ thất bại.

Lỗi không khớp Bundle ID là một trong những nguyên nhân có ưu tiên cao nhất cần kiểm tra trong quá trình phân loại tích hợp, nhưng đây không phải là lý do duy nhất khiến Universal Link có thể quay lại dạng web.

Cách Miền liên kết và AASA thiết lập mối liên kết hai chiều

Không giống như các lược đồ URL tùy chỉnh mà bất kỳ ứng dụng nào được cài đặt cũng có thể khai báo mà không cần xác minh miền, Universal Links thiết lập một mối liên kết hai chiều an toàn:

  • Khai báo Từ ứng dụng đến Miền: Ứng dụng iOS được biên dịch khai báo rằng nó yêu cầu quyền sở hữu đối với một miền web cụ thể bằng cách đưa quyền com.apple.developer.associated-domains vào chữ ký mã của nó.
  • Ủy quyền Từ miền đến Ứng dụng: Miền web xác nhận rằng họ cấp quyền định tuyến cho các ứng dụng cụ thể bằng cách lưu trữ tệp AASA JSON tại https://<domain>/.well-known/apple-app-site-association hoặc https://<domain>/apple-app-site-association.

Trong quá trình cài đặt hoặc cập nhật ứng dụng, hệ điều hành sẽ xác minh quyền Miền liên kết đã ký của ứng dụng với cấu hình AASA được truy xuất cho miền đó. Định danh Ứng dụng được sử dụng cho liên kết ứng dụng phải khớp với định danh tương ứng được khai báo trong cấu hình AASA. Sau khi định danh khớp, URL được yêu cầu cũng phải thỏa mãn các quy tắc components hoặc paths được định cấu hình.

Triệu chứng lỗi: Tại sao các định danh không khớp lại buộc phải quay lại dạng web

Khi xảy ra lỗi không khớp Định danh Ứng dụng, iOS thường không hiển thị lỗi không khớp Định danh Ứng dụng dưới dạng ngoại lệ thời gian chạy nghiêm trọng. Thay vào đó, lỗi được phản ánh qua trạng thái xác minh miền liên kết, chẩn đoán thiết bị hoặc hành vi quay lại dạng web:

  • Hệ thống xử lý: Khi liên kết miền thất bại, hệ thống không gọi ứng dụng thông qua đường dẫn Universal Link đã được xác minh. Tùy thuộc vào cách URL được mở và ngữ cảnh trình duyệt xung quanh, URL vẫn ở trạng thái hoặc quay lại dạng web thay vì được chuyển đến ứng dụng gốc.
  • Tác động đến trải nghiệm người dùng: Khi người dùng chạm vào một liên kết web khớp trong Tin nhắn, Thư hoặc Safari, hệ thống không nhận ra bản đồ ứng dụng gốc được ủy quyền và sẽ mở URL web trong trình duyệt.

Xem thêm: Bundle ID ──> Kiến trúc Universal Links

Cách CDN của Apple truy xuất và lưu đệm các tệp AASA

Quy trình bắt tay khi cài đặt và cơ chế CDN của Apple

Khi một ứng dụng chứa quyền com.apple.developer.associated-domains được cài đặt hoặc cập nhật, hệ thống sẽ thiết lập hoặc làm mới mối quan hệ miền liên kết:

  • Trình thu thập dữ liệu trung gian qua CDN: Khi hệ thống thiết lập hoặc làm mới mối quan hệ miền liên kết, nó sẽ lấy dữ liệu AASA của miền thông qua cơ sở hạ tầng miền liên kết của Apple và sử dụng dữ liệu đó để xác minh liên kết.
  • Vòng đời lưu đệm độc lập: CDN do Apple quản lý kiểm soát vòng đời làm mới và lưu đệm của riêng mình, vì vậy không nên cho rằng bản cập nhật ở nguồn sẽ hiển thị ngay lập tức thông qua CDN. Khi kiểm tra các thay đổi, hãy sử dụng chế độ thay thế phát triển được tài liệu hóa khi phù hợp và kiểm tra trạng thái liên kết thiết bị.
  • Yêu cầu máy chủ gốc: Máy chủ web gốc phải phục vụ tệp AASA qua HTTPS với chứng chỉ TLS hợp lệ, đáng tin cậy (các chứng chỉ tự ký sẽ bị từ chối), sử dụng loại MIME application/json. Việc lưu trữ AASA không được dựa vào chuyển hướng HTTP; điểm cuối AASA phải trả về tệp trực tiếp với mã HTTP 200 OK.

Tính nhất quán của định dạng AASA JSON

Các phiên bản iOS hiện đại hỗ trợ cú pháp từ điển components chi tiết đồng thời duy trì khả năng tương thích ngược với các mảng paths cũ.

Theo Ghi chú kỹ thuật TN3155 của Nhà phát triển Apple về Gỡ lỗi Universal Links, trong một mục details cho trước, các nhà phát triển nên sử dụng cấu trúc appIDs + components hiện đại hoặc cấu trúc appID + paths cũ; không kết hợp hai cấu trúc này trong cùng một mục, vì các cấu trúc hỗn hợp có thể tạo ra hành vi xác minh không mong muốn.

Các ví dụ AASA cũ thường bao gồm "apps": []. Đối với các bản triển khai nhắm mục tiêu vào các bản phát hành hệ điều hành Apple hiện đại, khóa này không bắt buộc; chỉ giữ lại khi hỗ trợ các phiên bản hệ điều hành cũ đặc biệt yêu cầu nó.

Quy trình chẩn đoán: Quy trình giải quyết từng bước

Bước 1: Kiểm tra quyền của ứng dụng đã ký bằng codesign

Để xác định xem tệp IPA đã xuất hoặc bản dựng gỡ lỗi có chứa chính xác Định danh Ứng dụng và Miền liên kết mong đợi hay không, hãy kiểm tra trực tiếp chữ ký mã của tệp nhị phân bằng tiện ích dòng lệnh codesign trên macOS. Kiểm tra đồng thời application-identifier, com.apple.developer.team-identifiercom.apple.developer.associated-domains.

Hồ sơ cung cấp hiển thị những tính năng và miền mà hồ sơ cho phép; tệp thực thi đã ký (codesign) hiển thị những gì tệp nhị phân được xuất xưởng thực sự chứa.

Bước 2: Kiểm toán Lược đồ AASA JSON được lưu trữ

Xác minh rằng máy chủ gốc lưu trữ tệp AASA hợp lệ có thể truy cập công khai mà không cần xác thực hoặc chuyển hướng. Lưu ý rằng các ví dụ AASA cũ thường bao gồm "apps": [], trong khi các cấu hình hiện đại nhắm mục tiêu đến các bản phát hành iOS đương đại sẽ bỏ qua khóa này.

Lược đồ AASA JSON tiêu chuẩn bên dưới minh họa việc định tuyến đường dẫn thích hợp bằng cấu trúc appIDscomponents hiện đại:


```json
{
  "applinks": {
    "details": [
      {
        "appIDs": [
          "9JA723G82S.com.example.mobileapp",
          "9JA723G82S.com.example.mobileapp.staging"
        ],
        "components": [
          {
            "/": "/product/*",
            "comment": "Khớp với các tuyến chi tiết sản phẩm"
          },
          {
            "/": "/invite/*",
            "?": { "ref": "?*" },
            "comment": "Khớp với liên kết giới thiệu có tham số truy vấn tùy chỉnh"
          },
          {
            "/": "/help/*",
            "exclude": true,
            "comment": "Loại trừ URL hỗ trợ khách hàng khỏi định tuyến gốc"
          }
        ]
      }
    ]
  }
}

Bước 3: Chạy các Công cụ CLI Chẩn đoán (codesign, swcutil, curl)

Trên các phiên bản macOS cung cấp chẩn đoán swcutil, hãy sử dụng công cụ này để kiểm tra hoặc xác minh dữ liệu miền liên kết. Do các tùy chọn lệnh có thể khác nhau giữa các phiên bản hệ điều hành và chuỗi công cụ, hãy xác nhận các tùy chọn có sẵn bằng swcutil --help trước khi chạy các quy trình chẩn đoán bên dưới:

# 0. Xác nhận các tùy chọn có sẵn (cú pháp có thể khác nhau tùy theo phiên bản hệ điều hành và chuỗi công cụ)
swcutil --help

# 1. Giải nén kho lưu trữ IPA đã xuất
unzip -q YourApp.ipa -d UnpackedApp

# 2. Trích xuất và kiểm tra trực tiếp các quyền đã ký từ tệp nhị phân thực thi
codesign -d --entitlements :- "UnpackedApp/Payload/YourApp.app" > signed-entitlements.plist 2>/dev/null
/usr/libexec/PlistBuddy -c "Print" signed-entitlements.plist

# 3. Kiểm tra xem dữ liệu AASA có thể được tải xuống cho miền bằng swcutil (công cụ chẩn đoán của macOS)
sudo swcutil dl -d custom.opwakeup.com

# 4. Xác thực việc khớp mẫu AASA với một URL cụ thể bằng swcutil
sudo swcutil verify -d custom.opwakeup.com -j ./apple-app-site-association -u https://custom.opwakeup.com/product/123

# 5. Truy vấn trực tiếp điểm cuối chẩn đoán CDN Miền liên kết do Apple quản lý
curl -i https://app-site-association.cdn-apple.com/a/v1/custom.opwakeup.com

Kiểm tra điểm cuối CDN Miền liên kết do Apple quản lý khi khắc phục sự cố dữ liệu AASA được phân phối ở biên. Hãy coi điểm cuối này là cơ sở hạ tầng chẩn đoán thay vì là một hợp đồng API công khai.

Bước 4: Sử dụng Chế độ Nhà phát triển Miền Liên kết để Kiểm tra AASA

Theo tài liệu của Apple về Cấu hình Miền Liên kết, Apple cung cấp một chế độ thay thế để phát triển. Chế độ developer (?mode=developer) cho phép các thiết bị phát triển đủ điều kiện bỏ qua CDN do Apple quản lý và lấy tệp AASA trực tiếp từ miền liên kết qua HTTPS.

Cấu hình bên dưới minh họa cách khai báo Chế độ Nhà phát triển trong các cấu hình quyền Xcode riêng biệt:

<?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>

Khi hệ điều hành thiết lập liên kết miền, việc định tuyến ở cấp ứng dụng sẽ xử lý các tải trọng URL đến bằng các ủy quyền vòng đời UIKit hoặc SwiftUI tiêu chuẩn:

import UIKit

// ----------------------------------------------------------------------------
// 1. Triển khai UIKit AppDelegate
// ----------------------------------------------------------------------------
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

    // Gọi lại tiếp tục Universal Link chuẩn của 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("Đang xử lý Universal Link đã xác minh: \(incomingURL.absoluteString)")
        
        // Chuyển tiếp incomingURL đến bộ định tuyến nội bộ hoặc tầng SDK để trích xuất tham số
        return handleIncomingRoute(incomingURL)
    }

    private func handleIncomingRoute(_ url: URL) -> Bool {
        // Logic định tuyến đích ở cấp ứng dụng
        // Lưu ý: Trả về true cho biết ứng dụng đã xử lý hoạt động, chứ không có nghĩa là phân tích URL thành công.
        return true
    }
}

// ----------------------------------------------------------------------------
// 2. Triển khai vòng đời 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("Universal Link khởi động lạnh: \(incomingURL.absoluteString)")
        }
    }

    func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
           let incomingURL = userActivity.webpageURL {
            print("Universal Link ở nền trước: \(incomingURL.absoluteString)")
        }
    }
}

Để bật Chế độ Nhà phát triển phía máy khách trên phần cứng vật lý:

  1. Trên iOS 16+, hãy chuyển đến Cài đặt > Quyền riêng tư & Bảo mật > Chế độ Nhà phát triển và bật công tắc này (yêu cầu khởi động lại thiết bị).
  2. Chuyển đến Cài đặt > Nhà phát triển > Phát triển Miền liên kết và bật công tắc.
  3. Cài đặt bản dựng phát triển được ký bằng hồ sơ cung cấp phát triển chứa quyền ?mode=developer.
  4. Lưu ý về sản xuất: Giữ ?mode=developer bị giới hạn ở các cấu hình phát triển và thử nghiệm nội bộ, và không đưa nó vào quyền miền liên kết phiên bản sản xuất trừ khi quá trình triển khai của bạn yêu cầu và hỗ trợ rõ ràng cấu hình đó.

Cây quyết định nguyên nhân gốc rễ

Universal Link quay lại xử lý dạng web
        │
        ├── application-identifier đã ký có khớp với appIDs của AASA không?
        │       ├── KHÔNG ──> Sửa Tiền tố App ID hoặc Bundle ID trong AASA
        │       └── CÓ
        │
        ├── Quyền miền liên kết có liệt kê chính xác miền đó không?
        │       ├── KHÔNG ──> Thêm applinks:<domain> vào quyền mục tiêu
        │       └── CÓ
        │
        ├── Lệnh sudo swcutil dl -d <domain> có thành công không?
        │       ├── KHÔNG ──> Sửa HTTPS gốc, chứng chỉ TLS hoặc chuyển hướng 301/302
        │       └── CÓ
        │
        ├── Lệnh sudo swcutil verify có khớp với đường dẫn URL mục tiêu không?
        │       ├── KHÔNG ──> Sửa cú pháp components hoặc paths trong AASA
        │       └── CÓ
        │
        └── Kiểm tra trạng thái liên kết thiết bị và các trình xử lý định tuyến ứng dụng nội bộ
Cây quyết định sơ đồ kỹ thuật để chẩn đoán các nguyên nhân gốc rễ quay lại dạng web của iOS Universal Links trên các quyền nhị phân, lược đồ AASA và lưu đệm CDN trên nền lưới màu kem ấm áp.

Ma trận chẩn đoán: Nguyên nhân gốc rễ của lỗi Universal Link

Chế độ lỗi Nguyên nhân gốc rễ cơ bản Hành vi hệ thống quan sát được Khắc phục được khuyến nghị
Lỗi chính tả Bundle ID Phân biệt chữ hoa chữ thường hoặc không khớp ký tự trong appIDs của AASA Liên kết mở trình duyệt thay vì ứng dụng gốc Sửa chuỗi trong AASA JSON và triển khai lại cho nguồn
Không khớp Tiền tố App ID Sử dụng tiền tố không chính xác thay vì Tiền tố App ID của Nhà phát triển thực tế Liên kết miền thất bại trong quá trình cài đặt Xác minh Tiền tố Định danh Ứng dụng trong Trung tâm Thành viên Apple
Không khớp Tên miền phụ Quyền trỏ đến www.example.com trong khi AASA nằm trên example.com Ứng dụng không thể nhận liên kết từ tên miền phụ Lưu trữ tệp AASA chuyên dụng trên mỗi tên miền phụ được yêu cầu hoặc định cấu hình ký tự đại diện
Chuyển hướng HTTP trên Điểm cuối Máy chủ gốc trả về chuyển hướng 301 hoặc 302 cho URL AASA Trình thu thập dữ liệu CDN của Apple từ chối tệp AASA Định cấu hình máy chủ web để trả về trực tiếp mã 200 OK
Tính không nhất quán của định dạng AASA Kết hợp appID/paths cũ với appIDs/components hiện đại Khớp đường dẫn không nhất quán hoặc một phần Chuẩn hóa theo cú pháp appIDs + components hiện đại
Không khớp mẫu URL AASA tải xuống thành công nhưng URL được yêu cầu không khớp với các mẫu Liên kết mở trong trình duyệt web Xác minh cú pháp đường dẫn và các thành phần bằng swcutil verify
Để chế độ nhà phát triển trong bản phát hành Bản dựng phân phối giữ lại chế độ thay thế phát triển Quyền không chuẩn trong bản dựng phân phối Xóa ?mode=developer trong cấu hình bản dựng Phát hành

Biểu đồ ma trận so sánh doanh nghiệp quốc tế minh họa các chế độ lỗi Universal Link trên iOS, nguyên nhân gốc rễ, hành vi hệ thống và các bước khắc phục với các huy hiệu trạng thái riêng biệt trên nền lưới màu kem ấm áp.

Triển khai Cấu hình Môi trường Kép trong Xcode

Quản lý Nhiều Cấu hình Bản dựng (Debug, Staging, Production)

Các đường ống phát triển doanh nghiệp thường quản lý các Bundle ID riêng biệt trên các môi trường xây dựng (ví dụ: com.example.app.debug, com.example.app.staging, com.example.app).

Để duy trì Universal Links hoạt động trên tất cả các cấu hình bản dựng:

  • Khai báo AASA rõ ràng: Tệp AASA được lưu trữ phải liệt kê rõ ràng Định danh Ứng dụng đầy đủ của từng môi trường trong mảng appIDs của nó:

    "appIDs": [
      "9JA723G82S.com.example.app",
      "9JA723G82S.com.example.app.staging",
      "9JA723G82S.com.example.app.debug"
    ]
    
    
  • Quyền hạn cụ thể theo mục tiêu: Sử dụng cài đặt cấu hình bản dựng Xcode để liên kết các tệp .entitlements riêng biệt cho mỗi cấu hình bản dựng, đảm bảo các miền sản xuất không bị truy vấn bởi các bản dựng gỡ lỗi nội bộ.

Quản lý Định danh Mục tiêu

Để khắc phục sự cố Universal Links, hãy sử dụng chính xác Bundle ID và Tiền tố Định danh Ứng dụng từ bản dựng đã ký thay vì dựa vào các định danh ký tự đại diện. Hãy xử lý rõ ràng từng tên máy chủ: nếu ứng dụng yêu cầu example.comwww.example.com, hãy định cấu hình các mục miền liên kết tương ứng và đảm bảo mỗi tên máy chủ phục vụ dữ liệu AASA thích hợp. Đảm bảo quyền được định cấu hình trên mục tiêu thực sự xử lý Universal Links và xác minh riêng bất kỳ mục tiêu phần mở rộng ứng dụng hoặc watchOS nào khi áp dụng.

Xác thực Hồ sơ Cung cấp được Nhúng và Tệp Nhị phân đã Ký trong CI/CD

Tự động hóa quyền hạn và xác minh Định danh Ứng dụng bên trong các tập lệnh xây dựng tích hợp liên tục trước khi tải lên các tệp nhị phân cho TestFlight:

# Tập lệnh xác thực CI tự động
security cms -D -i /path/to/embedded.mobileprovision > provision.plist

# 1. Kiểm tra các quyền của hồ sơ đối với Miền liên kết được phép
/usr/libexec/PlistBuddy -c "Print :Entitlements:com.apple.developer.associated-domains" provision.plist

# 2. Trích xuất các quyền đã ký thực tế từ tệp nhị phân thực thi đã biên dịch
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 "Đã trích xuất Định danh Ứng dụng đã ký: $SIGNED_APP_ID"

# 3. Xác thực rằng Miền liên kết đã ký khớp với miền mục tiêu
/usr/libexec/PlistBuddy -c "Print :com.apple.developer.associated-domains" signed-entitlements.plist

# 4. Xác minh rằng App ID đã ký tồn tại trong tệp AASA được lưu trữ thông qua 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'Lỗi không khớp AASA: {signed_id} không tìm thấy trong appIDs của AASA: {app_ids}')
    sys.exit(1)
print(f'Kiểm tra tính nhất quán AASA thành công: {signed_id} đã được đăng ký')
" "$SIGNED_APP_ID"

Nếu tập lệnh xác thực thoát ra bằng mã lỗi, hãy hủy bỏ đường ống xây dựng để tránh xuất xưởng các tệp nhị phân liên kết sâu không hoạt động vào môi trường sản xuất.

Quy trình công việc của nhà phát triển 4 bước quốc tế để tự động hóa việc xác minh App ID và AASA của iOS Universal Link trong các đường ống xây dựng CI/CD trên nền lưới màu kem ấm áp mềm mại.

Tiêu chí khớp Universal Link

Để đảm bảo định tuyến đáng tin cậy, các điều kiện sau phải được đáp ứng đồng thời:

Cấu hình ứng dụng đã ký:
application-identifier = <ApplicationIdentifierPrefix>.<CFBundleIdentifier>
com.apple.developer.associated-domains = applinks:<hostname>

Cấu hình AASA:
appIDs = [..., "<ApplicationIdentifierPrefix>.<CFBundleIdentifier>", ...]
components / paths = Khớp với các đường dẫn URL mục tiêu và tham số truy vấn

Tính đủ điều kiện của hệ thống:
1. Quyền Miền liên kết chứa rõ ràng tên máy chủ mục tiêu.
2. Định danh Ứng dụng đã ký khớp với một mục nhập được ủy quyền trong appIDs của AASA trên miền.
3. URL đến thỏa mãn các mẫu định tuyến AASA.
4. Trạng thái liên kết thiết bị và ngữ cảnh người dùng/trình duyệt cho phép ủy quyền ứng dụng gốc.

Ngay cả khi quyền, liên kết AASA và mẫu URL đều khớp, quá trình định tuyến được quan sát vẫn có thể phụ thuộc vào trạng thái thiết bị và ngữ cảnh của người dùng hoặc trình duyệt. Ví dụ, khi người dùng chạm vào một liên kết đa năng trong khi đang duyệt cùng một miền trong Safari, hệ điều hành có thể tôn trọng ý định của người dùng là tiếp tục ở lại Safari.

Các câu hỏi thường gặp (FAQ)

Định dạng chính xác của định danh ứng dụng trong tệp AASA là gì?
Định danh ứng dụng phải được định dạng nghiêm ngặt theo dạng `<ApplicationIdentifierPrefix>.<CFBundleIdentifier>`, trong đó `<ApplicationIdentifierPrefix>` là tiền tố Mã ứng dụng liên kết với ứng dụng trong tài khoản Nhà phát triển Apple của bạn (ví dụ: `9JA723G82S`) và `<CFBundleIdentifier>` là Bundle ID (ví dụ: `com.example.app`), tạo thành `9JA723G82S.com.example.app`. Không giả định rằng tiền tố luôn giống với Team ID; hãy xác minh giá trị từ hồ sơ cung cấp của ứng dụng.
Tại sao Universal Link của tôi hoạt động ở Chế độ Nhà phát triển nhưng lại thất bại trong môi trường sản xuất?
Chế độ Nhà phát triển (`?mode=developer`) cho phép các thiết bị phát triển đủ điều kiện bỏ qua CDN do Apple quản lý và lấy tệp AASA trực tiếp từ máy chủ web gốc của bạn qua HTTPS. Nếu Universal Links thất bại trong môi trường sản xuất, các nguyên nhân phổ biến bao gồm chứng chỉ TLS không hợp lệ trên máy chủ gốc của bạn, chuyển hướng HTTP trên điểm cuối AASA hoặc tải trọng AASA sản xuất chứa lỗi định dạng bị từ chối bởi trình thu thập dữ liệu CDN của Apple.
Tôi có thể sử dụng dấu hoa thị ký tự đại diện trong mảng appIDs của AASA không?
Để khắc phục sự cố Universal Link, hãy sử dụng Định danh Ứng dụng rõ ràng từ ứng dụng đã ký (`<Tiền tố App ID>.<Bundle ID>`) và khai báo định danh đó trong cấu hình AASA. Không sử dụng ký tự đại diện để thay thế cho định danh thực tế của ứng dụng.

Tóm tắt và Khung quyết định

Độ tin cậy định tuyến của Universal Link phụ thuộc vào việc căn chỉnh chính xác ở cấp độ ký tự trên ba nút: cấu hình App ID trên Cổng thông tin Nhà phát triển Apple, quyền hạn com.apple.developer.associated-domains trong Xcode và tệp JSON apple-app-site-association được lưu trữ. Một SDK của bên thứ ba hoặc khung định tuyến không thể sửa chữa một liên kết miền hệ điều hành bị hỏng; nó chỉ có thể xử lý URL sau khi iOS đã phân phối thành công Universal Link đến ứng dụng. Nếu Universal Links được liên kết chính xác ở cấp độ hệ điều hành nhưng việc trích xuất tham số thất bại, hãy kiểm tra tầng định tuyến ở cấp ứng dụng tách biệt với tầng liên kết miền.

Nếu ứng dụng của bạn cũng yêu cầu khôi phục tham số liên kết động và định tuyến tích hợp sau khi liên kết Universal Link thành công, OpoInstall cung cấp một tầng SDK tùy chọn cho quy trình làm việc ở cấp ứng dụng đó.

Để tìm hiểu thêm về các mẫu cấu hình miền và tích hợp liên kết sâu, hãy xem lại tài liệu liên kết sâu của OpoInstall.

Tài liệu liên quan

  • Khái niệm: Xác minh Định danh Ứng dụng, Xác thực Lược đồ AASA, Lưu đệm CDN của Apple, Trích xuất Quyền hạn

  • Công nghệ: iOS Universal Links, Quyền hạn Xcode, Cổng thông tin Nhà phát triển Apple, Thông tin xác thực web được chia sẻ

  • Tiêu chuẩn: IETF RFC 8259 (Trao đổi dữ liệu JSON), Thông số kỹ thuật TLS 1.3

  • Công cụ chẩn đoán: Công cụ CLI codesign của Apple, Công cụ swcutil của macOS, Truy vấn bộ nhớ đệm CDN do Apple quản lý

Tài liệu chính thức

Share this article