이번에 모바일 웹에서 앱을 여는 기능을 개발하게 되었다. 아래 이미지에서 볼 수 있듯이, 이미 우리는 흔하게 사용하고 있는 기능이다.
하지만 처음 개발해 보는 내용이라 고생도 많이 했고, 새롭게 안 용어들도 많아서 이번 기회에 정리해 보려고 한다.
개발 요구사항은 다음과 같다.
참 심플한 기능이다. 심지어 이미 사용하고 있는 공통 모듈도 있었기 때문에, 구현하는 데 어려움이 없어 보였다. 처음에 구현한 방식은 다음과 같았다.
하지만 안드로이드에서 원하는 페이지가 나오지 않는 문제가 생겼다!
공통 모듈을 사용하여 쉽게 구현하려 했으나 실패하였으므로, 모듈을 이해하여 코드를 수정할 수 밖에 없었다.
이런 식으로 “특정 주소 혹은 값을 입력하면 앱이 실행되거나 앱 내 특정 화면으로 이동시키는 기능” 을 딥링크라고 한다. 딥링크는 다음 3가지 방식으로 구분할 수 있다.
모듈에서는 URI 스킴 방식을 사용하고 있었기 때문에 이를 집중적으로 살펴봤다.
스킴(Scheme)은 앱마다 등록할 수 있는 값으로, 이를 통해 우리는 앱을 구분할 수 있다. 그래서 우리는 특정 스킴 값을 호출하여 특정 앱을 열 수 있다.
URI 스킴 방식은 Scheme://Path
라는 두 개의 요소로 구성된다.
twitter://signup
window.location.href = (URI 스킴)
구문을 통해 이동할 수 있다.URI 스킴에서 가장 문제가 되는 점은, 스킴이 중복될 수 있다는 것이다. 즉, 앱으로 바로 이동하지 못하고 어떤 앱으로 이동할 지 사용자가 선택을 해야 한다는 것이다. 실제로 market://
은 구글플레이 스토어, OneStore, 삼성 앱스토어 등 여러 앱스토어에서 함께 사용하고 있다.
스킴이 중복되는 것은 마케팅적으로 문제가 된다. 스킴의 생성 목적이 앱 사용자 수를 늘리기 위함인데, 자신들의 앱으로 연결하지 못한다면 의미가 없기 때문이다.
A common and old technique to solve this problem is using iframe to load the deep link URL and having a delayed JavaScript to redirect to store
결과적으로는 URI 스킴 이동과 앱스토어 이동이 모두 일어나지만, 시간차를 이용해 한 가지만 일어나는 것처럼 보이게 하는 일종의 트릭이다.
twitter://signup
로 이동한다고 가정했을 때setTimeout()
로 인해 일정 시간 뒤에 마켓 주소로 이동하는 자바스크립트가 실행된다. 따라서, 앱스토어로 이동되어 사용자가 앱을 설치할 수 있다.setTimeout(
var visitedAt = (new Date()).getTime(); // 방문 시간
function() {
if((new Date()).getTime() - visitedAt < 2000) {
location.href = "{마켓 주소}";
}
}, 500);
var iframe = document.createElement('iframe');
iframe.style.visibility = 'hidden'; // 보이지 않는 iframe으로 스킴을 호출한다.
iframe.src = '{커스텀 스킴 주소}';
document.body.appendChild(iframe);
document.body.removeChild(iframe); // back 호출시 캐싱될 수 있으므로 제거
Since Chrome for Android version 25 and later, the above code stopped working according to Chrome documentation Fortunately, Google provides the Intent URL for a better solution.
Chrome의 경우 intent URL 방식을 도입하면서부터 iframe 방식을 사용할 수 없게 되었다. 하지만 intent URL은 앱의 설치 여부에 따른 처리를 자동으로 해주기 때문에 더욱 유용하다.
intent://path/#Intent;scheme=yourapp;package=com.yourapp.example;
setTimeout(function() {
location.href = "intent://커스텀스킴주소#Intent; scheme=스킴; action=..;category=..; package=com.android.xxx; end;";
}, 1000);
iOS에서는 안드로이드에서 iframe 방식과 동일한 트릭을 사용하여 구현 가능하다.
대신 iframe을 통해 이동할 필요 없이, 그냥 스킴 주소를 통해 이동할 수 있다.
setTimeout(
function() {
if ((new Date()).getTime() - visitedAt < 2000) {
location.href = "{마켓 주소}";
}
}, 500);
setTimeout(function() {
location.href = "{커스텀 스킴 주소}";
}, 0);
안드로이드 intent 방식을 사용했을 때만 인코딩 이슈가 있었기 때문에, 결과적으로는 기존 방식에서 사용하던 트릭을 그대로 이용하기로 결정했다.
(intent 방식으로 처리할 때 내부적인 로직으로 인해 인코딩이 풀리는 것으로 보인다. 혹시 정확한 원인을 아시는 분이 있다면 댓글 부탁드린다.. 나는 원인을 찾지 못했다 ㅠㅠ)
setTimeout(
function() {
if ((new Date()).getTime() - visitedAt < 2000) {
location.href = "{intent URL}";
}
}, 500);
setTimeout(function() {
location.href = "{커스텀 스킴 주소}";
}, 0);