Làm cách nào để kích hoạt Universal Links bên trong WKWebView trên iOS? Universal Links vốn dĩ đã có thể tự phân giải từ các liên kết hợp lệ bên trong WKWebView. Việc triển khai WKNavigationDelegate cho phép ứng dụng chủ tùy chỉnh các chính sách điều hướng—chặn các đích đến thuộc sở hữu của ứng dụng, kiểm soát việc chuyển hướng bên ngoài thông qua decidePolicyForNavigationAction và thực thi bảo mật ở cấp độ frame.
Trong kiến trúc ứng dụng iOS, việc chặn điều hướng WKWebView cho phép ứng dụng chủ tùy chỉnh các chính sách định tuyến cho Universal Links, custom URL schemes và các đích đến trên web. Bằng cách đánh giá siêu dữ liệu yêu cầu điều hướng trong WKNavigationDelegate, ứng dụng có thể định tuyến nội bộ các đích đến thuộc sở hữu của ứng dụng, ủy quyền cho các trình xử lý hệ thống đối với các mục tiêu bên ngoài và thực thi các chính sách bảo mật cấp độ frame.
| Thuật ngữ | Định nghĩa | Thực thể liên quan | Vai trò ý định tìm kiếm |
|---|---|---|---|
| WebView | Một thành phần hiển thị dựa trên WebKit được nhúng để hiển thị nội dung web tương tác bên trong các ứng dụng iOS. | iOS SDK | Thông tin / Thương mại |
| Universal Links | Một cơ chế HTTPS tiêu chuẩn liên kết các tên miền web đã được xác minh với các giao diện ứng dụng iOS gốc. | Định tuyến Deep Link | Kỹ thuật / Thông tin |
| Custom URL Scheme | Một lược đồ URI do ứng dụng định nghĩa dùng để định tuyến các URL vào ứng dụng gốc. | Mobile Deep Linking | Thông tin |
Cách WKWebView và điều hướng Universal Link tương tác trên iOS

