Skip to main content

Node.js로 Firebase Dynamic Link 다루기

· 16 min read
김현섭

안녕하세요, 비브로스 백엔드팀에 새로 합류하게 된 김현섭입니다.

비브로스 백엔드팀은 신규 입사자를 위한 온보딩 프로세스가 준비되어 있고, 해당 과정에는 기술 스택 학습 및 모의 프로젝트 등 다양한 과정이 포함되어 있습니다.

저는 모의 프로젝트 대신 서버에 Dynamic Link 관련 API를 추가하는 간단한 업무를 맡게 되었고, 이 글을 통해 해당 과정에서 사용한 Dynamic Link를 소개하려고 합니다.


Dynamic Link는 Firebase에서 제공하는 기능으로, 플랫폼 및 앱 설치 여부와 관계없이 앱 내부의 특정 콘텐츠로 유저를 바로 랜딩시킬 수 있는 링크입니다.

앱이 설치되어 있다면 유저를 바로 최종 목적지로 랜딩시키고,
앱이 설치되어 있지 않다면 스토어로 이동 -> 앱 설치가 완료된 이후에 유저를 목적지로 랜딩시킵니다.

이 링크는 Firebase Console 또는 REST API 방식으로 생성할 수 있고, 생성된 링크에 대해 클릭 횟수 및 앱 설치 횟수 등의 통계 확인 또한 가능합니다.

기존에 Deep Link를 접해보셨던 분들은 익숙한 개념이실 텐데요, 먼저 본격적인 내용에 들어가기 전에 Dynamic Link와 Deep Link의 개념에 대해 간단히 살펴보겠습니다.

Dynamic Link는 Deep Link를 포함하는 포괄적인 개념으로, 기존의 Deep Link (Deferred Deep Link)가 가진 단점을 보완한 기술입니다.

Deep Link 기술에 대한 히스토리는 크게 세 단계로 나눌 수 있습니다.

  • 초기의 Deep Link는 유저를 특정 콘텐츠로 랜딩시킬 수는 있었지만, 앱 설치가 안 된 상태라면 설치 과정에서 Deep Link 정보가 유실되었습니다.
  • 이를 해결하기 위해 Deferred Deep Link의 개념이 등장하게 되었고, 이는 앱 설치 이후에도 Deep Link의 정보를 유지시킴으로써 더 이상 앱 설치 유무에 구애받지 않게 되었습니다.
  • 하지만 이 Deferred Deep Link에도 한계점이 있었는데, 개발자가 각 OS별 처리를 직접 해야 한다는 점이었습니다. 같은 목적의 링크를 생성하더라도 AOS, iOS에 대한 링크가 따로 존재해야 했으며 이에 대한 내부 구현도 따로 이루어져야 했습니다.

Dynamic Link는 이러한 문제점들이 보완된 기술입니다. 플랫폼, OS 차이에서 오는 차이점을 내부적으로 처리해 줌으로써 개발자 입장에서는 한결 편한 개발이 가능합니다.

Dynamic Link를 사용하는 이유

그렇다면 이 Dynamic Link를 왜 사용할까요?

이러한 기술이 없다면 유저가 앱 내부의 목적지까지 랜딩하는 과정이 복잡해지며, 그 과정 중 유저의 이탈률도 높아지게 됩니다. 이는 곧 서비스의 유저 확보와 연결되기 때문에 굉장히 중요한 부분인데요, 이런 관점에서 Dynamic Link가 적용된다면 유저에게 매끄러운 경험을 제공함으로써 장기적인 유저 확보 및 마케팅 측면에서 이점을 얻을 수 있습니다.

똑닥에서는 알림톡, 상세 페이지 등의 기능에 Dynamic Link를 활용하고 있고, 추후 병원 공유하기 등의 기능에 적용할 예정입니다.


이어서 Node.js 서버에서 링크를 생성하는 과정에 대해 알아보겠습니다.

다만 여기서 의문이 드실 수도 있는데요, Dynamic Link는 서버뿐만이 아닌 App 단에서도 생성할 수 있기 때문입니다. 서버에서 링크를 생성하려고 하는 이유는 아래와 같습니다.

  • 앱에서 링크를 생성하게 되면, 링크가 필요한 시점마다 매번 생성해야 함
    • 구글 API 콜 제한에 영향을 미침
    • 이미 생성된 링크더라도 이를 알 수 없으므로, 똑같은 목적지로 향하는 링크가 매번 새롭게 생성됨

