# 모바일 웹에서 앱 실행하기 deeplink 사용법
앱의 dau를 늘려 파생상품을 판매하거나 홍보를 위하는 등 다양한 이유로 모바일 웹애서 특정 앱 또는 자사 앱을 실행하고 싶을 때가 있습니다.
이때 모바일 앱 딥링크는 앱으로 전환율과 유지율을 크게 높일 수 있습니다.
모바일 앱 딥링크는 현재 앱이 설치된 경우 사용자가 링크를 클릭하면 앱이 열리고 개발자가 원하는 화면으로 이동할 수 있습니다. 앱이 설치되지 않은 경우는 playstore 또는 appstore로 redirect시켜 앱을 다운받도록 권고 할 수 있습니다.
서론은 여기까지 하고 제가 구현한 딥링크에 대해 알아보겠습니다
저는 모바일 웹과 앱의 웹뷰를 담당하였고, 앱 스킴을 이용해서 앱을 실행하는 작업을 하였습니다. 즉, 이 포스팅은 안드로이드 또는 ios에서 앱 스킴을 만드는 방법은 포함하지 않습니다.
스킴 기반 딥링크는 url을 앱과 연결한다는 아이디어로 만들게 됩니다. (스킴 기반 딥링크: youapp://, universal link: https://yourdomain.com/) 사용자가 URL을 클릭하면 시스템이 설치된 앱을 실행합니다.
# 전제조건
앱이 실행되려면 앱이 깔려있어야하겠죠?? 그렇기 때문에 유저가 앱을 깔지 않은 경우 앱스킴을 몇번을 실행해도 사용자는 오류 메시지를 보게 되거나 아무 일도 일어나지 않을 것입니다. 웹 상에서 기기에 앱이 설치되어 있는지를 직접 확인할 수 있는 방법은 없지만, 앱이 설치되어 있다면 이를 불러오거나, 설치되어 있지 않다면 사용자를 App Store나 playstore 또는 다른 장소로 연결할 수 방법은 여러가지가 있습니다
저는 이번 예시에서 앱이 설치되지 않은 경우 앱을 다운받을 수 있는 alert를 제공하는 방법으로 구현하겠습니다
# 딥링크
먼저 앱이 있다고 가정하고 딥링크를 실행합니다
딥링크 URL은 yourapp://path/이라고 가정합니다
const exeDeepLink = () => { url = "yourapp://path/"; location.href = url; };
Copied!
위의 경우 앱이 설치된 경우 앱이 실행되고, 앱이 설치되지 않았다면 exeDeepLink함수는 아무 작업도 수행하지 않습니다
# 설치 유도
앱이 설치되지 않아 exeDeepLink에서 아무 실행이 없었다면 timeout기능을 통해 app을 다운받도록 유도합니다
아래코드는 checkInstallApp 가 실행되면 0.5초 후에 앱 다운로드 하겠냐는 팝업을 띄우는 코드입니다. 0.2초 마다 브라우저가 닫히는 것을 체크하여 다운로드 팝업을 띄우지 않습니다.
const checkInstallApp = () => { const clearTimers = () => { clearInterval(check); clearTimeout(timer); }; const isHideWeb = () => { if (document.webkitHidden || document.hidden) { clearTimers(); } }; const check = setInterval(isHideWeb, 200); const timer = setTimeout(function() { redirectStore(); }, 500); }; const redirectStore = () => { const ua = navigator.userAgent.toLowerCase(); if (window.confirm("스토어로 이동하시겠습니까?")) { location.href = ua.indexOf("android") > -1 ? "https://play.google.com/store/apps/details?id=xxxxxx" : "https://apps.apple.com/kr/app/xxxxxx"; } };
Copied!
# 종합 코드
위에 앱 딥링크 코드와 앱다운로드 코드를 종합하면 아래와 같습니다 react로 구현하였습니다
버튼 클릭시 앱 딥링크가 실행되어 앱이 깔린 경우 앱이 실행되고, 그렇지 않은 경우 다운로드 팝업이 띄워집니다
import { useState } from "react"; import styled from "styled-components"; const Index = () => { const [isOpenModal, setIsModalOpen] = useState(true); const redireactApp = () => { exeDeepLink(); checkInstallApp(); }; function checkInstallApp() { function clearTimers() { clearInterval(check); clearTimeout(timer); } function isHideWeb() { if (document.webkitHidden || document.hidden) { clearTimers(); } } const check = setInterval(isHideWeb, 200); const timer = setTimeout(function() { redirectStore(); }, 500); } const redirectStore = () => { const ua = navigator.userAgent.toLowerCase(); if (window.confirm("스토어로 이동하시겠습니까?")) { location.href = ua.indexOf("android") > -1 ? "https://play.google.com/store/apps/details?id=xxx" : "https://apps.apple.com/kr/app/xxx"; } }; function exeDeepLink() { url = "yourapp://path/"; location.href = url; } return ( <DeepLinkBlock> <div className="modal"> <p className="title">앱을 여시겠습니까?</p> <div className="button-group"> <button className="open btn" onClick={redireactApp}> 네 열래요 </button> </div> </div> </DeepLinkBlock> ); }; const DeepLinkBlock = styled.div` background: #d1d1d1; position: fixed; overflow: hidden; height: 100vh; width: 100vw; display: flex; justify-content: center; align-items: center; .modal { width: 278px; height: 171px; padding: 26px 14px 14px; background: #ffffff; box-shadow: 0px 4px 4px rgba(192, 192, 192, 0.25); border-radius: 8px; position: relative; bottom: 50px; .title { font-weight: bold; font-size: 17px; margin-bottom: 12px; } .desc { font-size: 12px; color: #777777; } .button-group { display: flex; justify-content: space-around; margin-top: 38px; .btn { height: 40px; width: 120px; background: #eeeeee; color: #555555; font-size: 14px; letter-spacing: -1px; border-radius: 6px; } .open { background: orange; color: #ffffff; } } } `; export default Index;
Copied!