Vòng đời điều hướng WebKit và chính sách định tuyến thuộc sở hữu của ứng dụng
Apple triển khai Universal Links như một cơ chế định tuyến cấp hệ thống được hỗ trợ trên môi trường Safari và WKWebView. Khi người dùng nhấn vào một liên kết hợp lệ bên trong WKWebView được nhúng, nền tảng có thể phân giải các liên kết tên miền và điều hướng thực thi theo chính sách của hệ điều hành.
Trong khi các Universal Links được hệ thống công nhận có thể chuyển giao việc thực thi cho các trình xử lý gốc, các môi trường trình duyệt nhúng thường yêu cầu logic định tuyến cụ thể theo ứng dụng. Ví dụ, khi một liên kết nhắm đến tên miền của chính ứng dụng chủ, các nhà phát triển thường ưu tiên điều hướng trực tiếp thông qua các view controller gốc thay vì kích hoạt việc khởi chạy lại toàn bộ ứng dụng bên ngoài. Việc triển khai WKNavigationDelegate cung cấp cho ứng dụng chủ khả năng kiểm soát chi tiết việc đánh giá liên kết, cho phép các đội ngũ thực thi các danh sách cho phép (allowlist) tùy chỉnh và định tuyến các đích đến nội bộ một cách nhất quán.
Rào cản trải nghiệm người dùng: Khi trình duyệt web trong ứng dụng khiến người dùng bị kẹt trong các vòng lặp chuyển hướng web
Các WebView nhúng thường được triển khai để lưu trữ các trang microsite quảng cáo, trung tâm trợ giúp, danh mục đối tác và các trang đích tiếp thị trong ứng dụng iOS. Khi một trang web trong ứng dụng bao gồm các liên kết nhằm điều hướng người dùng đến các phần khác của ứng dụng chủ (ví dụ: nút "Xem trong ứng dụng") hoặc đến các ứng dụng đối tác, điều hướng mặc định có thể dẫn đến việc hiển thị dư thừa:
- Hiển thị web dư thừa: Thay vì hiển thị các view controller gốc, người dùng có thể được chuyển hướng đến các phiên bản web phản hồi của các trang trong ứng dụng, yêu cầu xác thực lặp lại và làm giảm tính nhất quán về mặt hình ảnh.
- Bẫy web: Người dùng có thể bị mắc kẹt trong các ngăn xếp điều hướng web sâu mà không có cách trực quan để quay lại giao diện ứng dụng gốc chính.
- Chuyển đổi Ứng dụng sang Ứng dụng thất bại: Việc nhấn vào các liên kết trỏ đến các dịch vụ bên thứ ba (như ứng dụng điều hướng, hộp thoại chia sẻ mạng xã hội hoặc cổng thanh toán) yêu cầu sự ủy quyền rõ ràng nếu các dịch vụ đó dựa trên custom URL schemes.
So sánh WKWebView với SFSafariViewController cho các chuyển giao từ Web sang Ứng dụng
Khi thiết kế trình duyệt web trong ứng dụng trên iOS, các đội kỹ thuật phải chọn giữa WKWebView và SFSafariViewController:
SFSafariViewController: Cung cấp giao diện duyệt web Safari khép kín, được hệ thống quản lý với các tính năng như Tự động điền (AutoFill) và chặn nội dung. Ứng dụng chủ không thể kiểm tra hoạt động duyệt web hoặc dữ liệu trang web, và khả năng tùy chỉnh giao diện người dùng chỉ giới hạn ở màu sắc.WKWebView: Một thành phần view được nhúng nằm trong quy trình UI của ứng dụng trong khi chạy nội dung web trong các quy trình WebKit riêng biệt. Nó cho phép tùy chỉnh giao diện sâu, cầu nối JavaScript và tích hợp bố cục tùy chỉnh, yêu cầu triển khai rõ ràngWKNavigationDelegateđể tùy chỉnh các chính sách định tuyến và xử lý các lược đồ tùy chỉnh do ứng dụng định nghĩa.
Cách decidePolicyForNavigationAction chặn điều hướng WebKit
Quy trình chính sách điều hướng: Hiểu về WKNavigationAction, request và decisionHandler
Để kiểm soát luồng điều hướng bên trong WKWebView, các nhà phát triển gán một delegate tùy chỉnh tuân thủ Hướng dẫn dành cho nhà phát triển của Apple về WKNavigationDelegate. Điểm chặn chính là phương thức delegate:
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
)
Các hành động điều hướng được kích hoạt bởi tương tác người dùng, chuyển hướng lập trình hoặc gửi biểu mẫu sẽ đi qua phương thức này. Đối tượng WKNavigationAction cung cấp siêu dữ liệu quan trọng:
navigationAction.request.url:URLmục tiêu đang được yêu cầu.navigationAction.navigationType: Loại trình kích hoạt (.linkActivated,.other,.formSubmitted).navigationAction.sourceFrame: Thông tin về frame bắt đầu yêu cầu điều hướng.navigationAction.targetFrame: Thông tin về frame đích nơi nội dung dự kiến sẽ tải.
decisionHandler là một closure hoàn thành thông báo cho WebKit liệu có cho phép hay hủy bỏ điều hướng được yêu cầu hay không.
Khi nào nên trả về .allow so với .cancel: Kiểm soát vòng đời tải tài nguyên WebKit
WKNavigationActionPolicy được truyền đến decisionHandler kiểm soát việc WebKit có tiếp tục điều hướng hay không:
.allow: Thông báo cho WebKit tiếp tục điều hướng được yêu cầu bên trong web view..cancel: Hướng dẫn WebKit hủy điều hướng được yêu cầu. Chính sách này được thực thi bất cứ khi nào ứng dụng chủ chặn một custom scheme, định tuyến nội bộ một Universal Link thuộc sở hữu của ứng dụng hoặc ủy quyền mục tiêu bên ngoài choUIApplication.shared.open().
decisionHandler phải được gọi chính xác một lần cho mỗi hành động điều hướng để đảm bảo việc phân giải chính sách điều hướng diễn ra mà không bị đình trệ.
Đánh giá các loại điều hướng: Phân biệt các lượt nhấp của người dùng (.linkActivated) với các chuyển hướng tự động
WKNavigationAction.navigationType cho phép các nhà phát triển phân biệt tương tác rõ ràng của người dùng với các tập lệnh tự động:
.linkActivated: Người dùng đã thực sự nhấn vào một thẻ neo HTML (<a href="...">)..other: Đại diện cho các điều hướng theo lập trình, chẳng hạn như cập nhậtwindow.location.href, meta refresh hoặc các lệnhwebView.load()ban đầu..formSubmitted/.formResubmitted: Đại diện cho các gửi POST hoặc GET của biểu mẫu.
Việc đánh giá navigationType cho phép các ứng dụng thực thi chính sách liên kết rõ ràng ở cấp ứng dụng. Đối với các yêu cầu custom scheme bên ngoài hoặc chuyển giao ứng dụng bên thứ ba, việc yêu cầu .linkActivated như một cổng chính sách giúp ngăn chặn các tập lệnh nền không được nhắc nhở kích hoạt các lệnh khởi chạy ứng dụng bên ngoài tự động.
Xử lý các chính sách quyết định bất đồng bộ mà không có chu kỳ giữ (retain cycles)
Khi việc xác thực tuyến đường hoặc kiểm tra quyền yêu cầu truy vấn bộ nhớ đệm cục bộ hoặc trình xác thực bảo mật trước khi đưa ra quyết định:
- Đảm bảo
decisionHandlerđược thực thi trên tất cả các đường dẫn thực thi, bao gồm các điều kiện lỗi và guard. - Sử dụng các tham chiếu yếu (
[weak self]) trong các closure thoát (escaping closures) để ngăn chặn chu kỳ giữ giữaWKWebView, delegate của nó vàUIViewControllercha.
Phân biệt tên miền liên kết của ứng dụng chủ với Universal Links bên ngoài

