0Pricing
React Native Academy · บทเรียน

การกำหนดโครงร่าง URL แบบกำหนดเอง

กำหนดโครงร่าง URL แบบกำหนดเองใน app.json สำหรับ Expo ทดสอบการเปิดแอปจากเทอร์มินัลด้วย xcrun openurl หรือ adb และอ่าน URL เริ่มต้นเมื่อแอปเปิดทำงาน

การกำหนดโครงร่าง URL แบบกำหนดเอง เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

What Is Deep Linking?

Deep linking allows external URLs — in emails, web browsers, QR codes, or other apps — to open your React Native app and navigate directly to a specific screen rather than the home screen. This dramatically improves user experience for notifications, marketing campaigns, and cross-app flows.

There are two types of deep links: custom URL schemes (like myapp://profile/123) and universal links (like https://example.com/profile/123). This lesson covers custom URL schemes, which are simpler to set up and work on both iOS and Android.

Configuring the Scheme in app.json

In an Expo managed app, you register your custom URL scheme in app.json under the scheme key. Choose a scheme that is unique to your app — using a generic term risks conflicts with other apps. Convention is to use your app name in lowercase, like myappname.

After adding the scheme, you must rebuild the native app (run npx expo run:ios or run:android) because scheme registration requires native configuration. The scheme is read from app.json by Expo's prebuild pipeline and injected into the native project files automatically.

// app.json
{
  'expo': {
    'name': 'MyApp',
    'slug': 'my-app',
    'scheme': 'myapp',  // registers myapp:// scheme
    'ios': {
      'bundleIdentifier': 'com.example.myapp'
    },
    'android': {
      'package': 'com.example.myapp'
    }
  }
}

What Happens Under the Hood

When you define a scheme in app.json, Expo's prebuild writes the necessary native configurations:

  • iOS: adds a CFBundleURLSchemes entry in Info.plist so the system routes myapp:// URLs to your app
  • Android: adds an intent-filter in AndroidManifest.xml with action VIEW and scheme matching your custom scheme

These registrations tell the operating system that your app handles URLs of that scheme. When another app or a web page opens such a URL, the OS launches your app and passes the URL to it.

// What Expo writes to AndroidManifest.xml:
// <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' />
// </intent-filter>

Testing the URL Scheme Locally

You can test your custom URL scheme from a terminal without building a special test harness. On iOS simulator use xcrun simctl openurl booted 'myapp://profile/123'. On Android emulator use adb shell am start -W -a android.intent.action.VIEW -d 'myapp://profile/123'.

Both commands launch the app (or bring it to foreground if running) and pass the URL. This lets you verify scheme handling before integrating with actual links in other apps or web pages.

# iOS Simulator:
xcrun simctl openurl booted 'myapp://profile/123'

# Android Emulator (ADB):
adb shell am start \
  -W -a android.intent.action.VIEW \
  -d 'myapp://profile/123'

Reading the Initial URL on Launch

When the app is opened cold (not running) via a deep link, you need to read the URL that triggered the launch. Use Linking.getInitialURL() from React Native's built-in Linking module. It returns a Promise that resolves with the URL string or null if the app launched normally.

Call this in a useEffect with an empty dependency array so it runs once on mount. Parse the URL to extract the route and navigate accordingly once the navigation stack is ready.

import { Linking } from 'react-native';
import { useEffect } from 'react';

useEffect(() => {
  Linking.getInitialURL().then((url) => {
    if (url) {
      console.log('App opened via URL:', url);
      // Parse and navigate
      handleDeepLink(url);
    }
  }).catch((err) => {
    console.error('getInitialURL error:', err);
  });
}, []);

Handling Links While App Is Running

When the app is already running and a deep link URL opens it, getInitialURL() returns null. Instead, you need to subscribe to URL events using Linking.addEventListener('url', callback). This fires whenever a new URL arrives while the app is in the foreground or background.

Always remove the event listener in the cleanup function returned from useEffect to prevent memory leaks. Both the initial URL check and the event listener should call the same URL handler for consistency.

useEffect(() => {
  // Cold launch:
  Linking.getInitialURL().then((url) => {
    if (url) handleDeepLink(url);
  });

  // While running:
  const subscription = Linking.addEventListener('url', ({ url }) => {
    handleDeepLink(url);
  });

  return () => subscription.remove(); // cleanup
}, []);

Parsing Deep Link URLs

The URL you receive is a raw string like myapp://profile/123?tab=posts. Parse it using the URL Web API (available in React Native via the Hermes runtime) or a helper library. Extract the pathname to determine the screen and query parameters for additional data.

A simple approach for basic deep links: split the URL on :// to get the path, then split the path on / to get segments. For query params, use URLSearchParams.

function handleDeepLink(url) {
  // url = 'myapp://profile/123?tab=posts'
  const parsed = new URL(url);
  // parsed.hostname = 'profile'
  // parsed.pathname = '/123'
  // parsed.searchParams.get('tab') = 'posts'

  const screen = parsed.hostname;
  const id = parsed.pathname.replace('/', '');
  const tab = parsed.searchParams.get('tab');

  if (screen === 'profile') {
    navigation.navigate('Profile', { id, tab });
  }
}

Multiple URL Scheme Support

An app can register multiple URL schemes — for example, one for production use (myapp://) and one for development/staging (myapp-dev://). In Expo you define the primary scheme in the top-level scheme field; additional schemes require a config plugin to add extra intent-filters to AndroidManifest and additional CFBundleURLSchemes entries to Info.plist.

Separate schemes per environment prevent staging deep links from accidentally opening the production app on the same device during QA testing.

// app.json - single scheme (managed):
{
  'expo': {
    'scheme': 'myapp'
  }
}

// For multiple schemes, use a config plugin:
// withMySchemes.js
const { withAndroidManifest } = require('@expo/config-plugins');
module.exports = (config) =>
  withAndroidManifest(config, (config) => {
    // Add extra intent-filters to main activity
    return config;
  });

Scheme Conflicts and Best Practices

Custom URL schemes are not globally registered — any app can claim the same scheme, and on iOS if two apps share a scheme the most recently installed one wins. This is why custom schemes are not suitable for security-sensitive flows like OAuth callbacks where you need to guarantee which app receives the redirect.

Best practices for custom schemes: use a reverse-domain format (com.yourcompany.yourapp://), keep the scheme in your app name format, and for anything security-sensitive (OAuth, payment callbacks) use universal links (HTTPS URLs) instead.

// Avoid generic schemes:
// 'app://' or 'mobile://' — easily conflicts

// Better: reverse domain or unique name:
// 'com.acme.myapp://'
// 'acmemyapp://'

// In app.json:
{
  'expo': {
    'scheme': 'acmemyapp'
  }
}

Opening Other Apps' URL Schemes

Your app can also open other apps via their URL schemes using Linking.openURL(url). Call Linking.canOpenURL(url) first to check if the scheme is available on the device. Use this to open maps, email, phone dialer, or other apps from within your app.

On iOS, you must declare any schemes your app opens in the LSApplicationQueriesSchemes array in Info.plist — otherwise canOpenURL always returns false. Expo config plugins or the ios.infoPlist key in app.json handle this.

import { Linking } from 'react-native';

async function openMaps(address) {
  const url = 'maps://0,0?q=' + encodeURIComponent(address);
  const supported = await Linking.canOpenURL(url);
  if (supported) {
    await Linking.openURL(url);
  } else {
    // Fallback to Google Maps web:
    await Linking.openURL(
      'https://maps.google.com/?q=' + encodeURIComponent(address)
    );
  }
}

Debugging Deep Link Issues

Common deep link problems and their solutions:

  • URL not received — check scheme is in app.json and the native app was rebuilt after adding it.
  • getInitialURL returns null — add a listener too; sometimes the URL arrives as an event even for cold launches on certain OS versions.
  • Navigation not working — ensure navigation is ready before calling navigate; use a ref to the navigator with onReady.
  • Android emulator ADB test fails — verify the correct package name and that the app is installed.

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: the scheme key in app.json registers a custom URL scheme that routes URLs to your app on both iOS and Android, Linking.getInitialURL() reads the URL that launched the app cold, and Linking.addEventListener handles deep link URLs while the app is already running. Next up we use the Linking API to parse incoming URLs and dispatch navigation actions.

คำถามที่พบบ่อย

บทเรียน “การกำหนดโครงร่าง URL แบบกำหนดเอง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การกำหนดโครงร่าง URL แบบกำหนดเอง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การกำหนดโครงร่าง URL แบบกำหนดเอง”

กำหนดโครงร่าง URL แบบกำหนดเองใน app.json สำหรับ Expo ทดสอบการเปิดแอปจากเทอร์มินัลด้วย xcrun openurl หรือ adb และอ่าน URL เริ่มต้นเมื่อแอปเปิดทำงาน คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การกำหนดโครงร่าง URL แบบกำหนดเอง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การกำหนดโครงร่าง URL แบบกำหนดเอง
  2. API สำหรับการเชื่อมโยงและการแยกวิเคราะห์ URL
  3. การกำหนดค่า Deep Link ของ React Navigation
  4. Universal Links (Deep Link ผ่าน HTTPS) บน iOS และ Android
← กลับไปที่ React Native Academy