Universal Links บน iOS และ App Links บน Android ต่างต้องการไฟล์ JSON ที่เสิร์ฟผ่าน HTTPS ที่รากของโดเมนคุณ iOS ต้องการ /.well-known/apple-app-site-association Android ต้องการ /.well-known/assetlinks.json localhost เสิร์ฟทั้งคู่ผ่าน hostname ที่ OS จะเชื่อมโยงกับแอปของคุณไม่ได้ ดังนั้นเราจึง tunnel
ข้อกำหนดจริงในแต่ละแพลตฟอร์ม
iOS Universal Links
OS ดึง https://your-domain.com/.well-known/apple-app-site-association (หรือ /apple-app-site-association) เมื่อติดตั้งแอป ตรวจเนื้อหากับ entitlement associated domains ของแอป การดึงต้องสำเร็จผ่าน HTTPS จริง iOS ไม่เชื่อใบรับรอง self-signed สำหรับงานนี้และไม่เชื่อ localhost
Android App Links
Android ตรวจสอบ App Links โดยดึง https://your-domain.com/.well-known/assetlinks.json ไฟล์ต้องระบุ fingerprint SHA-256 ของแอป การตรวจสอบเกิดตอนติดตั้งและการเปิดครั้งแรก ข้อจำกัดเดียวกัน: HTTPS จริง โดเมนจริง
ทำไม localhost ทำตรง ๆ ไม่ได้
แม้ mkcert ให้ HTTPS ที่เชื่อถือในเบราว์เซอร์แล็ปท็อปของคุณ OS มือถือก็ไม่เชื่อ CA ในเครื่องของคุณ และโดเมนใน apple-app-site-association ต้องตรงกับ associated-domain ใน entitlement ของแอป — ซึ่งเป็นโดเมนจริงที่ DNS resolve ได้ ไม่ใช่ localhost
บางทีมเลี่ยงด้วยโดเมน staging เฉพาะ ใช้ได้ แต่ลูปการวนซ้ำช้า tunnel localhost ให้ URL HTTPS จริงบน subdomain จริงที่อุปกรณ์มือถือเข้าถึงได้โดยไม่บ่น
วิธีต่อ
- เสิร์ฟ
apple-app-site-associationและassetlinks.jsonจากเซิร์ฟเวอร์ dev ในเครื่องที่/.well-known/ทั้งสองไฟล์ ทั้งสองเส้นทาง - รัน
npx portpreview 3000(หรือพอร์ตที่เซิร์ฟเวอร์ dev ใช้) - จด hostname tunnel — แบบ
abc123.portpreview.dev - ใน entitlement associated domains ของแอป iOS เพิ่ม
applinks:abc123.portpreview.devใน intent filter ของ Android ใช้ host เดียวกัน - build และติดตั้งแอปบนอุปกรณ์จริง (simulator มีพฤติกรรม Universal Link แปลก ๆ)
- เปิด URL จากแอปอื่น — Notes, Mail, QR code — แล้วดูมันส่งไปยังแอปที่ติดตั้งแทนเบราว์เซอร์
จุดที่ติดของการ tunnel สำหรับ deep link: hostname tunnel เปลี่ยนระหว่างเซสชันเว้นแต่คุณมี subdomain ที่จอง การหมุนแต่ละครั้งหมายถึง build แอปใหม่ด้วยรายการ associated-domain ใหม่ หากคุณวนซ้ำพฤติกรรม deep link บ่อย ขอ subdomain ที่จอง
content-type สำคัญสำหรับ apple-app-site-association
iOS คาดหวังไฟล์ไม่มีนามสกุล และ content-type application/json (iOS ใหม่) หรือ application/pkcs7-mime (รูปแบบเก่าที่เซ็น) แทบทุกแอปสมัยใหม่ใช้แบบ JSON ธรรมดา ตรวจให้แน่ใจว่าเซิร์ฟเวอร์ dev คืน content-type ถูก ไม่งั้น iOS ปฏิเสธไฟล์เงียบ ๆ โดยไม่มีข้อผิดพลาดที่มีประโยชน์
ทดสอบจากเบราว์เซอร์เดสก์ท็อปก่อน: เปิด https://your-tunnel.portpreview.dev/.well-known/apple-app-site-association และยืนยันว่า JSON เรนเดอร์และ header content-type ใน dev tools ถูก หากผิด แก้ก่อนไล่บั๊ก Universal Link ใน simulator
กับดักดีบัก deep link อื่น ๆ
entitlement แอปไม่ตรง
หาก entitlement associated-domains บอก applinks:abc.portpreview.dev แต่ apple-app-site-association ระบุ def.portpreview.dev iOS ไม่ดึง hostname ต้องสอดคล้องกัน
Universal Link จากใน Safari
แตะ Universal Link ใน Safari (แอปเดียวกับที่แท็บอยู่) บางครั้งเปิดใน Safari แทนแอป นี่เป็นการออกแบบ — iOS ป้องกันลูกเล่น "เปิดแอปเมื่อผู้ใช้คลิกลิงก์" ทดสอบจาก Notes หรือ Mail แทน
Android App Links กับ digital asset links
Android รองรับ custom URL scheme (yourapp://path) ด้วย ซึ่งไม่ต้องการ HTTPS หรือ assetlinks.json ทดสอบง่ายกว่าแต่ปลอดภัยน้อยกว่า — แอปไหนก็ลงทะเบียน scheme เดียวกันได้ สำหรับ deep linking คุณภาพ production App Links คือคำตอบ
flow ทดสอบมือถือที่เราใช้
สำหรับโปรเจกต์ที่ส่งทั้ง iOS และ Android พร้อม deep link:
- เริ่ม backend ที่เสิร์ฟไฟล์
.well-known - tunnel ด้วย
npx portpreview 3000 - เมื่อ URL tunnel เสถียรสำหรับเซสชัน (หรือใช้ subdomain ที่จอง) อัปเดตรายการ associated-domain ของแอปและ build
- QA บนอุปกรณ์จริง — ทั้งติดตั้งใหม่และอัปเดต
- สำหรับชุด OAuth-และ-deep-link (ผู้ให้บริการล็อกอินที่ redirect กลับเข้าแอป) จับคู่กับ การทดสอบ callback OAuth
การตั้งค่าน่ารำคาญครั้งแรก หลังจากนั้น URL tunnel ก็เป็นแค่ env var อีกตัวใน scheme ของ Xcode และ Gradle
สำหรับรูปแบบทดสอบมือถือที่กว้างกว่า ดู การทดสอบมือถือด้วย tunnel localhost เข้าร่วมรายชื่อรอของ PortPreview