web analytics

Flutter : การทำ Deep Link ใน Flutter

สวัสดีผู้อ่านครับ บล็อกนี้จะพามาลองเล่น Deeplink ซึ่งเป็นเทคนิคการใช้ url ร่วมกับแอป ใช้ได้กับทั้ง iOS Android และใน Flutter เองก็มี library ให้ใช้งานเช่นกัน ขั้นตอนติดตั้งค่อนข้างยุ่งยากนิดหน่อย มาลองเล่นกันดูครับ

รู้จัก Deep link

Deep link เป็นคำเรียกรวมๆของเทคนิคที่ทำให้แอปสามารถเข้าใจ link ยกตัวย่างที่เราเห็นบ่อยๆก็คือ url ของเว็บไซ์ เช่น https://benzneststudios.com โดยตรงส่วน https เรียกว่า scheme ส่วนตรง บลาๆ .com เรียกว่า host ดังนั้นจริงๆแล้วเราสามารถใช้ scheme , host เป็นอะไรก็ได้ เช่น example://hello หรือ store://app เป็นช่องทางให้ผู้อื่นส่งอะไรบางอย่างให้แอปของเรา หากเขารู้ว่า scheme ของแอปเรากำหนดไว้ว่าอะไร หรือผ่าน link ในรูปแบบที่เรากำหนด ยกตัวอย่างการใช้งานจริง เช่น แอปอื่นอยากจะขอเปิดแอป facebook page ขึ้นมา ทาง facebook ก็ได้เตรียม deep link เอาไว้ ว่า fb://page/ID หรือของ playstore ก็มี deeplink หากเราอยากเปิด play store จากแอปของเรา สามารถใช้ market://details?id= จะเห็นว่า deeplink มีประโยชน์มากทีเดียว

รู้จัก Universal App Link

ทีนี้การใช้ deeplink แบบที่เรากำหนดเอง เช่น example://app พวกนี้เราสามารถใช้ได้เลย แต่ deeplink แบบที่มีเงื่อนไขอยู่บ้างคือ แบบที่ใช้ scheme เป็น http:// และ https:// เพราะว่ามันเป็น url ที่ใช้สำหรับเปิดเว็บไซต์ กล่าวคือมันอาจมีเจ้าของ เราไม่ควรนำ url คนอื่นมาใช้เป็น deeplink โดยไม่ได้รับอนุญาต จะใช้ได้ก็ต่อเมื่อมีการยืนยันบางอย่างจากเว็บไซต์แล้วเท่านั้น

ใน iOS เรียกการใช้ deep link แบบที่ scheme เป็น https นี้ว่า Universal link ใน android เรียกว่า App link ผมขอเรียกรวมๆเลยละกันว่า UAL (universal app link อันนี้ผมเรียกเองนะ) ซึ่งหลักการของทั้งคู่เหมือนกัน คือเราต้องเอาไฟล์บางอย่างตามที่เขากำหนดไปวางไว้ในเว็บของเราก่อน เพื่อยืนยันความเป็นเจ้าของ จากนั้นพอ user เปิดลิงค์ขึ้นมา มันจะวิ่งไปเช็คว่า แอปที่จะเปิดลิงค์ นี้เป็นเจ้าของ url นั้นหรือไม่ ถ้าใช่ก็เปิดแอป หากไม่ก็เปิดเว็บปกติ ดังนั้นคนที่จะทำให้แอปรองรับ UAL ได้จะต้องเป็นเจ้าของเว็บด้วยนั่นเอง

ตัวอย่างการใช้ UAL เช่น เว็บ pantip.com ซึ่งมี url สำหรับอ่านกระทู้ในเว็บไซต์ https://pantip.com/topic/1234 และก็มีเวอชันแอปด้วย เมื่อผู้ใช้กดลิงค์ url pantip ในมือถือ ถ้าเครื่องนั้นติดตั้งแอป pantip อยู่ ก็สามารถใช้ UAL เปิดแอป pantip พร้อมเปิดหน้ากระทู้นั้นขึ้นมาให้อ่านในแอปได้เลย สะดวกใช่ไหมละ เป็นการสนับสนุนให้ผู้ใช้เข้ามาใช้งานแอปมากขึ้น เพราะผู้ใช้มือถือน่าจะเหมาะกับการอ่านในแอป มากกว่าอ่านผ่าน browser

