공지 링크를 웹에서는 새 탭으로, 모바일 앱에서는 WebView로 열도록 붙였다. 그런데 로그인이나 파일 다운로드 링크까지 WebView 안에 들어가 돌아오지 못하거나, 외부 앱 스킴을 일반 URL처럼 열어 오류가 났다. 링크 모양만 보고 실행 환경별 API를 호출하면 충분하지 않았다.
링크의 목적과 신뢰 수준에 따라 열기 정책을 정해야 했다.
URL을 분류한 뒤 실행했다
파싱한 URL의 프로토콜과 호스트, 경로를 기준으로 허용된 동작을 선택했다.
LinkAction Classify(Uri uri)
{
if (uri.Scheme == "https" && trustedHosts.Contains(uri.Host))
return LinkAction.InAppWebView;
if (uri.Scheme == "https")
return LinkAction.ExternalBrowser;
if (allowedDeepLinks.Contains(uri.Scheme))
return LinkAction.ConfirmAndOpenExternal;
return LinkAction.Block;
}
문자열 prefix 비교 대신 URL 파서를 사용해 비슷하게 보이는 악성 호스트를 구분했다.
WebView에는 최소 권한만 줬다
신뢰한 페이지라도 JavaScript 브리지가 모든 네이티브 기능을 노출하지 않게 허용 메시지와 origin을 확인했다. 새 창 요청, 파일 선택, 위치 권한은 기본 거부하고 필요한 기능만 제품 정책에 따라 열었다.
WebView에서 외부 호스트로 이동하려 하면 중단하고 외부 브라우저로 전환할지 사용자에게 안내했다.
복귀와 실패 흐름을 만들었다
외부 브라우저나 다른 앱으로 이동한 뒤 돌아오면 앱이 이전 화면 상태를 유지해야 했다. 딥링크 결과가 필요한 흐름은 state를 검증하고 이미 처리한 콜백을 다시 실행하지 않았다.
대상 앱이 설치되지 않았거나 URL을 열 수 없으면 조용히 실패하지 않고 복사 가능한 안전한 웹 대안을 제공했다.
링크 열기도 플랫폼 통합 기능이었다
처음에는 OpenURL 한 줄로 끝날 작업처럼 보였다. 실제로는 웹 콘텐츠, 네이티브 권한, 외부 앱 사이를 넘는 경계였다. 어디에서 열리는지가 보안과 로그인 상태, 복귀 경험을 바꿨다.
이후 링크 기능을 만들 때 URL 검증, 실행 위치, 권한, 실패 대안, 앱 복귀를 한 세트로 본다. 같은 링크도 맥락에 따라 안전한 열기 방법이 달랐다.