본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

การใช้ Deep Linking ใน Flutter

บทความนี้แนะนำ Deep Linking ใน Flutter ซึ่งเป็นวิธีการเปิดแอปพลิเคชันโดยตรงจากลิงก์ภายนอก โดยใช้ URI เพื่อนำทางผู้ใช้ไปยังหน้าเฉพาะเจาะจงภายในแอปพลิเคชัน และต้อ...

การใช้ Deep Linking ใน Flutter: เปิดแอปจาก Link ภายนอก

ในบทความก่อนหน้า เราได้พูดถึง Code Push ซึ่งเป็นวิธีที่ช่วยให้เราอัปเดตแอปพลิเคชัน Flutter ได้อย่างรวดเร็วโดยไม่ต้องผ่านกระบวนการ Release ใหม่บน Store ต่างๆ ในบทความนี้ เราจะมาสำรวจอีกหนึ่งฟีเจอร์ที่สำคัญไม่แพ้กัน นั่นคือ Deep Linking ซึ่งจะช่วยให้ผู้ใช้สามารถเปิดแอปพลิเคชันของเราได้โดยตรงจากลิงก์ภายนอก ไม่ว่าจะเป็นจากเว็บไซต์, อีเมล, หรือแอปพลิเคชันอื่นๆ

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

Deep Linking คืออะไร?

Deep Linking คือการสร้างลิงก์ที่สามารถนำผู้ใช้ไปยังหน้าเฉพาะเจาะจงภายในแอปพลิเคชันได้โดยตรง ต่างจาก Universal Link (iOS) และ App Links (Android) ที่ต้องมีการยืนยันความเป็นเจ้าของ Domain name ก่อน Deep Link จะทำงานได้ทันที แต่ก็มีข้อจำกัดเรื่องความน่าเชื่อถือมากกว่า (เช่น หากไม่มีแอปติดตั้ง ลิงก์อาจเปิดใน Browser แทน)

เมื่อผู้ใช้คลิกลิงก์ Deep Link ระบบปฏิบัติการจะตรวจสอบว่ามีแอปพลิเคชันที่สามารถจัดการลิงก์นั้นได้หรือไม่ หากมี ระบบก็จะเปิดแอปพลิเคชันไปยังหน้าที่ระบุไว้ในลิงก์นั้น

Uri: หัวใจสำคัญของ Deep Linking

