ขอหยิบเรื่องการเปิด Page หรือ Official Account ที่อยู่บน Facebook, Twitter, Instagram หรือ LINE จากแอปที่ติดตั้งไว้บนอุปกรณ์แอนดรอยด์ของผู้ใช้ มาเล่าให้อ่านกันครับ

เพราะแอปส่วนใหญ่ที่ไม่ได้เกี่ยวข้องกับ Social โดยตรง มักจะต้องการใส่ปุ่มเพื่อเปิดหน้า Page หรือ Official Account ที่ต้องการ เช่น บริษัท ABC มี Facebook Page และ Twitter Official Account ก็คงอยากจะใส่ปุ่มลงในแอปเพื่อให้ผู้ใช้กดแล้วเปิดเข้า Social เหล่านี้ทันที

การทำเช่นนั้นได้ก็จะต้องใช้ Implicit Intent โดยกำหนด URL ที่ต้องการแบบนี้

val uri = Uri.parse("https://www.facebook.com/SleepingForLess")
val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(intent)

คำสั่งดังกล่าวจะเปิด URL ดังกล่าว ซึ่งเป็น URL ของ Social ที่ต้องการ (ยกตัวอย่างเป็น Sleeping For Less ใน Facebook Page)

แต่ผลลัพธ์ที่ได้จะเป็นแบบนี้

จะเห็นว่าคำสั่งดังกล่าวเป็นการเปิด URL จน Web Browser ที่มีอยู่บนเครื่องแทน

ถ้าอยากให้เข้าผ่านแอปที่ติดตั้งอยู่ในเครื่องโดยตรงเลยล่ะ?

นั่นแหละครับ จุดประสงค์ของบทความนี้ เพราะในความเป็นจริงนั้นนักพัฒนาต้องการให้เปิดแอปที่ต้องการโดยตรง ไม่ได้อยากจะเปิดหน้าเว็ปซักเท่าไร

แต่การจะทำแบบนั้นได้ก็ต้องใช้สิ่งที่เรียกว่า Deep Link เข้ามาช่วยแทน

Deep Link คือรูปแบบของ URL ที่สามารถระบุแอปที่ต้องการเปิดได้เลย โดยแอปที่ติดตั้งอยู่ในเครื่องจะต้องรองรับกับ URL นั้นๆด้วย

จากที่เจ้าของบล็อกลองหาข้อมูลดู ก็พบว่า Social App ส่วนใหญ่รองรับ URL ที่เป็นแบบ Deep Link อยู่แล้ว ดังนั้นสิ่งที่นักพัฒนาจะต้องทำก็คือการกำหนด Page หรือ Official Account ที่ต้องการเปิดให้ถูกต้อง

ซึ่งบางแอปก็จะรองรับ Scheme ที่เป็น https ที่ใช้กับหน้าเว็ป แต่บางแอปอย่างเช่น Facebook จะต้องใช้ URL ที่เจาะจงสำหรับแอปเท่านั้น

สำหรับ Facebook

จะใช้ URL รูปแบบนี้

fb://page/<page_id>

โดย <page_id> คือ ID ของ Page ที่ต้องการ ซึ่งสามารถค้นหาผ่านเว็ป Find My Facebook ID ได้เลย

ยกตัวอย่างเช่น

fb://page/577361412281379

สำหรับ Twitter

จะใช้ URL รูปแบบนี้

twitter://user?user_id=<user_id>

ให้กำหนด <user_id> ด้วยเลข ID ของ User ที่ต้องการ ซึ่งสามารถค้นหาผ่านเว็ป Tweetter ID ได้เลย

TweeterID - Twitter ID and username converter
Convert any Twitter account’s username or @handle into its respective Twitter ID, or convert ID to username

ยกตัวอย่างเช่น

twitter://user?user_id=3195422066

Instagram

จะใช้ URL รูปแบบนี้

instagram://user?username=<username>

ให้กำหนด <username> ด้วยชื่อของ User ที่ต้องการ

ยกตัวอย่างเช่น

instagram://user?username=google

LINE

สำหรับ LINE จะเปิดจาก URL ที่เป็น https ได้เลย

https://line.me/ti/p/<account_name>

โดย <account_name> คือชื่อของ Account ที่ต้องการ

ยกตัวอย่างเช่น

https://line.me/ti/p/@linedevth

ถ้าอุปกรณ์แอนดรอยด์ในเครื่องนั้นๆมีแอปติดตั้งอยู่ ก็จะทำงานได้อย่างปกติ แต่ถ้าไม่มีแอปอยู่ในเครื่อง การใช้ Implicit Intent กับ URL ที่เป็น Deep Link ก็จะทำให้แอปพังทันทีจ้า

ถ้าไม่มีแอปติดตั้งอยู่ในเครื่องก็ควรเปิดหน้าเว็ปแทน

เพื่อไม่ให้แอปพังอย่างน่าเกลียด นักพัฒนาก็จะต้องเขียนเผื่อไว้ด้วยว่าถ้ามีแอปติดตั้งอยู่ก็จะให้เปิดผ่าน URL ที่เป็น Deep Link ทันที แต่ถ้าไม่ได้ติดตั้งไว้ ก็ให้เปิดหน้าเว็ปเหมือนปกติแทน

private fun launch(activity: Activity, deepLink: String, fallback: String) {
    var intent = Intent(Intent.ACTION_VIEW, Uri.parse(deepLink))
    if (activity.packageManager.resolveActivity(intent, 0) == null) {
        intent = Intent(Intent.ACTION_VIEW, Uri.parse(fallback))
    }
    activity.startActivity(intent)
}

โดยจะใช้คำสั่ง resolveActivity ของ PackageManager เพื่อเช็คว่ามีแอปตัวไหนในเครื่องที่รองรับกับ URL ดังกล่าวหรือไม่ ถ้ามีก็จะสั่งให้เปิดทันที แต่ถ้าไม่มีก็จะให้เปิด URL อีกตัวที่ใช้ Scheme เป็น https แทน

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

private static final String FACEBOOK_PACAKAGE_NAME = "com.facebook.katana"; private static final String URL_SCHEME_SFL_PAGE = "fb://page/577361412281379"; private static final String URL_SFL_PAGE = "https://www.facebook.com/SleepingForLess"; ... if(isAppInstalled(context, FACEBOOK_PACAKAGE_NAME)) { openUrl(URL_SCHEME_SFL_PAGE); } else { openUrl(URL_SFL_PAGE); } ... private void openUrl(String url) { Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); } private boolean isAppInstalled(Context context, String packageName) { try { context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); return true; } catch (PackageManager.NameNotFoundException ignored) { } return false; }

จากโค้ดตัวอย่างข้างบนนี้ก็จะทำการเช็คก่อนว่าเครื่องนั้นๆลงแอป Facebook ไว้หรือไม่ (เช็คจาก Pacakage Name) ถ้ามีการติดตั้งไว้ก็จะเปิด URL Scheme แต่ถ้าไม่ได้ติดตั้งไว้ก็จะเปิด URL ธรรมดาแทน

val activity: Activity = /* ... */
launch(
    activity = activity, 
    deepLink = "fb://page/577361412281379",
    fallback = "https://www.facebook.com/SleepingForLess"
)

สรุป

การเปิดหน้า Social App เพื่อให้แสดงหน้า Page หรือ Official Account ของ Social แต่ละตัวนั้นเป็นเรื่องที่อาจจะมองข้ามกันไปได้ง่ายๆ เพราะไม่ใช่เรื่องที่จะเจอกันได้บ่อยนัก

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