서버 단에서 링크를 생성하게 되면 위의 단점들을 해결할 수 있고, 한 번 생성된 링크는 DB에 저장하여 제공함으로써 외부 API 호출 횟수를 줄일 수 있습니다.

사전 준비

  • URL Prefix 추가 (Optional)
    • Firebase Console에서 완성된 Dynamic Link에 사용될 도메인을 설정할 수 있음
    • 설정 참고
  • Firebase Web API Key
    • Firebase Console의 Project 설정에서 확인 가능
  • AOS, iOS Package Name
    • Firebase Console의 Project 설정에서 확인 가능
    • 앱 미설치 시 작동에 필요

링크 생성 방법

Dynamic Link를 생성하는데는 여러 가지 방법이 있습니다.

  • String 조합으로 직접 생성
  • Firebase REST API 호출을 통한 생성
  • Firebase Console을 통한 생성

여기서는 그중 두 번째인 REST API를 통해 링크를 생성하겠습니다.

직접 Request를 보내 결과를 받는 방법도 있지만, 요청 / 응답에 대한 타입 정의가 잘 되어있는 NPM 패키지가 있으므로 해당 모듈을 사용하도록 하겠습니다.

npm i firebase-dynamic-links

로직 작성

먼저 모듈 초기화를 진행합니다. 모듈 초기화에는 Firebase Web API Key가 필요합니다.

// Firebase 설정값을 모아둔 객체
const firebaseConfig = {
webApiKey: 'anything'
};

// 사전 설정한 값을 바탕으로 Link를 생성해주는 인스턴스
const firebaseDynamicLinks = new FirebaseDynamicLinks(
firebaseConfig.webApiKey
);

위에서 생성한 인스턴스를 바탕으로 링크를 바로 생성해도 되지만, 내부에 들어가는 파라미터의 개수가 많아 별도의 함수로 분리하겠습니다.

const createDynamicLink = async (
value: string
): Promise<DynamicLinkResult> => {
const dynamicLinkInfo = {
domainUriPrefix: firebaseConfig.domainUriPrefix, // 링크에 사용될 도메인 (사전 설정 참고)
link: firebaseConfig.linkPrefix + value, // App에서 받게 될 목적지 링크
androidInfo: {
androidPackageName: firebaseConfig.aosPackageName, // 링크를 여는 데 사용될 App의 Package Name
},
iosInfo: {
iosBundleId: firebaseConfig.iosBundleId, // 링크를 여는 데 사용될 App의 Bundle ID
iosIpadBundleId: firebaseConfig.iosBundleId, // 링크를 여는 데 사용될 App의 Bundle ID
iosAppStoreId: firebaseConfig.iosAppStoreId, // App 미설치 시 App Store로 연결하기 위한 App의 Store ID
},
navigationInfo: {
enableForcedRedirect: true, // iOS에서 미리보기 페이지를 건너뛰고 앱으로 redirection 시킴
},
};
const result = await firebaseDynamicLinks.createLink({ dynamicLinkInfo });

return {
value,
dynamicLink: result.shortLink,
};
};

위 함수에서 중요한 부분은 dynamicLinkInfo내의 link 값입니다.

실제로 유저를 랜딩시킬 목적지의 Link로써, 이 값을 어떻게 설정하느냐에 따라 링크의 최종 동작이 바뀌게 됩니다. 이 함수에서는 사전 지정된 Link (firebaseConfig.linkPrefix)값을 기본으로 하고 pathvalue 값을 통해 유동적으로 받아, 동일한 카테고리를 가진 기능 내에서 최종 목적지만 달라지게 구현하였습니다.

똑닥에서는 이 중 linkPrefix를 병원 상세페이지 링크로, value 값을 병원의 고유 식별자로 설정하여 병원 상세페이지로 랜딩시키되, 어떤 병원으로 이동할지는 인자 값으로 받도록 구현하여 사용하고 있습니다.

위 함수를 실행한 결과는 아래와 같습니다.

{
"value": "testValue", // 특정 값
"dynamicLink": "https://customdomain.page.link/sh5zNnnHK9NfNjzk7", // 완성된 Dynamic Link
}

이 값에서 dynamicLink 필드의 값은 필요에 따라 DB에 저장한 후 유저에게 전달하면 됩니다.

위에서 구현한 createDynamicLink 함수를 분리하여 별도의 엔드포인트와 연결해 둔다면, 각 서버에서 번거롭게 세팅할 필요 없이 Dynamic Link가 필요할 때마다 편하게 생성하여 가져다 쓸 수 있습니다.

