Apple App Site Association Generator: สร้าง Universal Links ที่ iOS เชื่อถือ
สร้างไฟล์ apple-app-site-association JSON สำหรับ iOS Universal Links และ Shared Web Credentials — ใส่ appID, path rules และ webcredentials ได้ครบ ทำงานฝั่ง client ล้วนๆ
Table of Contents
Apple App Site Association Generator: สร้าง Universal Links ที่ iOS เชื่อถือ
ลองแตะลิงก์สินค้าใน Messages ดูสิ — แทนที่จะได้แท็บ browser แอป iOS กลับเปิดตรงไปหน้าสินค้านั้นทันที นั่นคือ Universal Links ที่ทำงานอยู่: URL HTTPS ธรรมดาที่ iOS ส่งเข้าแอปของคุณโดยตรง เมื่อโดเมนของคุณยืนยันว่าแอปตัวนี้พูดแทนเว็บไซต์ได้ ส่วนคนที่ไม่มีแอปก็เห็นหน้าเดิมใน Safari ตามปกติ ไม่มีทางตัน
Apple จะยอมเชื่อแบบนั้นก็ต่อเมื่อ server ของคุณเผยแพร่ไฟล์ claim — apple-app-site-association JSON — ไว้ที่ตำแหน่ง well-known บนโดเมนผ่าน HTTPS เท่านั้น Apple CDN เป็นคนไปดึงไฟล์มา แล้วเครื่องผู้ใช้เทียบ URL แต่ละอันกับ appID และ path patterns ของคุณ key เพี้ยนแค่จุดเดียว ลิงก์ก็เงียบๆ กลับไปเปิดใน browser โดยไม่มี error ให้เห็นเลย
Apple App Site Association Generator ช่วยตัดความเดาออก: ใส่ appID เพิ่ม path rules พร้อม NOT exclusions เปิด webcredentials สำหรับ password autofill ถ้าต้องการ แล้ว copy ไฟล์ที่ถูกต้องออกมา — generate ทั้งหมดใน browser ของคุณ บทความนี้จะพาไปดูวิธี generate, path patterns, associated-domains entitlement และรายละเอียดการ host ที่คนพลาดกันบ่อย
ทำไมต้องใช้ Apple App Site Association Generator?
- โครงสร้าง JSON ไม่ให้อภัย — JSON เพี้ยนหรือสะกด key ผิด iOS ก็มองข้ามทั้งไฟล์ทันที เครื่องมือนี้ emit output ที่ถูกโครงสร้างทุกครั้ง
- appID ต้องตรงเป๊ะทุกตัวอักษร — แต่ละรายการใช้รูปแบบ TEAMID.BUNDLEID โดย Team ID เป็นตัวอักษรพิมพ์ใหญ่ 10 ตัว ตัวพิมพ์เล็กแว้บเดียวหรือลืมจุด iOS ก็ไม่มีวัน match เครื่องมือ validate ให้ตั้งแต่พิมพ์
- Path patterns มีกฎแอบแฝง — wildcard, NOT exclusion และการจัดการ query เข้าใจผิดกันง่ายๆ pattern ผิดเป็นได้ทั้งแบบ match เกินและแบบ match ไม่เป็นที
- เปิด password autofill ได้ด้วยสวิตช์เดียว — ส่วน webcredentials ที่เปิดเสริมได้ทำให้ Shared Web Credentials ทำงาน: password ที่เซฟบนเว็บจะถูกเสนอในแอปและกลับกัน
- ทำงานฝั่ง client ล้วนๆ — Team ID และ bundle identifier ไม่หลุดออกจาก browser ปลอดภัยแม้กับแอปที่ยังไม่เปิดตัว
ฟีเจอร์หลัก
| Feature | สิ่งที่ทำ |
|---|---|
| appID builder | เพิ่มรายการ TEAMID.BUNDLEID ลงใน applinks details array |
| Path rules | ผูก path อย่าง /shop/* เข้ากับแอปของคุณ |
| NOT patterns | ตัด route ส่วนตัวหรือ route สำหรับแอดมินออกจาก deep link |
| webcredentials section | เปิด Shared Web Credentials password autofill ให้แอปของคุณ |
| Copy and download | ได้ไฟล์ apple-app-site-association พร้อมเอาขึ้น host ทันที |
- appID ผ่านการ validate รูปแบบ — ทุกแถวถูกเช็กกับรูปแบบทางการ — ตัวอักษรและตัวเลข 10 ตัว จุด แล้ว bundle identifier ที่ valid — แถวเพี้ยนจึงไม่มีทางหลุดไปใน output
- webcredentials ตรงตามสเปก — apps array ถูกเก็บเป็นลิสต์ appID ธรรมดา เพราะ associated domains ประกาศที่ฝั่งแอป ไม่ใช่ในไฟล์นี้
วิธีใช้งาน
- หา Team ID และ Bundle ID — ใน Xcode Team ID อยู่ที่ Settings, Accounts (Membership Details) ส่วน Bundle Identifier อยู่ที่แท็บ Signing and Capabilities ของแต่ละ target ทั้งสองมารวมกันเป็น appID เช่น AB12CD34EF.com.example.shop
- ใส่ appID — เปิด Apple App Site Association Generator แล้วเพิ่มหนึ่งแถวต่อหนึ่งแอป แต่ละแถวจะกลายเป็นรายการใน details array
- เพิ่ม path rules — ใส่ path ที่อยากให้ผู้ใช้ลงเช่น /shop/_ หรือ /article/_ แล้วตัด route ที่อ่อนไหวด้วยบรรทัด NOT อย่าง NOT /private/*
- เปิด webcredentials (ถ้าต้องการ) — ถ้าเว็บกับแอปใช้ login ร่วมกัน ให้สลับสวิตช์แล้วใส่โดเมน ระบบจะ generate section นี้พร้อม appID ของคุณให้เอง
- เอาไฟล์ไป host ให้ถูกวิธี — serve JSON ที่ https://yourdomain.com/.well-known/apple-app-site-association ผ่าน HTTPS ไม่มี redirect พร้อม content type application/json จากนั้นลงแอปใหม่บนเครื่องจริงแล้วแตะลิงก์ทดสอบ
Paths, Patterns และ Associated Domains Entitlement
แต่ละรายการในส่วน applinks จับคู่ appID หนึ่งตัวกับ paths ที่มัน claim:
{
"applinks": {
"details": [
{
"appID": "AB12CD34EF.com.example.shop",
"paths": ["/shop/*", "/article/*", "NOT /private/*"]
}
]
},
"webcredentials": {
"apps": ["AB12CD34EF.com.example.shop"]
}
}
อ่านไฟล์ให้เป็น — appID คือ Team ID ต่อด้วยจุดและ bundle identifier โดย iOS เทียบกับ signing team ของแอปที่ติดตั้งไว้ ส่วน paths ตัดสินว่า URL แบบไหนถึงจะถูกส่งเข้าแอป — ไม่ใส่เลยทุก URL match หมด, ใส่ array เปล่าไม่ match อะไรเลย
ไวยากรณ์ของ pattern — เครื่องหมาย _ match ได้หลายตัวอักษร ส่วน ? match ตัวเดียว เพราะ ? เป็น wildcard ด้วย ถ้าจะ match query จริงๆ ต้อง escape — /search?q=_ จะเล็งเฉพาะ URL ที่มีพารามิเตอร์ q และระบบประมวลผล pattern จากบนลงล่างใช้ตัวแรกที่ match ก่อน ให้วาง NOT exclusions ไว้ก่อน wildcard กว้างๆ อย่าง /* เสมอ
webcredentials กับ password autofill — apps array ระบุ appID ที่จะแชร์ credential กับโดเมนของคุณ เมื่อแอปประกาศ service นี้ใน entitlement ระบบ autofill จะมองเว็บกับแอปเป็น identity เดียว: password ที่เซฟใน Safari จะถูกเสนอในแอปและกลับกัน sync ผ่าน iCloud Keychain
Entitlement ฝั่งแอป — ไฟล์เดียวยังไม่พอ แอปต้องเปิด capability Associated Domains: applinks:example.com สำหรับ Universal Links และ webcredentials:example.com สำหรับ autofill ทุกโดเมนและทุก subdomain ที่อยู่ใน entitlement ต้องมีไฟล์ claim ของตัวเอง
เงื่อนไขการดึงผ่าน Apple CDN — เครื่องผู้ใช้อ่านสำเนาจาก Apple CDN ที่ดึงตอนติดตั้งและดึงซ้ำเป็นระยะ ต้อง serve หลัง HTTPS ที่ certificate valid ตอบ 200 โดยไม่มี redirect และใช้ content type application/json ไฟล์เปลี่ยนไม่ได้ทันที — ลงแอปใหม่เพื่อ trigger การดึงสำเนาล่าสุด
Use Case จริง
Deep Link สำหรับ E-commerce
คนที่มีแอปแตะ /shop/* แล้วเปิดตรงหน้าสินค้าโดยตะกร้าไม่หาย ส่วนคนอื่นเห็น URL เดิมบนเว็บปกติ ลิงก์เดียว serve ทุกเครื่อง
Password Autofill ระหว่างเว็บกับแอป
เมื่อเปิด webcredentials ผู้ใช้เซฟ password ครั้งเดียวแล้วเรียกใช้ได้ทั้งสองฝั่ง — ticket ลดลง และผู้ใช้กล้าใช้ password ยากๆ ขึ้นเพราะ iCloud Keychain เป็นคนจำให้
Marketing Campaign Attribution
Universal Links คง URL เดิมไว้ทั้งหมด พารามิเตอร์อย่าง utm และ campaign id จึงไปถึงแอปเพื่อวัดผลต่อ — ต่างจาก custom URL scheme ที่ไม่มี referrer และแอปไหนก็แย่งประกาศ scheme เดียวกันได้
QR-to-App Flow
QR Code บนโปสเตอร์หรือบรรจุภัณฑ์ฝัง URL HTTPS ธรรมดา: สแกนด้วย iPhone ที่มีแอปจะเปิดเนื้อหานั้นในแอปทันที ส่วนเครื่องอื่นเปิดเว็บจากโค้ดเดียวกัน
Best Practices
- ตัด route ส่วนตัวด้วย NOT — หน้า admin และหน้า reset password ไม่ควรถูกดูดเข้าแอป วาง NOT /private/* ไว้ก่อน catch-all เสมอ
- อัปเดตไฟล์ทุกครั้งที่ release แอป — target ใหม่, extension หรือ bundle ID ที่เปลี่ยนต้องมี appID เพิ่มในไฟล์ ไฟล์ค้างเก่าคือสาเหตุอันดับหนึ่งของลิงก์ที่คืนนี้ยังเปิดในแอป พรุ่งนี้เปิดใน Safari
- Verify ด้วย AASA validator ของ Apple — ส่ง URL จริงเข้าเครื่องมือ validation ของ Apple หลัง deploy ทุกรอบ เครื่องมือจะชี้จุด JSON พังและปัญหาการ fetch ได้ละเอียด
- อย่า serve ผ่าน HTTP หรือ redirect เด็ดขาด — TLS ที่ valid, status 200, application/json และไม่มี 301/302 เป็นเงื่อนไขที่ต่อรองไม่ได้
- ครอบคลุมทุก host ที่ใช้ลิงก์ — ทุก subdomain ใน entitlement ต้องมีไฟล์ของตัวเอง example.com กับ shop.example.com verify แยกกัน
- ทดสอบบนเครื่องที่ลงแอปใหม่ — การ fetch ผ่าน CDN เกิดตอนติดตั้ง ลงใหม่สดๆ จึงเป็นการทดสอบที่ซื่อสัตย์ที่สุด
เปิดลิงก์เข้าแอปโดยตรงตั้งแต่วันนี้
ไฟล์ JSON เล็กๆ ไฟล์เดียวตัดสินว่าแตะลิงก์แล้วจะลงแอปหรือแท็บ browser Apple App Site Association Generator สร้างไฟล์นี้ให้ถูกต้องในไม่ถึงนาที ทำงานฝั่ง client ล้วนๆ — ใส่ appID เอาไฟล์ไปวางใน /.well-known แล้วให้ iOS เริ่มเชื่อลิงก์ของคุณ
Related Tools You Might Like:
- Assetlinks JSON Generator — เวอร์ชันฝั่ง Android สำหรับ App Links verification
- JSON Formatter — validate และจัดรูป JSON ก่อนเอาขึ้นใช้งาน
- URL Parser — แยก deep link เป็น scheme, host, path และ query
ขอให้ทุกการแตะเปิดแอปที่ใช่ครับ!
คำถามที่พบบ่อย
ถ: ต้องวางไฟล์ apple-app-site-association ไว้ที่ไหน?
ตอบ: ที่ https://yourdomain.com/.well-known/apple-app-site-association — สังเกตว่าไม่มีนามสกุล .json — ผ่าน HTTPS ด้วย certificate ที่ valid ไม่มี redirect และ content type เป็น application/json
ถ: หา Team ID กับ Bundle ID ตรงไหน?
ตอบ: ใน Xcode — Team ID อยู่ที่ Settings, Accounts, Membership Details ส่วน Bundle Identifier อยู่ที่แท็บ Signing and Capabilities ของแต่ละ target appID คือ Team ID ต่อด้วยจุดและ bundle ID
ถ: อัปเดตไฟล์แล้วเครื่องยังเปิดใน browser อยู่ ทำไม?
ตอบ: เครื่องผู้ใช้ได้ไฟล์ผ่าน Apple CDN ที่ cache ไว้และดึงซ้ำเป็นระยะ ลบแล้วลงแอปใหม่เพื่อบังคับดึงสำเนาล่าสุด ระหว่างนั้นเช็ก URL จริงด้วย validator ของ Apple ไปก่อนได้