Một thông báo dẫn người dùng tới chi tiết đơn hàng. Link mở được ứng dụng là bước đầu, nhưng bạn vẫn cần biết URL có đúng route được hỗ trợ, người dùng đã đăng nhập chưa và tài khoản đó có quyền xem đơn hay không.
Bài viết trình bày luồng thiết kế cho Android App Links và iOS Universal Links, đối chiếu tài liệu chính thức ngày 22/10/2026. Ví dụ parser dùng TypeScript và URL chuẩn; tích hợp nhận sự kiện link trong framework mobile cụ thể là một lớp riêng.
Tách ba câu hỏi
- Hệ điều hành có liên kết domain này với ứng dụng đúng không?
- Ứng dụng có hiểu và chấp nhận URL này không?
- Backend có cho tài khoản hiện tại đọc dữ liệu đích không?
Android dùng Digital Asset Links tại /.well-known/assetlinks.json cho quy trình xác minh liên kết. Trên iOS, associated domains kết hợp cấu hình trong app với tệp apple-app-site-association trên website. Các cơ chế này xác lập quan hệ app–website; chúng không biến một ID trong URL thành quyền truy cập nghiệp vụ.
Nếu người dùng sửa mã đơn trong link, backend vẫn phải kiểm tra quyền như khi dữ liệu được mở từ danh sách trong app. Không nên dựa vào việc “link chỉ được gửi từ hệ thống” vì URL có thể được lưu, chia sẻ hoặc chỉnh sửa.
Chuẩn hóa URL thành một route có kiểu rõ ràng
Giả sử sản phẩm chỉ hỗ trợ link HTTPS dạng https://app.example.com/orders/ord_123. Parser nên trả về một kiểu route nhỏ, không chuyển nguyên object URL xuống mọi màn hình.
type DeepLinkRoute = { screen: 'Order'; orderId: string };
export function resolveDeepLink(raw: string): DeepLinkRoute | null {
let url: URL;
try {
url = new URL(raw);
} catch {
return null;
}
if (url.origin !== 'https://app.example.com') return null;
if (url.username || url.password) return null;
const match = /^\/orders\/([A-Za-z0-9_-]{1,64})\/?$/.exec(url.pathname);
if (!match) return null;
return { screen: 'Order', orderId: match[1] };
}
Domain trên là placeholder cho ví dụ, phải thay bằng domain được cấu hình thật của sản phẩm. Kiểm tra origin chính xác tránh nhận nhầm một host như app.example.com.other.test. Quy tắc ID chỉ là hợp đồng của route minh họa, không phải định dạng phù hợp cho mọi database.
Ví dụ không dùng các query parameter để chọn màn hình khác, đổi quyền hay thực hiện redirect. Nếu sản phẩm cần query parameter, khai báo cụ thể từng trường và giá trị hợp lệ. Không lấy một trường next tùy ý rồi chuyển cho trình duyệt hoặc navigator mà chưa kiểm tra đích đến.
Trong môi trường có nhiều framework hoặc bộ URL polyfill, chạy cùng bộ fixture trên runtime thật. Một parser qua được trong Node không tự chứng minh mọi hành vi tích hợp Android/iOS đều đúng.
Đưa người dùng qua bước đăng nhập mà không mất ý định
Khi nhận route hợp lệ nhưng chưa có phiên, lưu route đã chuẩn hóa như {screen, orderId} trong trạng thái ngắn hạn rồi mở màn hình đăng nhập. Sau khi đăng nhập thành công, lấy lại đúng route đó và yêu cầu backend tải dữ liệu theo tài khoản vừa xác thực.
Không lưu access token vào URL để “tiện chuyển màn hình”. Cũng cần xử lý người dùng hủy đăng nhập, đổi tài khoản hoặc đăng xuất giữa luồng. Một pending route cũ không nên tự mở dữ liệu theo phiên tiếp theo mà sản phẩm chưa có quyết định rõ ràng.
Nếu nhận hai link liên tiếp, xác định cách thay thế hoặc xếp hàng thay vì để hai callback cùng điều hướng. Khi app vừa khởi động, có thể phải đợi cây navigation sẵn sàng. Khi app đang mở, link lại đi vào một nhánh vòng đời khác; cả hai đều nên dùng chung parser và quy tắc phân quyền.
Kiểm tra liên kết nền tảng độc lập với route
Với thiết bị Android 12 trở lên, tài liệu có quy trình xác minh thủ công. Thay package ví dụ bằng package đã cài trên thiết bị kiểm tra:
adb shell pm verify-app-links --re-verify com.example.app
adb shell pm get-app-links com.example.app
adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d 'https://app.example.com/orders/ord_123'
Không kết luận thất bại ngay khi lệnh xác minh vừa trả về; quá trình xác minh có thể chưa hoàn tất. Đối chiếu fingerprint ký của đúng bản build với file liên kết. Debug build, bản phát hành và bản do store ký có thể dùng thông tin ký khác nhau.
Với iOS, kiểm tra entitlement và tệp associated domains cho đúng host/subdomain. Apple yêu cầu tệp được phục vụ bằng HTTPS hợp lệ, không qua redirect; cơ chế CDN/cache cũng có thể làm việc thay đổi file không hiện ra ngay trên thiết bị. Không dùng việc dán link thành công trong một tình huống để thay cho toàn bộ quy trình kiểm chứng.
Bộ tình huống nên có trước khi release
- Link hợp lệ khi app đóng và khi app đang mở.
- Link hợp lệ khi chưa đăng nhập, hủy đăng nhập và đổi tài khoản.
- Sai host, sai scheme, ID quá dài và path không hỗ trợ.
- Đơn không tồn tại hoặc thuộc tài khoản khác.
- Link lặp lại liên tiếp và link đến khi navigator chưa sẵn sàng.
- Trang web dự phòng khi thiết bị không mở app.
Với trường hợp không có quyền hoặc không tồn tại, chọn thông báo theo chính sách sản phẩm, tránh vô tình xác nhận tài nguyên riêng tư có thật. Log phục vụ debug chỉ cần mã tình huống và route đã làm sạch; không nên ghi token hoặc toàn bộ URL nhạy cảm.
Kết luận
Hãy xử lý deep link như một đầu vào cần chuẩn hóa và xác minh, rồi đưa nó qua luồng đăng nhập và quyền đọc vốn có. Domain đã xác minh giúp hệ điều hành chọn app; backend vẫn là nơi quyết định tài khoản được phép xem gì.