생성된 링크에 대한 통계 확인하기

동일한 모듈을 사용해, 이미 생성된 링크에 대한 통계를 확인할 수 있습니다. Firebase Console을 통해 생성한 링크라면, 아래처럼 Console에서 바로 통계치 확인이 가능합니다. Firebase Console - Dynamic Link Statistics

통계 목록

Firebase Console - Dynamic Link Statistics 2

특정 링크에 대한 상세 통계


하지만 String 조합으로 직접 생성했거나, REST API를 통해 생성했을 때는 Firebase Console에 표시되지 않으므로 통계 확인 또한 REST API를 통해야만 합니다.

링크 생성 시와 마찬가지로 모듈 초기화를 진행합니다.

const firebaseDynamicLinks = new FirebaseDynamicLinks(
firebaseConfig.webApiKey
);

이어서 Firebase Access Token을 발급받습니다.

마찬가지로 NPM 패키지가 존재하므로, 필요에 따라 사용하여 발급합니다.

토큰 발급이 완료되었다면, 링크 통계를 확인합니다.

// 토큰 발급 과정은 생략
const generateFirebaseAccessToken = (): Promise<string> => {
/* do something... */
};

// 발급받은 토큰을 메모리에 올려둠
export const firebaseAccessToken = await generateFirebaseAccessToken();

const getDynamicLinkStats = async (
dynamicLink: string,
duration: number
) => {
const result = await firebaseDynamicLinks.getLinkStats(
dynamicLink, // 통계 확인을 원하는 링크
duration, // 통계 데이터를 가져올 일 수 (day)
firebaseAccessToken // 위에서 발급받은 AccessToken
);

return result.linkEventStats;
};

위 함수를 실행한 결과는 아래와 같습니다.

[
{
"platform": "ANDROID",
"count": "20797",
"event": "CLICK"
},
{
"platform": "ANDROID",
"count": "4974",
"event": "APP_INSTALL"
},
{
"platform": "ANDROID",
"count": "8012",
"event": "APP_FIRST_OPEN"
}
]

백오피스 등 내부 환경에 위 함수를 사용한 기능을 적용한다면, Firebase Console을 통하지 않고 생성한 Dynamic Link에 대한 통계치를 확인할 수 있게 됩니다.


고려사항

실제 프로덕션 환경에서 사용 시, API 콜 제한 확인이 필요합니다.

공식 문서상 REST API의 콜 제한은 동일 IP 기준 초당 5회, 일일 20만 회로 표기되어 있으나, 제 경우 실제 사용 시 초당 300회 이상 호출해도 문제가 없었습니다.

이 부분은 문서 표기가 잘못된 건지 확실하게 확인되지는 않았으나, 동일 IP에서 빠른 속도로 다중 호출이 필요할 경우 잘 동작하는지 확인하고 진행해야 할 것 같습니다.

또한 일일 제한인 20만 회 이상 호출이 필요할 경우, 구글 측에 할당량 상향 요청이 가능하다고 하니 참고하면 좋을 것 같습니다.


마치며

입사 후 첫 업무로 진행했던 Dynamic Link 기술에 대해 살펴보았습니다.

복잡한 과정을 거치지 않고 원하는 콘텐츠에 바로 접근할 수 있다는 것이 상당히 매력적이었고, REST API를 지원하여 초기 설정 및 통계를 비롯한 관리 또한 자체 도구에 종속적이지 않다는 점이 좋았습니다.

업무를 진행하며 느낀 점

업무를 진행하기에 앞서, 새로운 회사이니만큼 일하는 방식이나 개발 문화에 적응하기 힘들지 않을까 우려했던 부분도 분명 있었습니다. 하지만 실제로 업무를 진행해보니 각 서버들은 대부분 내부 템플릿 구조에 맞춰 개발되어 있어 파악하기에 크게 어렵지 않았고, 코드 리뷰 문화 덕에 놓치고 있던 부분이나 코드 퀄리티를 보다 개선할 수 있었습니다. 또한 개발이 완료된 이후 배포하는 과정에서도 잘 갖춰진 CI/CD 프로세스 덕에 큰 스트레스를 받지 않고 편하게 배포할 수 있어 전반적으로 큰 부담 없이 적응할 수 있었던 것 같습니다.

이상으로 글 마치겠습니다, 긴 글 읽어주셔서 감사합니다.