Deep Linking ทำงานโดยอาศัย Uniform Resource Identifier (URI) ซึ่งเป็น String ที่ใช้ระบุแหล่งข้อมูล (Resource) บนอินเทอร์เน็ต หรือในที่นี้คือหน้าต่างๆ ภายในแอปพลิเคชันของเรา URI ประกอบด้วยส่วนประกอบต่างๆ ดังนี้:

  • Scheme: ระบุโปรโตคอลที่ใช้ในการเข้าถึง Resource (เช่น http, https, myapp)
  • Authority: ระบุชื่อ Domain หรือชื่อ Host ของ Resource (เช่น www.example.com)
  • Path: ระบุตำแหน่งของ Resource ภายใน Authority (เช่น /products/123)
  • Query: ระบุพารามิเตอร์เพิ่มเติมที่ใช้ในการเข้าถึง Resource (เช่น ?color=red&size=large)
  • Fragment: ระบุส่วนย่อยของ Resource ที่ต้องการเข้าถึง (เช่น #section2)

ตัวอย่าง URI สำหรับ Deep Linking ในแอปพลิเคชันของเรา:

myapp://products/123?color=red&size=large

ในตัวอย่างนี้:

  • myapp คือ Scheme ที่เรากำหนดเองสำหรับแอปพลิเคชันของเรา
  • products/123 คือ Path ที่ระบุว่าเราต้องการไปยังหน้าสินค้าที่มี ID เป็น 123
  • color=red&size=large คือ Query ที่ระบุพารามิเตอร์เพิ่มเติม เช่น สีและขนาดของสินค้า

Link Handling ใน Flutter

ในการใช้งาน Deep Linking ใน Flutter เราจะต้องทำการ Config แอปพลิเคชันของเราให้สามารถจัดการกับ URI ที่เรากำหนดได้ ซึ่งมีขั้นตอนหลักๆ ดังนี้:

  1. กำหนด Scheme: เลือก Scheme ที่เหมาะสมสำหรับแอปพลิเคชันของเรา (เช่น ชื่อแอปพลิเคชัน หรือชื่อ Domain ของเรา)
  2. Config Platform-Specific Settings:
    • Android: แก้ไขไฟล์ AndroidManifest.xml เพื่อระบุ intent-filter ที่จะจัดการกับ Scheme ของเรา
    • iOS: แก้ไขไฟล์ Info.plist เพื่อระบุ CFBundleURLTypes ที่จะจัดการกับ Scheme ของเรา
  3. Implement Link Handling Logic: เขียน Code ใน Flutter เพื่อดึงข้อมูลจาก URI และนำผู้ใช้ไปยังหน้าที่ถูกต้องภายในแอปพลิเคชัน

ตัวอย่าง Code

ต่อไปนี้เป็นตัวอย่าง Code ที่แสดงวิธีการ Implement Link Handling Logic ใน Flutter:

import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String? _latestLink = 'Unknown';
  String? _latestUri;

  @override
  void initState() {
    super.initState();
    _initURIHandler();
    _incomingLinkHandler();
  }

  Future<void> _initURIHandler() async {
    if (!mounted) return;

    try {
      final initialUri = await getInitialUri();
      if (initialUri == null) {
        print('No initial URI received');
      } else {
        _latestUri = initialUri.toString();
        _latestLink = 'Initial URI: $_latestUri';
        print('Initial URI received: $_latestUri');
        // TODO: Parse the URI and navigate to the correct screen
      }
    } on PlatformException {
      print('Failed to receive initial URI');
    } on FormatException catch (err) {
      print('Malformed Initial URI received: ${err.message}');
    }

    if (!mounted) return;

    setState(() {});
  }

  Future<void> _incomingLinkHandler() async {
    if (!mounted) return;

    uriLinkStream.listen((Uri? uri) {
      if (!mounted) return;
      print('Received URI: $uri');
      setState(() {
        _latestUri = uri.toString();
        _latestLink = 'Received URI: $_latestUri';
      });
      // TODO: Parse the URI and navigate to the correct screen
    }, onError: (Object err) {
      if (!mounted) return;
      print('Error occurred: $err');
      setState(() {
        _latestUri = 'Failed to get latest URI: $err.';
        _latestLink = 'Error: $_latestUri';
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Deep Linking Example'),
        ),
        body: Center(
          child: Text('Latest Link: $_latestLink\n\nLatest URI: $_latestUri'),
        ),
      ),
    );
  }
}

คำอธิบาย Code:

  • เราใช้ Package uni_links เพื่อจัดการกับ Deep Links
  • _initURIHandler() ใช้เพื่อดึง URI เมื่อแอปพลิเคชันถูกเปิดจาก Deep Link เป็นครั้งแรก
  • _incomingLinkHandler() ใช้เพื่อรับ URI เมื่อแอปพลิเคชันถูกเปิดจาก Deep Link ในขณะที่แอปพลิเคชันกำลังทำงานอยู่แล้ว
  • ใน setState() เรา Update State เพื่อแสดง URI ล่าสุดบนหน้าจอ
  • TODO: ส่วนที่ต้อง Implement เพิ่มเติมคือการ Parse URI และนำผู้ใช้ไปยังหน้าที่ถูกต้องภายในแอปพลิเคชัน

Android Configuration (AndroidManifest.xml)

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"> <!-- Important: set launchMode to singleTask -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" /> <!-- Replace with your scheme -->
    </intent-filter>
</activity>

iOS Configuration (Info.plist)

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myapp</string> <!-- Replace with your scheme -->
        </array>
        <key>CFBundleURLName</key>
        <string>com.example.myapp</string> <!-- Replace with your bundle identifier -->
    </dict>
</array>

ข้อควรระวังและแนวปฏิบัติที่ดี

  • Security: ตรวจสอบและ Validate ข้อมูลที่ได้รับจาก URI อย่างระมัดระวัง เพื่อป้องกันการโจมตี Cross-Site Scripting (XSS) หรือ SQL Injection
  • Error Handling: จัดการกับกรณีที่ URI ไม่ถูกต้อง หรือไม่สามารถนำผู้ใช้ไปยังหน้าที่ต้องการได้
  • User Experience: สร้างประสบการณ์ผู้ใช้ที่ราบรื่นและเป็นธรรมชาติ เมื่อผู้ใช้เปิดแอปพลิเคชันจาก Deep Link
  • Testing: ทดสอบ Deep Linking อย่างละเอียดบนอุปกรณ์และระบบปฏิบัติการต่างๆ
  • Deferred Deep Linking: พิจารณาใช้ Deferred Deep Linking เพื่อให้ผู้ใช้ไปยังหน้าที่ต้องการได้ แม้ว่าพวกเขาจะยังไม่ได้ติดตั้งแอปพลิเคชัน (ซึ่งต้องใช้ third-party service)

สรุป

Deep Linking เป็นเครื่องมือที่มีประสิทธิภาพในการปรับปรุงประสบการณ์ผู้ใช้และเพิ่มประสิทธิภาพทางการตลาดของแอปพลิเคชัน Flutter ของเรา การเข้าใจหลักการทำงานของ URI และการ Implement Link Handling Logic อย่างถูกต้อง จะช่วยให้เราสามารถสร้าง Deep Links ที่มีประโยชน์และใช้งานง่ายได้

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

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기