สำหรับ UAL ใน android รองรับเฉพาะ android 6.0 ขึ้นไป และใน iOS 9 หรือสูงกว่าเท่านั้น ทีนี้ทั้งคู่มีข้อแตกต่างของ UAL อีกนิดคือ ใน android สามารถใช้ UAL ได้ปกติ ไม่ต้องยืนยันเว็บไซต์ก็ได้ แต่ว่าตอนผู้ใช้เปิดลิงค์จะมีหน้าต่าง popup ขึ้นมาให้ผู้ใช้เลือกก่อน แต่ใน iOS จะใช้ไม่ได้ทุกกรณีต้องเป็นเจ้าของ url เท่านั้น ตามสรุปในตารางด้านล่าง

เริ่มต้น

ในตัวอย่างนี้ ใน Android ผมจะพาไปทำ UAL กันเลย เพราะการใช้ deep link แบบที่เรากำหนด scheme เองนั้นง่ายมาก หากทำ UAL ได้ก็ทำแบบ deep link ปกติได้ไม่ยาก

มาที่ Flutter Project ในตัวอย่างนี้ จะสร้างหน้าง่ายๆขึ้นมาหน้านึงสำหรับให้กดที่ deep link แล้วเปิดแอปของเราขึ้นมา

Universal App Links ใน android

ไปที่ android/app/src/main/AndroidManifest.xml
เพิ่ม inter-filter ลงไปใน <activity>

จุดสำคัญคือ ตรง data จะต้องกำหนด scheme , host , pathPrefix ซึ่งในที่นี้ผมจะใช้เป็น url ของเว็บบล็อกของผมเอง คือ
scheme = https
host = benzneststudios.com
pathPrefix = /blog

ลองเปิดเว็บที่มีลิงค์ url เป็นตามที่เรากำหนด ก็จะมีตัวเลือกขึ้นมาว่าจะให้เปิดแอปเราหรือไม่ ถ้าเราเลือกแอปของเรา แอปก็จะถูกเปิดขึ้นมา

นี่คือการใช้ deeplink https หรือที่ผมเรียกว่า UAL แบบไม่ยืนยันเว็บไซต์ใน android ซึ่งจะมีแค่หน้าต่างถามยืนยันมาขัดใจนิดหน่อย ดังนั้นหากเราจะใช้ deeplink แบบกำหนดเอง ก็แค่ไม่ใช้ https ไปใช้ abc , example , doreamon อะไรก็ตามใจนั่นเอง

เพิ่ม dependencies ใน Flutter

มาลองใช้งาน deep link ที่เรากดจากนอกแอป แล้วนำค่ามาใช้งานใน Flutter กัน
เพิ่ม dependencies ชื่อว่า uni_links ใน pubspec.yaml

เพิ่มส่วนการเช็ค ว่าแอปของเราเปิดจากที่ผู้ใช้กดจาก deeplink เข้ามา หรือไม่ ถ้าใช่เราจะได้ uri ซึ่งก็คือ object ที่เก็บค่าต่างๆเอาไว้ เช่น scheme , host , param

ในตัวอย่างนี้ผมจะนำ uri ไปแสดงในหน้าใหม่ โดยเช็คว่าหาก uri ไม่เท่ากับ null แสดงว่าผู้ใช้มาจากการใช้ deeplink แอปเปิดหน้าที่สองขึ้นมา ซึ่งเราไม่สามารถ push หน้าใหม่ขณะที่หน้าแรกยัง build ไม่เสร็จได้

ดังนั้น เลยต้องใช้คำสั่ง SchedulerBinding.instance.addPostFrameCallback เพื่อให้หน้าแรก build เสร็จก่อน แล้วค่อย push ไปหน้าที่สองพร้อมส่ง uri ไปด้วย

หน้าที่สอง ตัวอย่างนี้แค่เอา uri มาแสดง เพื่อยืนยันว่าแอปเปิดมาจาก deeplink นะ

ลองรัน ตัวอย่างนี้ผมสมมุติว่าเป็นแอปบล็อกของผม ใช้ deeplink เป็น url ของเว็บไซต์ผมเอง

Universal App Link Verified ใน Android

จากการใช้ UAL แบบไม่ยืนยันเว็บไซต์ สิ่งที่ขัดใจคือมีหน้าต่างขึ้นมาถาม หลังจากกดที่ url หากเราจะข้ามขั้นตอนนี้ เราจะต้องทำการยืนยันเว็บไซต์ของเราก่อน ก่อนอื่นเพิ่มบางอย่างใน android/app/src/main/AndroidManifest.xml ตรง intent-filter ให้เพิ่ม autoVerify=”true” เพื่อบอกว่าเราจะใช้การเปิด deeplink อย่างเป็นทางการ