Quản lý đích đến thuộc sở hữu ứng dụng so với ủy quyền liên kết cấp hệ thống
Đối với các tuyến đường thuộc sở hữu ứng dụng, hãy tránh cố gắng nhập lại cùng một ứng dụng thông qua tra cứu Universal Link dư thừa. Xử lý các đích đến thuộc sở hữu ứng dụng trực tiếp thông qua bộ định tuyến nội bộ của ứng dụng chủ và sử dụng mở hệ thống chủ yếu cho các đích đến cần rời khỏi ứng dụng hiện tại hoặc được phân giải bởi các dịch vụ bên ngoài.
Sự tách biệt kiến trúc này đảm bảo điều hướng mượt mà:
- Tên miền liên kết ứng dụng chủ: Nếu host của URL khớp với tên miền liên kết của chính ứng dụng chủ (
app.example.com), hãy hủy điều hướng web view (decisionHandler(.cancel)), xác thực đường dẫn tuyến đường và truyền các tham số đã phân tích trực tiếp đến bộ định tuyến điều hướng nội bộ của ứng dụng. - Ứng dụng bên ngoài: Nếu URL trỏ đến đích đến của đối tác bên ngoài hoặc một custom scheme được phép, hãy áp dụng cổng liên kết rõ ràng ở cấp ứng dụng (
navigationType == .linkActivated), hủy điều hướng web view và chuyển tiếp yêu cầu đếnUIApplication.shared.open(url)để cho phép hệ điều hành khởi chạy ứng dụng bên ngoài.
Thiết kế xác thực tuyến đường nội bộ: Trích xuất đường dẫn và tham số truy vấn qua AppRouteValidator
Khi một URL đến khớp với tên miền liên kết của ứng dụng chủ, chuỗi URL phải đi qua một trình xác thực định tuyến nghiêm ngặt trước khi kích hoạt chuyển đổi view controller.
Mô hình AppRouteValidator:
- Xác thực đường dẫn URL dựa trên danh sách cho phép của các tuyến đường nội bộ được hỗ trợ (ví dụ:
/open/,/product/,/promo/,/checkout/). - Trích xuất các tham số truy vấn (ví dụ:
id,promo,utm_source). - Thực thi các hạn chế bộ ký tự, giới hạn độ dài và từ chối khóa trùng lặp, trả về cấu trúc dữ liệu
ValidatedAppRoutesạch.
Xử lý các Universal Links bên thứ ba bên ngoài thông qua ủy quyền UIApplication hệ thống

