안녕하세요.
딥링크는 무엇이고, 안드로이드에서는 어떻게 딥링크를 구현할 수 있을 지에 대해서 설명해보려고 합니다.
우선 딥링크란 무엇일까요?
딥링크는 사용자가 특정 링크를 클릭하면 특정 앱으로 이동하거나 사용자에게 액션을 유도하는 링크를 딥링크라고 합니다.
카카오톡으로 누군가를 독려하는 메시지를 보냈다고 가정할게요.
독려 메시지에 [참여하기]라는 버튼을 클릭했을 때, 어디로 이동하셨으면 좋을 것 같나요?
앱이 존재하면 앱으로 이동하고, 앱이 존재하지 않다면 구글 플레이 스토어로 이동하기를 기대할 수 있습니다.
이처럼 딥링크를 유용하게 사용하면 마케팅에서 좋은 전략이 될 수 있습니다.
그렇다면 딥링크는 어떻게 구성되나요?
링크라고 한다면 다들 아시는 웹 사이트의 주소를 떠올릴겁니다.
딥링크도 그 주소의 구성과 유사합니다.
흔히 사용되는 구성은 위의 그림과 같습니다.
이렇게 구성을 한 이유는 여러가지 있습니다.
여러가지 이유가 더 있겠지만, 위에서 말한 이유로 위 구조를 따르게 하면 딥링크 사용 시 Android, iOS, 웹 등 다양한 플랫폼에서 동일한 규칙으로 파싱할 수 있습니다.
하지만, 여기에서도 문제점이 존재합니다.
만약 안드로이드 OS에서 같은 스킴(Scheme)을 가진 앱이 여러개 존재한다면, 무슨 앱을 열어야 하는 지 알 수 없습니다.
그래서 앱을 선택할 수 있는 UI가 나타납니다.
(iOS에서는 해결할 수 있는 방법이 없다고 합니다.)
iOS에서는 해결할 수 없고, Android 에서 특정 앱을 열 수 없다니... 그렇다면 다른 방법이 없을까요?
다른 방법이 존재합니다.
를 사용하면 됩니다.
App Link와 Universal Link는 2015년에 커스텀 스킨의 한계를 보안했고, 표준 웹링크 형태(https://www.xxx) 를 가집니다. 그렇기 때문에 이 방법으로 위에 문제들을 해결할 수 있게 됩니다.
위에서 딥링크가 무엇인지 알아봤으니, 실제로 적용해볼까요?
iOS는 진행하지 않고 Android에서 실무에서 어떻게 적용할 수 있는 지 알아보려고 합니다.
안드로이드에서 간단하게 딥링크를 테스트할 수 있는 방법은 무엇인가요?
우선, 커스텀 스킴을({scheme}://{host}) 설정해주어야 합니다.
요구사항은 다음과 같습니다.
matee://open
으로 MainActivity를 열어야 한다.그렇기 때문에 아래와 같이 AndroidManifest.xml에 intent-filter를 설정해줍니다.
<activity
android:name="com.kwanhee.example.MainActivity"
...>
<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="matee"
android:host="open"/>
</intent-filter>
</activity>
위 처럼 설정한 뒤, 애뮬레이터를 실행시킵니다.
그 이후에 터미널에 아래 명령어를 입력하면, 해당 matee 스킴을 가진 앱을 실행시키며, open 호스트 데이터를 가진 Activity를 열게 됩니다.
adb shell am start \
-a android.intent.action.VIEW \
-d "matee://open"
간단하게 커스텀 스킴을 사용하여 테스트 하는 방법입니다.
링크 전달도 다음과 같이 할 수 있습니다.
저는 슬랙이라는 메신저 툴을 사용했고, 슬랙에서 matee://app-launch 커스텀 링크를 메시지로 입력하면 하이퍼링크가 되어 등록된 앱의 커스텀 스킴이 존재한다면 이동하는 것을 알 수 있습니다.
그렇다면 해당 앱이 존재하지 않으면 어떻게 될까요?
슬랙에서는 해당 링크를 열 수 없다고 알림 메시지가 나옵니다.
그렇기 때문에 앱이 설치되지 않다면, 구글 플레이 스토어로 이동시키는 전략을 세워 앱의 다운로드를 유도해보려고 합니다.
그러기 위해서는 표준 웹링크를 사용하는 App Link 를 사용할 수 있어야 합니다.
Android에서 App Link는 어떻게 구현하나요?
우선, 안드로이드 manifest 설정은 아래와 같습니다.
딥링크와 앱링크 방식 모두 데이터로 추가해둡니다.
<activity
android:name="com.livinai.presentation.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter
android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="matee.livincare.kr" />
<data android:pathPrefix="/app-launch" /> <!-- 예: https://matee.livincare.kr/app-launch -->
</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="matee"/>
<data android:host="app-launch"/> <!-- 예: matee://app-launch -->
</intent-filter>
</activity>
Android App Link에서 사용하는 디지털 인증 에셋 JSON 파일 (assetlinks.json
)은 앱과 도메인 간의 신뢰 관계를 증명하는 핵심 요소입니다. 이 파일을 통해 Android는 “이 도메인은 이 앱에서 공식적으로 소유하고 있다”고 판단하게 되는 것입니다.
형식은 아래와 같습니다.
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "[your-package-name]",
"sha256_cert_fingerprints":
["[your-application-sha256]"]
}
}]
*구글 플레이 스토어 등록 시, sha256키 변경되니 구글 플레이 스토어 올릴 경우, sha256 키로 변경해야 합니다.
만약에 SHA256키 추출을 원한다면, 터미널에 아래 명령어를 입력해주세요!
./gradlew signingReport
이제 assetlinks.json 파일 내용을 작성하셨다면, 웹에 호스팅(게시)해야 합니다.
웹 사이트의 아래 path처럼 json 파일이 들어가 있어야 합니다.
https://[your-domain-name]/.well-known/assetlinks.json
저는 Nginx로 정적 빌드 리액트 파일을 서빙했고, 링크 접속 시 아래처럼 나오게 됩니다.
그런데 여기서 중요한 부분은 에셋 파일도 호스팅해야 한다는 부분입니다.
nginx 설정 시, 정적 파일만 서빙하면 안되고, 위처럼 .well-knwon/assetlinks.json 경로로 웹사이트 접속시 json 파일이 보여야 합니다.
server {
location / { // 웹 정적 파일 서빙
root /home/livinai/matee_front/dist;
try_files $uri $uri/ /index.html =404;
}
location /.well-known/ { // JSON Digital Asset 인증 파일 호스팅
root /home/livinai/matee_front;
try_files $uri $uri/ /index.html =404;
}
}
웹 코드도 작성해야하나요?
네 맞습니다.
저는 React + Vite 로 프로젝트를 셋팅하고 단순한 코드를 작성했습니다.
초기 셋팅하는 코드는 아래와 같습니다.
npm create vite@latest my-app -- --template react
cd my-app
npm install
그 이후, react-routing으로 라우팅 처리를 해줍니다.
npm install react-router-dom
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import AppLaunch from './pages/AppLaunch';
function App() {
return (
<div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/app-launch" element={<AppLaunch />} />
</Routes>
</div>
);
}
export default App;
최종적으로 코드를 아래처럼 작성하면 됩니다.
앱이 존재하면 앱으로 이동시키고, 앱이 존재하지 않다면 플레이 스토어로 이동시키는 로직을 작성하면 됩니다.
import { useEffect } from "react";
// src/pages/AppLaunch.jsx
const AppLaunch = () => {
// React useEffect 예시
useEffect(() => {
// 1) Intent URI 에 앱 패키지명·fallback URL·스킴 등을 한 번에 담는다
const intentUri =
'intent://app-launch#Intent;' +
'scheme=matee;' + // custom scheme
'package=com.livinai.mateeapp;' + // 앱 패키지
'S.browser_fallback_url=' +
encodeURIComponent(
'https://play.google.com/store/apps/details?id=com.livinai.mateeapp'
) + ';' +
'end';
// 2) 한 번만 리다이렉트
window.location.replace(intentUri);
}, []);
return (
<></>
);
};
export default AppLaunch;
저는 위 코드에서 Intent 스킴을 사용했습니다.
디버그에서 테스트할 때, https://matee.livincare.kr/app-launch 링크를 클릭하니 앱을 열어주지 않더라구요.. 그래서 앱으로 이동하지 않길래 추가해두었습니다.
Intent 스킴은 뭔가요?
Intent 스킴은 Android App Link가 나오기 전에 Android 웹뷰에서 사용했던 딥링크 유형입니다. iOS에서는 Intent 스킴을 사용할 수 없기 때문에 구분하는 로직이 필요할 것 같습니다.
꼭 Intent 스킴을 사용해야 하나요?
꼭 그렇지 않은 것 같습니다.
개발 환경에서는 https://matee.livincare.kr/app-launch 링크를 클릭하니 앱을 열어주지 않은 이유가 앱에서 설정을 따로 해주어야 하더라구요.
아래 처럼 앱 설정에서 등록한 웹 주소를 지원되게 허용해주어야 한다고 합니다.
![]() |
![]() |
![]() |
플레이 스토어 배포 후 설치된 앱을 확인해보니 위 웹 주소 허용이 되어있는 것을 확인했고, Intent 스킴을 사용하지 않더라도 잘 작동하는 것을 확인했습니다.
최종적으로 테스트하기 위한 설정이 완료되었다면, 아래 명령어를 터미널에 넣어주면 동작합니다.
adb shell am start -a android.intent.action.VIEW \
-c android.intent.category.BROWSABLE \
-d "https://matee.livincare.kr/app-launch"
웹링크를 클릭하더라도 https://matee.livincare.kr/app-launch 링크를 클릭해도 잘 동작합니다.
Android 앱 링크 처리하기 | App architecture | Android Developers
Android, iOS 웹뷰에서 딥링크 열기 | 토스페이먼츠 개발자센터
딥링크 실전에서 잘 사용하는 방법 | 토스페이먼츠 개발자센터
딥링크의 모든것(feat. App Link, Universal Link, Deferred DeepLink) | 헤이딜러 기술블로그