บันทึกการใช้งาน iOS Universal Links และ Android App Links บน React Native

สำหรับธุรกิจที่มีโปรดักส์ทั้งบนเว็บไซต์และโมบายแอพพลิเคชัน เชื่อว่าหลาย ๆ โปรดักส์ก็อยากจะให้ผู้ที่ใช้งานเว็บไซต์บนมือถือ เปลี่ยนใจเข้ามาใช้งานบนแอพพลิเคชันแทน
ซึ่งหนึ่งวิธีที่น่าสนใจ คือการกดลิงก์แล้วจะเปิดแอพพลิเคชันให้ เมื่อมีแอพพลิเคชันติดตั้งอยู่ในเครื่อง แต่ถ้าหากไม่มี ก็ให้ไปเปิดเว็บไซต์แทน ลองดูตัวอย่างด้านล่างนี้นะครับ

Universal Links
โจทย์นี้เราสามารถใช้ Universal Links เข้ามาช่วยได้ครับ โดยลักษณะของลิงก์ จะเหมือนกันกับ URL บนเว็บไซต์เลย เช่น https://my-web.com
ความสามารถนี้ ใน iOS เรียกว่า Universal Links ส่วน Android เรียกว่า App Links ในบทความนี้ขอเรียกรวม ๆ ว่า Universal Links แล้วกันนะครับ
ต้องทำอย่างไรบ้าง จึงจะใช้ Universal Links ได้ ?
ทั้ง iOS และ Android มีสองงานที่ต้องทำคือ
- ในเว็บไซต์ต้องถือไฟล์เพื่อให้รู้ว่า เว็บไซต์เหล่านี้จะจัดการกับแอพพลิเคชันได้อย่างไรบ้าง
- เพิ่มการตั้งค่าในแอพพลิเคชันเกี่ยวกับโดเมนของเว็บไซต์
เรามาดูแต่ละแพลตฟอร์มกัน
iOS
เพิ่มไฟล์ Apple App Site Association (AASA) บนเว็บไซต์
บนเว็บไซต์จะต้องมีไฟล์ Apple App Site Association (AASA) สำหรับบอกว่า เราจะจัดการเว็บไซต์นี้ ให้เปิดแอพพลิเคชันของเราได้อย่างไรบ้าง เช่น เว็บนี้เปิดแอพพลิเคชันตัวไหนได้บ้าง หรือ URL อะไรของเว็บที่สามารถเปิดแอพพลิเคชันของเราได้บ้าง เป็นต้น
ไฟล์นี้จะอยู่ในรูปของ JSON และต้องวางไว้ที่ https://my-web.com/apple-app-site-association
หรือ https://my-web.com/.wellknown/apple-app-site-association
ก็ได้ โดยจะทำงานบน https
เท่านั้นนะ
หน้าตาของไฟล์จะมีเนื้อหาประมาณนี้
{
"applinks": {
"apps": [],
"details": [
{
"appID": "5A67289A19.com.aofleejay.ducker",
"paths": [
"/",
"/about"
]
}
]
}
}
- details — เป็นอาเรย์ของแอพพลิเคชันที่เกี่ยวข้องกับเว็บไซต์ของเรา สามารถมีได้มากกว่า 1 แอพพลิเคชัน
- appID — ได้จากการเอา team id (หาได้ใน https://developer.apple.com/account/#/membership) และต่อด้วย bundle id
- paths — เป็นอาเรย์ที่ระบุว่าส่วนไหนของเว็บไซต์สามารถเปิดหรือไม่สามารถเปิดแอพพลิเคชันของเราได้ สามารถตั้งค่าได้หลายแบบ เช่น
"*"
คือเข้าได้จากทุก URL ของเว็บไซต์ หรือใส่"NOT /search"
ไว้เพื่อไม่ให้เปิดแอพพลิเคชันได้ เป็นต้น
ตั้งค่า Associated Domain Entitlement ในแอพพลิเคชัน
เราต้องไปตั้งค่าแอพพลิเคชัน โดยการใส่ลิสของโดเมนที่แอพพลิเคชันของเราซัพพอร์ท
ทำได้ผ่าน Xcode โดยเลือก target เป็นแอพพลิเคชันของเรา -> แท็บ Capabilities -> แท็บ Associated Domains -> แล้วเพิ่มโดเมนของเราไป โดยใช้ prefix เป็น applinks:
เช่น applinks:my-web.com

Android
เพิ่มไฟล์ Digital Asset Links บนเว็บไซต์
บนเว็บไซต์จะต้องมีไฟล์ JSON ที่เอาไว้จัดการเกี่ยวกับการเปิดแอพพลิเคชัน วางไว้ที่ https://my-web.com/.wellknown/assetlinks.json
สำหรับไฟล์นี้ผมใช้ Android App Links Assistant ใน Android Studio ช่วยสร้างขึ้นมาครับ จะได้หน้าตาประมาณนี้
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.aofleejay.ducker",
"sha256_cert_fingerprints":
["38:C7:02:86:A6:B0:77:21:3F:11:62:68:FE:24:0D:97:6F:05:6D:9A:4F:37:52:36:D9:22:F1:DE:8B:FE:01:7F"]
}
}
]
เพิ่ม Scheme ในแอพพลิเคชัน
เข้าไปเพิ่ม <intent-filter />
ได้ใน AndroidManifest.xml
โดยกำหนด android:scheme
และ android:host
ตามโดเมนของเราครับ
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="ducker.netlify.com" />
</intent-filter>
มาลองทดสอบกัน
วิธีทดสอบก็คือวางลิงก์ ให้สามารถคลิกได้ เช่น วางไว้ในโน้ต แล้วลองกดลิงก์ในมือถือดูครับ หากว่ามีแอพก็จะเปิดแอพขึ้นมาทันที แต่ถ้าไม่มีแอพหรือเปิดบนเดสก์ท็อปก็จะเปิดเบราเซอร์ขึ้นมาแทน
หรือถ้าทำใน simulator ก็สามารถใช้คำสั่งดังนี้ได้ครับ
- iOS —
xcrun simctl openurl booted https://my-web.com
- Android —
adb shell am start -W -a android.intent.action.VIEW -d "https://ducker.netlify.com"


