
앱을 구현하다 보면 다른 앱으로 연결을 해야 할 때가 있습니다.
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()

2. 네이버 지도 길찾기
전화 - tel://
문자 - sms://
네이버지도 - nmap://
Linking을 할 때 가장 앞에 적는 것이 URL Schemes인데 어떤 앱으로 연결할지 지정할 수 있습니다.

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 이상인 경우엔 지도 앱이 설치되어 있더라도 스토어로 이동합니다.

3. AndroidManifest.xml intent 추가
Android 11 버전 이후부턴 개인정보 보호를 위해 외부 앱을 호출하는 행위를 제한하는 보안 정책이 도입됐습니다.
따라서 외부 앱을 열 때 queries와 intent를 추가해주어야 합니다.
네이티브 코드인 AndroidManifest를 수정해야 하니 prebuild를 우선 해야 합니다.
npx expo prebuild
prebuild를 한 후엔 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 파일을 생성합니다. (파일명은 다른 것으로 변경해도 무방합니다.)
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