Khi một trang web bên trong WKWebView liên kết đến các dịch vụ bên ngoài (như ứng dụng đối tác, nền tảng xã hội hoặc tiện ích bên ngoài), ứng dụng chủ có thể ủy quyền định tuyến cho hệ thống iOS:
let options: [UIApplication.OpenExternalURLOptionsKey: Any] = [
.universalLinksOnly: true
]
UIApplication.shared.open(url, options: options) { success in
if !success {
// Dự phòng chính sách ứng dụng: tải đích đến web nếu không có ứng dụng gốc nào xử lý Universal Link
}
}
Sử dụng .universalLinksOnly như một chính sách ứng dụng đảm bảo rằng người dùng chỉ được chuyển ra ngoài ứng dụng hiện tại nếu một ứng dụng gốc đã được xác minh được cài đặt để xử lý Universal Link.
Quản lý dự phòng Custom URL Scheme (myapp://) song song với HTTPS Universal Links
Trong khi HTTPS Universal Links đại diện cho deep linking tiêu chuẩn trên iOS, các lược đồ tùy chỉnh do ứng dụng định nghĩa (myapp:// hoặc partnerapp://) vẫn phổ biến trong các chiến dịch quảng cáo và tích hợp đối tác.
Trong một triển khai WKNavigationDelegate thống nhất:
- Các lược đồ không phải HTTP/HTTPS được kiểm tra trước. Nếu lược đồ khớp với một giao thức tùy chỉnh được phép và đáp ứng chính sách liên kết rõ ràng (
navigationType == .linkActivated), delegate sẽ xác minh host, đường dẫn và các tham số trước khi gửi đếnUIApplication.shared.open(). - Các lược đồ không được nhận dạng hoặc các lệnh gọi lược đồ nền không được nhắc nhở sẽ bị hủy ngay lập tức, ngăn chặn lỗi điều hướng không được xử lý hoặc việc flood intent do tập lệnh điều khiển.
[Người dùng tương tác với liên kết bên trong iOS WKWebView]
│
▼
[WKNavigationDelegate: decidePolicyForNavigationAction]
│
┌─────────────┴─────────────┐
▼ ▼
[!action.sourceFrame.isMainFrame] [action.sourceFrame.isMainFrame]
│ │
▼ ▼
[Cổng bảo mật subframe] [Kiểm tra lược đồ & Host đích]
├─ HTTP(S) -> .allow │
└─ Non-Web -> .cancel ┌───────────┼───────────┐
(Chặn Subframe) ▼ ▼ ▼
[Host Tên miền] [Web bên ngoài] [Lược đồ tùy chỉnh]
│ │ │
▼ ▼ ▼
[AppRoute] [Kiểm tra Link] [Kiểm tra Link]
├─ Hợp lệ -> ├─ Đối tác-> ├─ Hợp lệ & Nhấp->
│ Nội bộ │ Mở App │ Mở App
└─ Không -> └─ Web -> └─ Không/Tự động->
.cancel .allow .cancel
Cách thực thi bảo mật Main Frame và ngăn chặn Iframe Hijacking

Xử lý điều hướng web nhúng như đầu vào không tin cậy: Tiêu chuẩn bảo mật Deep Link OWASP
Theo Hướng dẫn kiểm tra bảo mật ứng dụng di động OWASP về Deep Link không an toàn, tất cả các URL và tải trọng tham số được xử lý bởi các trình xử lý điều hướng di động phải được coi là đầu vào không tin cậy, bên ngoài.
Các trang web được hiển thị trong WKWebView có thể tải các tập lệnh của bên thứ ba, biểu ngữ quảng cáo hoặc nội dung do người dùng tạo. Nếu một delegate điều hướng chuyển tiếp các URL tùy ý đến các view controller gốc hoặc UIApplication.shared.open() mà không có xác thực, các tham số không mong đợi có thể nhắm mục tiêu vào các tuyến đường ứng dụng nội bộ nhạy cảm.
Cách ly điều hướng Main Frame khỏi Iframes nhúng và mục tiêu cửa sổ mới
Theo Tài liệu dành cho nhà phát triển của Apple về WKNavigationAction, việc đánh giá bảo mật frame yêu cầu kiểm tra frame bắt đầu:
sourceFrame.isMainFrame == true: Điều hướng được bắt đầu trực tiếp bởi frame tài liệu chính, cấp cao nhất.sourceFrame.isMainFrame == false: Điều hướng được bắt đầu bởi một subframe hoặc iframe được nhúng.targetFrame == nil: Điều hướng yêu cầu một mục tiêu cửa sổ mới (chẳng hạn như một neo vớitarget="_blank").
Để ngăn chặn iframe hijacking—nơi một iframe được nhúng cố gắng khởi chạy các ứng dụng bên ngoài hoặc kích hoạt các chuyển đổi view gốc ở chế độ nền—delegate phải đánh giá sourceFrame.isMainFrame. Nếu frame bắt đầu là một iframe (sourceFrame.isMainFrame == false), hãy cho phép điều hướng subframe HTTP/HTTPS tiêu chuẩn (.allow), nhưng chặn bất kỳ custom schemes nào không phải web hoặc các chuyển giao định tuyến gốc (.cancel).
Ngăn chặn lệnh gọi giao thức subframe độc hại và flood lược đồ nền
Việc thực thi kiểm tra frame bắt đầu ngăn chặn các subframe kích hoạt các lệnh gọi lược đồ bên ngoài không được nhắc nhở:
if !navigationAction.sourceFrame.isMainFrame {
let scheme = url.scheme?.lowercased() ?? ""
if scheme == "http" || scheme == "https" {
decisionHandler(.allow) // Cho phép điều hướng subframe HTTP(S) tiêu chuẩn
} else {
decisionHandler(.cancel) // Chặn các lược đồ không phải web từ subframes
}
return
}
Thực thi các danh sách cho phép đường dẫn và tham số truy vấn nghiêm ngặt trong định tuyến Client
Cả URL tên miền liên kết nội bộ và custom schemes bên ngoài đều phải đi qua các mô hình xác thực nghiêm ngặt trước khi thực thi:
- Cho phép tiền tố đường dẫn: Thực thi các tiền tố tuyến đường đã được phê duyệt (ví dụ:
/open/,/product/,/promo/,/checkout/), từ chối các đường dẫn tùy ý hoặc sai định dạng. - Lọc khóa truy vấn: Loại bỏ các khóa truy vấn không mong đợi và từ chối các khóa tham số trùng lặp để ngăn chặn ô nhiễm tham số.
- Ràng buộc kiểu dữ liệu & độ dài: Giới hạn các giá trị tham số vào bộ ký tự chữ và số và thực thi giới hạn độ dài tối đa (
ký tự).
Triển khai WKNavigationDelegate trong môi trường Production với Swift
Cấu trúc CustomWebViewController và kiến trúc Delegate trong Swift
Một controller WKWebView trong môi trường production điều phối cấu hình web, đánh giá chính sách điều hướng, định tuyến nội bộ và ủy quyền bên ngoài. Triển khai gói gọn các quy tắc xác thực trong các lớp trình xác thực chuyên dụng (AppRouteValidator và CustomSchemeValidator) để giữ cho các callback delegate sạch sẽ, có thể kiểm thử và an toàn.
Triển khai các mô hình AppRouteValidator và CustomSchemeValidator
Các mô hình trình xác thực thực thi bảo mật fail-closed nghiêm ngặt:
AppRouteValidatorxác thực các tên miền liên kết nội bộ, kiểm tra tiền tố đường dẫn và làm sạch các tham số truy vấn thành một đối tượngValidatedAppRoutecó cấu trúc.CustomSchemeValidatorxác minh các lược đồ tùy chỉnh được ủy quyền (myapp), xác thực các host được phép (open,product,event) và làm sạch các giá trị truy vấn.
OpoInstall có thể được tích hợp cùng với một lớp định tuyến thuộc sở hữu ứng dụng để phục hồi tham số và quy cho các lượt cài đặt. Xem tài liệu tích hợp SDK để có hướng dẫn tích hợp toàn diện.
Triển khai kỹ thuật dưới đây minh họa cách cấu hình WKNavigationDelegate an toàn trong Swift:
// iOS: CustomWebViewController với định tuyến WKNavigationDelegate nghiêm ngặt và bảo mật Frame
// Ví dụ tích hợp tham khảo. Xác minh chữ ký phương thức và ánh xạ tên miền so với kiến trúc đã triển khai của bạn.
import UIKit
import WebKit
struct ValidatedAppRoute {
let path: String
let queryParams: [String: String]
}
// 1. Trình xác thực cho tên miền liên kết của ứng dụng chủ (Tuyến đường nội bộ)
class AppRouteValidator {
private static let allowedPrefixes = ["/open/", "/product/", "/promo/", "/checkout/"]
private static let allowedQueryKeys = Set(["target", "id", "promo", "utm_source"])
static func validate(url: URL) -> ValidatedAppRoute? {
let path = url.path
// Thực thi danh sách cho phép tiền tố đường dẫn đã phê duyệt
guard allowedPrefixes.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 {
// Xác thực fail-closed: từ chối URL nếu có khóa truy vấn không được ủy quyền hoặc khóa trùng lặp
guard allowedQueryKeys.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)
}
}
// 2. Trình xác thực cho Custom Schemes bên ngoài (myapp://)
class CustomSchemeValidator {
private static let allowedSchemes = Set(["myapp"])
private static let allowedHosts = Set(["open", "product", "event"])
private static let allowedPathPrefixes = ["/detail/", "/view/", "/main/"]
private static let allowedQueryKeys = Set(["target", "id", "promo", "utm_source"])
static func validate(url: URL) -> URL? {
guard let scheme = url.scheme?.lowercased(), allowedSchemes.contains(scheme) else {
return nil
}
guard let host = url.host?.lowercased(), allowedHosts.contains(host) else {
return nil
}
let path = url.path
if !path.isEmpty && !allowedPathPrefixes.contains(where: { path.hasPrefix($0) }) {
return nil
}
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 {
guard allowedQueryKeys.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 {
return nil
}
}
}
return url
}
}
// 3. UIViewController lưu trữ WKWebView với chặn chính sách điều hướng an toàn
class CustomWebViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
private let hostAssociatedDomain = "app.example.com"
private let allowedExternalPartnerHosts = Set(["partner.example.com"])
override func viewDidLoad() {
super.viewDidLoad()
let configuration = WKWebViewConfiguration()
webView = WKWebView(frame: view.bounds, configuration: configuration)
webView.navigationDelegate = self
view.addSubview(webView)
}
func webView(
_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
// Kiểm tra bảo mật 1: Thực thi ranh giới frame bắt đầu (sourceFrame) để ngăn chặn iframe hijacking
if !navigationAction.sourceFrame.isMainFrame {
let scheme = url.scheme?.lowercased() ?? ""
if scheme == "http" || scheme == "https" {
decisionHandler(.allow) // Cho phép điều hướng subframe HTTP(S) tiêu chuẩn
} else {
decisionHandler(.cancel) // Chặn lược đồ không phải web từ subframes/iframes
}
return
}
let scheme = url.scheme?.lowercased() ?? ""
let isExplicitLinkActivation = (navigationAction.navigationType == .linkActivated)
// Kiểm tra bảo mật 2: Xử lý Tên miền liên kết của ứng dụng chủ
// Định tuyến nội bộ thay vì gọi UIApplication.shared.open
if scheme == "https", let host = url.host?.lowercased(), host == hostAssociatedDomain {
if let validatedRoute = AppRouteValidator.validate(url: url) {
AppInternalRouter.shared.navigate(to: validatedRoute)
}
decisionHandler(.cancel) // Hủy tải trong webview để định tuyến nội bộ
return
}
// Kiểm tra bảo mật 3: Xử lý Custom Schemes được phép (myapp://) với Chính sách kích hoạt liên kết
if scheme != "http" && scheme != "https" && scheme != "about" {
// Thực thi rằng các lượt khởi chạy ứng dụng bên ngoài qua lược đồ tùy chỉnh yêu cầu kích hoạt liên kết rõ ràng từ người dùng
if isExplicitLinkActivation, let validatedURL = CustomSchemeValidator.validate(url: url) {
UIApplication.shared.open(validatedURL, options: [:], completionHandler: nil)
}
decisionHandler(.cancel) // Hủy tải trong webview để ngăn chặn lỗi lược đồ không được xử lý
return
}
// Kiểm tra bảo mật 4: Xử lý đích đến bên ngoài và các yêu cầu cửa sổ mới (target="_blank")
if scheme == "http" || scheme == "https" {
let host = url.host?.lowercased() ?? ""
// Ủy quyền Universal Links của đối tác đã xác minh cho ứng dụng bên ngoài với chính sách kích hoạt liên kết rõ ràng
if allowedExternalPartnerHosts.contains(host) && isExplicitLinkActivation {
let options: [UIApplication.OpenExternalURLOptionsKey: Any] = [
.universalLinksOnly: true
]
UIApplication.shared.open(url, options: options) { [weak self] success in
if !success {
// Dự phòng chính sách ứng dụng: tải đích đến đối tác bên ngoài bên trong web view nếu không có ứng dụng gốc nào xử lý nó
guard let self = self else { return }
self.webView.load(navigationAction.request)
}
}
decisionHandler(.cancel)
return
}
// Nếu targetFrame là nil (yêu cầu cửa sổ mới), tải an toàn vào webView hiện tại
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
decisionHandler(.cancel)
return
}
// Nội dung web tiêu chuẩn tiếp tục tải bên trong WKWebView
decisionHandler(.allow)
return
}
decisionHandler(.allow)
}
}
// Trình giữ chỗ bộ định tuyến nội bộ của ứng dụng (không phải API SDK OpoInstall)
class AppInternalRouter {
static let shared = AppInternalRouter()
func navigate(to route: ValidatedAppRoute) {
// Thực thi chuyển đổi UI view controller nội bộ dựa trên đường dẫn và tham số truy vấn
}
}
Thực thi an toàn luồng: Đảm bảo chuyển đổi giao diện người dùng thực thi trên Main Actor
Trong các mô hình đồng thời Swift hiện tại, các callback WKNavigationDelegate được cách ly bởi main-actor. Việc định tuyến ứng dụng và chuyển đổi view controller thực thi trên main actor, duy trì tính an toàn luồng trên các quy trình điều hướng gốc.
Lỗi điều hướng Deep Link WKWebView và ma trận chẩn đoán
Hướng dẫn khắc phục sự cố Deep Linking WKWebView trên iOS toàn diện
Ma trận dưới đây phác thảo các chế độ lỗi phổ biến gặp phải khi quản lý deep link và custom schemes bên trong WKWebView trên iOS, cùng với các nguyên nhân gốc rễ chính và các phương án khắc phục kỹ thuật được khuyến nghị:
| Dấu hiệu lỗi / Triệu chứng | Nguyên nhân gốc rễ chính | Các phiên bản iOS áp dụng | Điểm kiểm tra chẩn đoán | Khắc phục được khuyến nghị |
|---|---|---|---|---|
| Universal Link tải trong Web | Tên miền thuộc sở hữu ứng dụng chưa được chặn | iOS 9+ | decidePolicyForNavigationAction chưa được xử lý |
Chặn tên miền host, phân tích đường dẫn, định tuyến nội bộ, .cancel |
| Liên kết tên miền tự thân không định tuyến được | Gọi UIApplication.open trên chính tên miền của mình |
iOS 9+ | UIApplication.shared.open được gọi trên host của chính mình |
Tránh tự mở bên ngoài; định tuyến trực tiếp đến bộ định tuyến nội bộ |
| Lược đồ tùy chỉnh thất bại âm thầm | Giao thức không phải HTTP không được WebKit nhận dạng | iOS 9+ | Lược đồ không được ủy quyền cho UIApplication |
Chặn lược đồ trong delegate, xác thực danh sách cho phép, mở qua UIApplication |
| Iframe Hijacking giao thức | Subframe kích hoạt lược đồ tùy chỉnh bên ngoài | iOS 9+ | sourceFrame.isMainFrame chưa được kiểm tra |
Dùng if !sourceFrame.isMainFrame và chặn các lược đồ không phải web |
| Vấn đề cảnh báo chuyển giao UI hoặc chuyển đổi | Chuyển đổi UI thực thi ngoài luồng chính | iOS 9+ | Thiếu dispatch main-actor | Đảm bảo thực thi main-actor cho bộ định tuyến nội bộ và chuyển đổi view controller |
Các câu hỏi thường gặp (FAQ)
Các nhà phát triển có thể chặn Universal Links trong WKWebView như thế nào?
Tôi có thể sử dụng UIApplication.shared.open để khởi chạy ứng dụng của riêng mình từ WKWebView không?
Làm thế nào để ngăn chặn các iframes được nhúng trong WKWebView kích hoạt các lượt khởi chạy ứng dụng bên ngoài?
Tóm tắt và Khung quyết định
Việc xử lý Universal Links và custom schemes bên trong WKWebView trên iOS đòi hỏi phải bắc cầu qua ranh giới giữa bộ chứa hiển thị web của WebKit và vòng đời điều hướng UIKit gốc. Việc dựa vào các chính sách điều hướng mặc định có thể ngăn cản các chuyển giao mượt mà khi cần logic định tuyến thuộc sở hữu ứng dụng.
Bằng cách triển khai WKNavigationDelegate mạnh mẽ, xác minh ranh giới frame, thực thi chính sách kích hoạt liên kết thận trọng đối với các chuyển giao bên ngoài, phân tích các tên miền liên kết nội bộ thông qua các trình xác thực tuyến đường nghiêm ngặt và ủy quyền các mục tiêu bên ngoài một cách an toàn cho UIApplication.shared.open, các đội ngũ kỹ thuật duy trì được sự điều hướng có kiểm soát trong khi tự bảo vệ trước việc chiếm đoạt giao thức iframe.
Để khám phá các kiến trúc định tuyến tham số và deep linking gốc trên iOS, hãy tham khảo tài liệu tích hợp SDK.
Tài liệu liên quan
-
Khái niệm: Định tuyến WebView iOS, Chặn Universal Links, WKNavigationDelegate, Cách ly ranh giới Frame
-
Công nghệ: Apple WebKit, iOS UIKit, WKWebView, OpoInstall iOS SDK
-
Tiêu chuẩn: IETF RFC 3986 Uniform Resource Identifier, Thông số tên miền liên kết Apple, Hướng dẫn kiểm tra bảo mật ứng dụng di động OWASP (MASTG)
-
API:
WKNavigationDelegate.decidePolicyForNavigationAction,WKNavigationAction.sourceFrame,UIApplication.shared.open -
Tài liệu & Tham chiếu chính thức:
Share this article