ยืนยันเว็บไซต์ด้วย Asset link

ขั้นตอนคือ เราต้องเอาไฟล์ที่ชื่อว่า assetlinks.json ไปวางไว้ในเว็บไซต์ domian ของเรา เพื่อให้ android วิ่งไปอ่านเป็นการยืนยันตัวตน หลังจากผู้ใช้กด url ที่เป็น UAL ของแอปเรา

หน้าตาของไฟล์ .json จะเป็นประมาณนี้ คือมี package name กับ fingerprint ที่ build จาก keystore (จะ debug หรือ release ก็ได้) โดยสามารถกำหนดได้หลายอัน

เจ้าไฟล์ assetlinks.json ไม่จำเป็นต้องเขียนเองก็ได้ ใน Android studio มีตัวช่วยในการสร้าง คือไปที่ Tools > App Links Assistant

หลังจากทำไฟล์เสร็จแล้ว เราก็เอาไฟล์ assetlinks.json ไปวางในโฟลเดอร์ .well-known เช่น ของผมได้ลองวางไว้บนเว็บไซต์ของผม คือ
https://benzneststudios.com/.well-known/assetlinks.json

เอาไฟล์ไปวางเสร็จแล้ว เราจะต้องยืนยันเว็บไซต์ด้วยการเข้าลิงค์นี้ โดยตรง parameter ก็เปลี่ยนเป็นเว็บไซต์ของผู้อ่านซะ

ถ้าสำเร็จก็จะมี json กลับมาว่า เรียบร้อยแล้ว ประมาณนี้

ยังเหลืออีกนิด คือเราจะต้องเอา path ของไฟล์ assetlinks.json บนเว็บของเราไปใส่ในโปรเจค

ก่อนอื่นสร้างไฟล์ android/app/src/main/res/values/strings.xml ซึ่งไฟล์นี้ก็คือการกำหนดค่าใน resource ของ android แล้วเพิ่ม asset_statement เป็น url ของไฟล์
assetlinks.json

จากนั้นที่ AndroidManifest.xml ก็เพิ่ม meta data เรียกใช้ resource

ลองรัน ตอนนี้เราสามารถใช้ Universal App Link ได้แล้ว และไม่มี dialog กวนใจ

การใช้ Custom Scheme ใน iOS

ลองใช้ custom scheme ใน iOS กัน เช่น benz://
ไม่ยากเลย แค่เพิ่มค่าลงไปใน Info.plist

จากนั้นเราก็สามารถเรียก custom scheme ได้แล้ว ซึ่งมันจะมีหน้าต่างขึ้นมาถามว่าให้เปิดแอปของเรามัยแบบนี้

Universal App Link Verified ใน iOS

ทีนี้มาลองใช้ deeplink แบบ https กันบ้าง ใน iOS ขั้นตอนก็ไม่ต่างจาก Android เท่าไหร่นัก แน่นอนว่าก็ต้องใช้ไฟล์ บางอย่างไปวางบนเว็บไซต์เพื่อยืนยันตัวตน

ก่อนอื่นต้องรู้ TEAM id ของเราก่อน โดยเข้าไปที่ https://developer.apple.com/account/#/membership

อีกอันที่ต้องใช้คือ bundle id ของ แอป ดูได้จากใน Xcode

จากนั้นเราก็สร้างไฟล์ที่ข้อมูลข้างในคือโครงสร้าง json ชื่อไฟล์ว่า
apple-app-site-association (ไม่มี .json นะ) ข้อมูลข้างในก็คือ ตรง appID ให้เอา team id กับ bundle id มาต่อกัน

จากนั้นก็เอาไฟล์ ไปวางใน .well-known เช่น ของเว็บไซต์ผม คือ
https://benzneststudios.com/.well-known/apple-app-site-association

กลับมาที่โปรเจคของเรา เปิด Xcode และไปที่ Runner เมนู Capabilities ตรง Associated Domains ให้เราเปิด On แล้วใส่ Domains ว่า applinks:xx.com ซึ่งตรง applinks คือบังคับนะ

ลองรัน แล้วเปิด url ของเว็บไซต์เรา ถ้าถูกต้องจะเปิดแอปของเราขึ้นมา

สรุป

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

หวังว่าบล็อกนี้จะมีประโยชน์นะครับ (:

ตัวอย่างโค้ดอยู่ที่ Github ครับ
https://github.com/benznest/flutter-deep-link