Expo 외부 앱으로 연결 Deep Linking 방법 (길찾기, 유튜브 등)

2025. 1. 15. 21:19·🔍 Tech 🔍/Front-End
expo deep linking

앱을 구현하다 보면 다른 앱으로 연결을 해야 할 때가 있습니다.

1. 전화 / 문자
2. 인스타그램 프로필  / 페이스북 페이지 열기
3. 지도앱으로 길찾기
4. 카카오톡으로 공유하기

 

1. Linking

그때 Expo에서 사용하는 메서드가 Linking입니다.
https://reactnative.dev/docs/linking

Linking · React Native

Linking gives you a general interface to interact with both incoming and outgoing app links.

reactnative.dev

사용법은 간단합니다. 특정 웹 페이지를 열고 싶다면 아래와 같이 작성하면 되고

Linking.openURL("https://www.google.com")

앱의 설정 페이지로 이동하고 싶다면 모두 Linking 메서드를 사용하면 됩니다.

Linking.openSettings()
https://reactnative.dev/docs/linking#built-in-url-schemes

2. 네이버 지도 길찾기

전화 - tel://
문자 - sms://
네이버지도 - nmap://

Linking을 할 때 가장 앞에 적는 것이 URL Schemes인데 어떤 앱으로 연결할지 지정할 수 있습니다.

https://guide.ncloud-docs.com/docs/maps-url-scheme

https://guide.ncloud-docs.com/docs/maps-url-scheme
 
공식문서를 참고한 네이버 지도 길찾기 기능 예제입니다.

import {
  StyleSheet,
  Platform,
  View,
  Linking,
  Pressable,
  Text,
} from "react-native";

export default function HomeScreen() {
  // 길찾기 앱 열기
  const openNmap = async () => {
    // 현재 위치 예시
    const location = {
      coords: {
        latitude: 37.55316386899907,
        longitude: 126.97272605295855,
      },
      name: "서울역",
    };

    // 목적지 위치 예시
    const destination = {
      coords: {
        latitude: 37.51380325278886,
        longitude: 127.10204823010712,
      },
      name: "잠실역",
    };

    // 네이버 지도 길찾기 url
    const naverMapUrl = `nmap://route/public?slat=${location.coords.latitude}&slng=${location.coords.longitude}&sname=${location.name}&dlat=${destination.coords.latitude}&dlng=${destination.coords.longitude}&dname=${destination.name}`;

    // 네이버 지도 앱이 설치되어 있는지 확인
    Linking.canOpenURL(naverMapUrl).then((supported) => {
      console.log(supported);
      if (supported) {
        // 설치되어 있다면 네이버 지도 앱 열기
        Linking.openURL(naverMapUrl);
      } else {
        // 설치되어 있지 않다면 앱스토어로 이동
        if (Platform.OS === "android") {
          Linking.openURL("market://details?id=com.nhn.android.nmap");
        } else if (Platform.OS === "ios") {
          Linking.openURL("https://apps.apple.com/kr/app/id311867728");
        }
      }
    });
  };

  return (
    <View style={styles.container}>
      <Pressable onPress={openNmap} style={styles.btn}>
        <Text>Open Naver Map</Text>
      </Pressable>
    </View>
  );
}

 
canOpenURL 메서드를 통해 해당 디바이스에 네이버 지도 앱이 설치되어 있는지 우선 확인합니다.
설치되어 있을 경우 해당 URL을 통해 길찾기 기능이 연동되고, 설치가 되어있지 않다면 스토어로 이동합니다.
 
하지만 위 기능에는 한 가지 추가해야 할 작업이 있습니다.
해당 코드만으로 길찾기가 잘 되는 경우는 Android 11 (API30) 미만 버전인 경우입니다. 11 이상인 경우엔 지도 앱이 설치되어 있더라도 스토어로 이동합니다.

Android 11 이상

3. AndroidManifest.xml intent 추가

Android 11 버전 이후부턴 개인정보 보호를 위해 외부 앱을 호출하는 행위를 제한하는 보안 정책이 도입됐습니다.
따라서 외부 앱을 열 때 queries와 intent를 추가해주어야 합니다.
 
네이티브 코드인 AndroidManifest를 수정해야 하니 prebuild를 우선 해야 합니다.

npx expo prebuild

prebuild를 한 후엔 AndroidManifest.xml 파일을 찾아 수정해 줍니다.

android > app > src > main > AndroidManifest.xml

 

      <intent-filter data-generated="true">
        <action android:name="android.intent.action.VIEW"/>
        <data android:scheme="nmap"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>

