Skip to content
isdnetworks
Go back

웹을 감싼 앱을 만들며

모바일 앱이 필요했고 웹 화면은 이미 있었다. 웹을 감싸는 방식으로 가서 앱은 껍데기고 WebView 안에서 웹이 돈다.

빨리 나왔다. 그리고 몇 가지가 안 됐다.

Table of contents

Open Table of contents

제약 — 웹으로 안 되는 넷

써 보면서 하나씩 나왔고 모아 보니 네 가지로 갈렸다.

기기 기능   카메라·위치·파일 접근. 브라우저 권한으로 되는 것도 있고 안 되는 것도 있다
알림       앱이 꺼져 있을 때 보내려면 네이티브가 필요하다
오프라인   연결이 끊기면 아무것도 안 된다
저장       웹 저장소는 용량이 작고 지워질 수 있다

이 넷이 경계였다. WebView 안에서 해결되지 않으므로 앱 쪽에서 만들어 웹에 열어 줘야 하고 어떤 것이 이 넷에 해당하는지를 처음에 알았으면 계획이 달라졌을 것이다.

다리를 놓았다

웹과 네이티브 사이에 통로를 만들었다.

// 웹에서 부른다
Bridge.call('getLocation', {}, (result) => { ... });

네이티브가 그 요청을 받아 처리하고 결과를 돌려준다. addJavascriptInterface 로 객체를 하나 붙이면 웹 쪽 JavaScript 가 그것을 부를 수 있다.

Bridge 에 필요한 것만 하나씩 열었고 처음부터 다 만들지 않았다.

통로가 늘어나면

이것이 계속 늘면 결국 앱을 다시 만드는 것과 같아져서 기준을 뒀다.

웹으로 되면 웹으로 한다     통로는 안 될 때만
통로는 얇게                 로직을 네이티브에 넣지 않는다
목록을 유지한다             어떤 통로가 있는지 문서로 관리

통로를 넓게 열어 두면 나중에 곤란해진다. 문서도 이 기능이 JavaScript 에게 앱을 제어할 힘을 준다고 경고하고 들어오는 HTML 이 전부 우리가 쓴 것일 때만 쓰라고 적는다.

다행히 좁히는 장치가 규격에 들어 있었다. targetSdkVersion 이 17 이상이면 @JavascriptInterface 를 붙인 메서드만 웹에서 보이고 안 붙인 것은 아예 안 불린다.

한 번 열어 준 것은 웹이 쓰기 시작하므로 닫기 어렵다. 통로는 얇게 두고 판단은 웹에서 하게 하니 앱을 다시 배포할 일이 줄었다.

버전이 갈렸다

가장 곤란했던 것이 이것이었다. 웹은 배포하면 즉시 반영되는데 APK 는 사용자가 업데이트해야 한다.

웹: 새 통로를 쓰는 코드로 갱신됨
앱: 옛 버전, 그 통로가 없음
→ 오류

웹이 앱보다 앞서 나가면 깨진다. 두 가지를 넣었다.

if (Bridge.version >= 3) {  기능 } else { 대체 동작 }

Bridge.version 으로 앱이 자기 버전을 알려주고 웹이 그것을 보고 기능을 켜고 끈다. 버전은 User-Agent 끝에 덧붙여 보내게 했다.

그리고 너무 낡은 앱은 업데이트를 요구하는 최소 버전을 강제했는데 이것은 마지막 수단이다. 두 배포 주기가 다르다는 것을 구조에 반영해야 했다.

화면이 어색했다

WebView 에 웹 화면을 그대로 넣으니 앱 같지 않았다.

뒤로 가기가 브라우저처럼 동작한다
스크롤이 튕긴다
링크를 누르면 브라우저가 열린다

하나씩 잡았다. 뒤로 가기는 goBack() 에 연결해 줘야 웹 화면 사이를 돌아간다.

Android 쪽에서 네이티브 감각을 흉내 내는 작업이 생각보다 많았고 이 부분에서 시간이 꽤 들었다. 처음에 웹이 있으니 금방이라고 본 것이 여기서 틀렸다.

그래도 이 방식을 고른 것은 화면이 많고 자주 바뀌기 때문이었다. 그것을 네이티브로 두 벌 만들면 유지가 안 된다.

대가는 네이티브 감각이 부족하고 기기 기능마다 Bridge 통로가 필요하고 버전이 갈린다는 것이다. 기준은 화면이 자주 바뀌는가였고 자주 바뀌면 웹이 유리하며 안 바뀌고 기기 기능이 많으면 네이티브가 낫다.

정리


Share this post on:

Previous Post
눌러도 아무 일이 없는 버튼이 있었다
Next Post
시도 한 번이 비싼 경우가 있다