
Google Firebase Dynamic Links는 2025년 8월 25일에 중단되기 때문에 대체안인 “AppsFlyer”를 찾았습니다.
AppsFlyer는 기본적으로 모바일 앱 마케팅 및 광고 성과 분석을 위한 모바일 측정하기 위한 솔루션입니다.
딥링크란 사용자를 일반적인 앱 홈페이지나 모바일 웹사이트가 아닌 앱 내부의 특정 위치로 직접 연결하는 것을 말합니다.
딥링크는 일반 웹 링크와 매우 유사한 방식으로 작동하며, 클릭하면 웹사이트 내의 기사나 페이지로 이동합니다. 차이점은 모바일에서는 이러한 링크가 앱 내부의 콘텐츠로 이동한다는 점입니다.
AppsFlyer 딥링크는 앱에 AppsFlyer SDK를 설치하고 딥 링크를 이용해 앱의 특정 화면으로 이동할 수 있습니다.
Firebase Dynamic Links를 대체할 수 있는 딥링크 솔루션은 여러 있지만 그 중에서 AppsFlyer를 선택한 이유는 토스를 이용할 때 토스에서 카톡 알림이 오는 경우 링크를 클릭하면 *.onelink.me라는 도메인을 사용하고 있어서 그것에 대해 찾아보니 아래에 대한 정보입니다.
새로나온 수파링크라는 것도 있는데 한국인이 만든 솔루션입니다. 이것도 무료라서 가볍게 사용하기에 좋아보입니다.
Supalink - The Perfect Alternative to Firebase Dynamic Links
Deep linking | AppsFlyer mobile glossary
npx @react-native-community/cli@latest init appsflyer_deep_link_app
// package.json
"dependencies": {
"react": "19.0.0",
"react-native": "0.78.0"
},
// android/gradle.properties
newArchEnabled=false
// ios/Podfile
ENV['RCT_NEW_ARCH_ENABLED'] = '0' // 최상단에 위치
...
Getting started | React Navigation
yarn add @react-navigation/native
yarn add react-native-screens react-native-safe-area-context
yarn add @react-navigation/native-stack
yarn add @react-navigation/elements
yarn add -D babel-plugin-module-resolver
// package.json
"dependencies": {
"@react-navigation/native": "^7.0.15",
"@react-navigation/native-stack": "^7.2.1",
"react": "19.0.0",
"react-native": "0.78.0",
"react-native-safe-area-context": "^5.3.0",
"react-native-screens": "^4.9.1"
},
"devDependencies": {
"babel-plugin-module-resolver": "^5.0.2",
}
// android/app/src/main/java/com/appsflyer_deep_link_app/MainActivity.kt
package com.appsflyer_deep_link_app
import android.os.Bundle // add this
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
class MainActivity : ReactActivity() {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "appsflyer_deep_link_app"
// add this
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(null)
}
/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}
// babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['.'],
extensions: [
'.ios.ts',
'.android.ts',
'.ts',
'.ios.tsx',
'.android.tsx',
'.tsx',
'.jsx',
'.js',
'.json',
],
alias: {
'@screens': './src/screens',
'@utils': './src/utils',
'@hooks': './src/hooks',
'@typings': './src/typings',
'@components': './src/components',
'@config': './config/config.json',
},
},
],
],
};
// tsconfig.json
{
"extends": "@react-native/typescript-config/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@screens/*": ["src/screens/*"],
"@utils/*": ["src/utils/*"],
"@hooks/*": ["src/hooks/*"],
"@typings/*": ["src/typings/*"],
"@components/*": ["src/components/*"],
"@config": ["config/config.json"]
}
}
}
// src/typings/navigation.ts
import type {NativeStackScreenProps} from '@react-navigation/native-stack';
export type RootStackNavigatorTypes = {
Home: undefined;
DeepLink: {
id: string;
};
};
export type DeepLinkScreenProps = NativeStackScreenProps<
RootStackNavigatorTypes,
'DeepLink'
>;
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackNavigatorTypes {}
}
}
// src/utils/consts.ts
import type {LinkingOptions} from '@react-navigation/native';
import type {RootStackNavigatorTypes} from '@typings/navigation';
export const NAVIGATION_LINKS = {
HOME: '/home',
DEEP_LINK: '/deep-link',
} as const;
export const navigationLinking: LinkingOptions<RootStackNavigatorTypes> = {
prefixes: ['appsflyer-deep-link://'],
config: {
screens: {
Home: NAVIGATION_LINKS.HOME,
DeepLink: {
path: `${NAVIGATION_LINKS.DEEP_LINK}/:id`,
parse: {
id: String,
},
},
},
},
};
Configuring links | React Navigation
// src/App.tsx
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import DeepLinkScreen from '@screens/DeepLink';
import HomeScreen from '@screens/Home';
import {RootStackNavigatorTypes} from '@typings/navigation';
import {navigationLinking} from '@utils/consts';
const RootStack = createNativeStackNavigator<RootStackNavigatorTypes>();
function App() {
return (
<NavigationContainer linking={navigationLinking}>
<RootStack.Navigator initialRouteName="Home">
<RootStack.Screen name="Home" component={HomeScreen} />
<RootStack.Screen name="DeepLink" component={DeepLinkScreen} />
</RootStack.Navigator>
</NavigationContainer>
);
}
export default App;
// src/screens/Home.tsx
import type {FC} from 'react';
import {SafeAreaView, Text, View} from 'react-native';
const HomeScreen: FC = () => {
return (
<SafeAreaView>
<View>
<Text>Home Screen</Text>
</View>
</SafeAreaView>
);
};
export default HomeScreen;
// src/screens/DeepLink.tsx
import {DeepLinkScreenProps} from '@typings/navigation';
import type {FC} from 'react';
import {SafeAreaView, Text, View} from 'react-native';
const DeepLinkScreen: FC<DeepLinkScreenProps> = ({route}) => {
return (
<SafeAreaView>
<View>
<Text>DeepLink Screen</Text>
<Text>deep link id: {route.params?.id || 'empty'}</Text>
</View>
</SafeAreaView>
);
};
export default DeepLinkScreen;
npx pod-install ios
yarn start
yarn ios
[RN CheatSheet] New architecture 비활성화 하기
Deep linking | AppsFlyer mobile glossary
Getting started | React Navigation
Configuring links | React Navigation
react native appsflyer deep link 완벽 가이드 - 초기 설정 (1) - 현재
react native appsflyer deep link 완벽 가이드 - SDK 설치 (2)
react native appsflyer deep link 완벽 가이드 - OneLink (3)
react native appsflyer deep link 완벽 가이드 - 코드 (4)