외부 앱인 네이버 지도와 상호작용 하기 위해 네이버 지도의 패키지 이름, intent 동작 또는 스키마를 명시해 주어 길찾기 기능이 되도록 추가해야 합니다.

  <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
    <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
    <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
      <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"/>
        <data android:scheme="com.yeonhub.linking"/>
      </intent-filter>
      <intent-filter data-generated="true">
        <action android:name="android.intent.action.VIEW"/>
        <data android:scheme="nmap"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    </activity>
  </application>

서버 종료 후 앱을 다시 실행시키면 길찾기 기능이 정상적으로 동작합니다.

npx expo run

 

⚠️ 빌드 시 AndroidManifest에 코드를 수정하는 방법은 두 가지가 있는데, 비교적 간단한 4번 app.json 방식을 추천합니다.

 

4. 프로덕트 버전 (app.json) - 추천

AndroidManifest에 nmap을 추가하기 위해 app.json을 수정해야 합니다.

      "intentFilters": [
        {
          "action": "VIEW",
          "data": [
            {
              "scheme": "nmap"
            }
          ],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
app.json > expo > android

위 경로에 맞게 추가해 주세요.

.
.
.
"android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "com.yeonhub.linking",
      "intentFilters": [
        {
          "action": "VIEW",
          "data": [
            {
              "scheme": "nmap"
            }
          ],
          "category": ["BROWSABLE", "DEFAULT"]
        }
      ]
    },
    .
    .
    .

이제 prebuild, build 시에도 intent-finter가 추가되게 됩니다.
AndroidManifest에서 해당 코드를 지우고 prebuild로 테스트해 보시기 바랍니다.


 

⚠️ 4. 프로덕트 버전 (app.json) - 추천과 같은 기능을 하는 설정입니다. 해당 작업을 하지 않은 분만 진행해 주세요.

 

5. 프로덕트 버전 (config-plugins)

AndroidManifest에 직접 수정을 하는 방식은 개발 단계에서만 가능합니다.
만약 프로덕트 버전으로 빌드를 하게 되면, AndroidManifest에는 해당 intent가 없게 됩니다.
 
빌드 시에도 네이티브 코드를 수정하고 싶다면 expo에서 제공 중인 config-plugins를 사용해야 합니다.
https://github.com/expo/config-plugins

GitHub - expo/config-plugins: Out-of-tree Expo config plugins for packages that haven't adopted the config plugin system yet.

Out-of-tree Expo config plugins for packages that haven't adopted the config plugin system yet. - expo/config-plugins

github.com

 

config-plugin.js

루트 경로에 config-plugin.js 파일을 생성합니다. (파일명은 다른 것으로 변경해도 무방합니다.)

const { withAndroidManifest } = require("expo/config-plugins");

const withAndroidQueries = (config) => {
  return withAndroidManifest(config, (config) => {
    const queries = config.modResults.manifest.queries || [];

    const newIntents = [
      {
        action: "android.intent.action.VIEW",
        data: "nmap",
      },
    ];

    newIntents.forEach(({ action, category, data }) => {
      const intentExists = queries.some((q) =>
        q.intent?.some(
          (intent) =>
            intent.action?.[0]?.$["android:name"] === action &&
            intent.data?.[0]?.$["android:scheme"] === data
        )
      );

      if (!intentExists) {
        const newIntent = {
          action: [{ $: { "android:name": action } }],
          data: [{ $: { "android:scheme": data } }],
        };

        if (category) {
          newIntent.category = [{ $: { "android:name": category } }];
        }

        queries.push({ intent: [newIntent] });
      }
    });

    config.modResults.manifest.queries = queries;

    return config;
  });
};

module.exports = withAndroidQueries;

본 예제에서 사용하는 네이버 지도의 queries - intent를 추가하는 코드입니다.
빌드 시 중복되지 않도록 하는 내용이 추가되어 있습니다.
 
config 실행 파일을 생성했으면 prebuild 혹은 build 시 실행할 수 있도록 app.json 파일에 명시해주어야 합니다.

    .
    .
    .
    "plugins": [
      "expo-router",
      [
        "expo-splash-screen",
        {
          "image": "./assets/images/splash-icon.png",
          "imageWidth": 200,
          "resizeMode": "contain",
          "backgroundColor": "#ffffff"
        }
      ],
      "./config-plugin.js"
    ],
    .
    .
    .
app.json > expo > plugins

 
이제 AndroidManifest에서 해당 코드를 지우고 prebuild를 해봅시다.
prebuild 성공 후 똑같이 코드가 추가되었다면 성공한 것입니다.


6. 유튜브, 카카오톡 공유

유튜브의 경우 별도의 URL scheme를 사용하지 않습니다. 따라서 https로 linking이 가능합니다.

const openYoutube = async () => {
    // 유튜브 검색어
    const input = "react native expo";
    // 유튜브 검색어를 URL 인코딩
    const encodedInput = encodeURIComponent(input);
    // 유튜브 앱 검색 URL
    const youtubeSearchUrl = `https://www.youtube.com/results?search_query=${encodedInput}`;

    await Linking.openURL(youtubeSearchUrl);
  };

위 함수를 추가하여 버튼에 할당하면 유튜브 앱이 열리고 "react native expo"를 검색하게 됩니다.
 
카카오톡 공유나 메세지의 경우 공식문서에 자세히 나와있으니 확인해 보시기 바랍니다.
Android 11 이상에서 queries, intent를 추가하는 것은 똑같습니다.
https://developers.kakao.com/docs/latest/ko/message/android-link

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com


이번 포스팅에서 사용한 네이버 지도 외에도 다른 앱들이 URL scheme를 지원하고 있으므로 원하는 앱이 있으면 추가해 보시길 바랍니다.
 
본 포스팅 예제 코드는 아래 리포지토리에 업로드하였습니다.

⚠️ 전체 예제 코드를 사용할 경우 app.json 파일명이 app4.json, app5.json으로 되어있습니다. 4.app.json 방식과  5. config-plugin 방식 중 원하는 방식으로 선택 해 app.json으로 파일명 수정 후 사용하시기 바랍니다.

* 4번 방식 사용 시 루트 경로에 config-plugin.js 파일은 필요 없게 됩니다.

 
https://github.com/yeonhub/yeonhub-post/tree/linking

GitHub - yeonhub/yeonhub-post

Contribute to yeonhub/yeonhub-post development by creating an account on GitHub.

github.com

 

'🔍 Tech 🔍/Front-End' 카테고리의 다른 글
  • React Native Expo Firebase Analytics 추가 하기
  • React Native Firebase Analytics 추가 하기
  • React Native Expo FCM 푸시 알림 설정
  • React Native Expo google map 지도 구현 방법
Yeonhub
Yeonhub
✨ https://github.com/yeonhub 📧 lsy3237@gmail.com
  • Yeonhub
    비 전공자의 Be developer
    Yeonhub
  • 전체
    오늘
    어제
    • 전체보기 (169)
      • 🔍 Tech 🔍 (19)
        • Front-End (11)
        • Back-End (4)
        • AI (1)
        • Server (1)
        • Etc (2)
      • 💡 원티드 프리온보딩 챌린지 💡 (14)
        • PRE-ONBOARDING_AI (11월) (1)
        • PRE-ONBOARDING_FE (2월) (2)
        • PRE-ONBOARDING_FE (1월) (2)
        • PRE-ONBOARDING_FE (12월) (9)
      • 🔥 부트캠프-웹 개발 🔥 (118)
        • HTML5 (7)
        • CSS3 (21)
        • JavaScript (27)
        • JavaScript_advanced (9)
        • React (24)
        • Next (1)
        • MYSql (5)
        • Node (5)
        • 오늘하날(개인프로젝트) (12)
        • 이젠제주투어(팀프로젝트) (7)
      • 💻 CS 💻 (1)
        • 알고리즘 (1)
      • ⚡ 코딩테스트 ⚡ (11)
        • JavaScript (11)
      • 📚 Books 📚 (6)
        • 클린 아키텍처 (2)
        • 인사이드 자바스크립트 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    rn admob
    라스콘4
    php node
    프론트엔드 테스트코드
    expo fcm push
    node fcm
    expo node fcm
    expo 길찾기
    expo 지도
    라스콘
    javascript fcm
    expo google map
    react native analytics
    expo fcm
    rn bottom sheet
    node cron
    node.js fcm
    react vite
    expo deep linking
    expo admob
    react native firebase analytics
    Node
    bottom sheet
    node crontab
    react native expo fcm
    python node
    react native bottom sheet
    컴파운드 컴포넌트 패턴
    expo map
    react native admob
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Yeonhub
Expo 외부 앱으로 연결 Deep Linking 방법 (길찾기, 유튜브 등)
상단으로

티스토리툴바