ตั้งค่าสำหรับ React Native กันต่อ
ใน React Native เราสามารถใช้งาน Universal Links คู่ไปกับ react-navigation ได้ (ดูการติดตั้ง react-navigation ได้ ที่นี่)
สิ่งที่ต้องทำเพิ่มจากปกติคือ ระบุ path ให้กับแต่ละหน้า และตั้งค่า urlPrefix ด้วยโดเมนของเรา เพียงแค่นี้ก็สามารถใช้งาน Universal Links ใน React Native ได้แล้วครับ
จากตัวอย่างด้านล่างเป็น stack navigator ที่มีสองหน้าก็คือหน้า home กับหน้า about ครับ
import React from 'react'
import {
createStackNavigator,
createAppContainer,
} from 'react-navigation'
import { Home, About } from ‘./pages’const AppNavigator = createStackNavigator({
Home: { screen: Home, path: '/' },
About: { screen: About, path: '/about' },
})const AppContainer = createAppContainer(AppNavigator)export default () => (
<AppContainer uriPrefix="https://ducker.netlify.com" />
)
เมื่อเรากดลิงก์ด้วย https://my-web.com/about
ก็จะเข้าไปยังหน้า about ในแอพพลิเคชันได้เลยครับ
ความแตกต่างระหว่าง Universal Links กับ Deep Links (URI Schemes)
- หน้าตาของ Deep Links จะไม่ใช่เว็บ URL แต่จะเป็น
my-app://home
ทำนองนี้แทน ซึ่งก็จะใช้ร่วมกับเว็บไม่ได้ - Deep Links ไม่รองรับ fallback เช่น ถ้าเราไม่ได้ลงแอพพลิเคชันเอาไว้ หรือไม่มีแอพพลิเคชันตาม Deep Links ที่เรากรอก ก็จะเจอ error ทันที เช่น
non-extsting-app://
ต่างกับ Universal Links ที่ถ้าไม่มีแอพพลิเคชัน สามารถไปเปิดเว็บไซต์แทนได้ - Deep Links สามารถเปิดแอพพลิเคชันของใครก็ได้ เช่น สามารถพิมพ์
fb://
เพื่อเปิดเฟสบุ๊คได้เลย ต่างกับ Universal Links ที่ต้องใช้ Apple App Site Association หรือ Digital Asset Links ไปวางไว้บนเว็บไซต์ของเราก่อน ทำให้มั่นใจได้ว่าจะไม่มีใครมาสั่งเปิดแอพพลิเคชันของเราได้แน่ ๆ
จบไปอีกหนึ่งบทความแล้วนะครับ ขออภัยที่ห่างหายไปนาน สำหรับบทความนี้มีข้อแนะนำหรือติชมอะไรก็สามารถบอกได้เลยนะครับผม ขอให้สนุกกับการโค้ดดิ้งครับ