0%

Frontend

네이티브 코드 한 줄 없이 google Play Store에 앱을 올렸습니다

전*진··수정됨 2026.09.04

네이티브 코드 한 줄 없이 google Play Store에 앱을 올렸습니다


웹앱을 스토어에? — TWA라는 선택

처음 개발할 때는 막막했습니다. 앱을 만들려면 네이티브 개발을 배우거나 React Native 같은 걸로 다시 만들어야 하는 줄 알았거든요. 이미 잘 돌아가는 웹앱이 있는데 처음부터 다시 만든다는 게 영 내키지 않았습니다.

이후 개발 경험이 쌓인 이후에 TWA(Trusted Web Activity)라는 걸 이전에도 사용해 본 적이 있어 TWA를 적용하게 되었습니다.

TWA를 한 문장으로 설명하면 이렇습니다. "크롬 브라우저가 앱인 척 전체 화면으로 내 웹사이트를 띄워주는 기술." 흔히 아는 WebView 래핑과는 다릅니다. WebView는 반쪽짜리 브라우저를 앱 안에 심는 거라 최신 웹 API가 안 되는 경우가 많은데, TWA는 사용자 폰에 설치된 진짜 크롬이 렌더링을 합니다. 서비스 워커, 푸시 알림, 웹에서 되던 게 그대로 다 됩니다.

조건이 하나 있습니다. 이름에 들어있는 Trusted, 그러니까 "이 앱과 이 웹사이트는 같은 주인이다"라는 걸 증명해야 해요. 이 증명이 나중에 저를 얼마나 괴롭힐지, 이때는 몰랐습니다.

Bubblewrap으로 10분 만에 APK 뽑기

구글이 만든 Bubblewrap이라는 CLI 도구를 쓰면 TWA 앱 프로젝트가 뚝딱 만들어집니다. PWA 요건(manifest, 서비스 워커, HTTPS)만 갖춰져 있다면요.

npm i -g @bubblewrap/cli
bubblewrap init --manifest https://내도메인.com/manifest.webmanifest

init을 실행하면 앱 이름, 패키지명(com.example.myapp 같은 것), 아이콘 등을 물어보는데, 대부분 웹 manifest에서 알아서 읽어옵니다. 그리고 마지막에 이런 걸 물어봐요.

"서명 키(keystore)가 없네요. 새로 만들까요?"

네, 하고 엔터를 치면 android.keystore라는 파일이 생깁니다. 이때는 "아 앱에 도장 찍는 건가 보다" 하고 넘어갔습니다. 이 파일과 비밀번호는 잃어버리면 안 됩니다. 일단 여기까지만 기억해 두세요.

bubblewrap build

빌드가 끝나면 app-release-signed.apkapp-release-bundle.aab 두 파일이 생깁니다. APK는 폰에 직접 설치해볼 수 있는 파일이고, AAB는 Play Store에 업로드하는 전용 포맷이에요.

APK를 폰에 옮겨 설치해 봤습니다. 앱 아이콘이 생기고, 탭하니 제 웹앱이 뜹니다. 여기까지 정말 10분쯤 걸렸어요. 생각보다 쉽죠?

그런데요....

그런데 주소창이 안 사라집니다

앱을 열었는데 화면 상단에 브라우저 주소창이 떡하니 붙어 있었습니다. https://내도메인.com이라고 적힌 회색 바가요. 이러면 그냥 크롬으로 사이트를 연 것과 다를 게 없잖아요. 앱이라고 부르기 민망한 모습이었습니다.

검색해 보니 이건 버그가 아니라 TWA가 의도한 동작이었습니다.

아까 TWA의 조건이 "이 앱과 이 웹사이트는 같은 주인임을 증명하는 것"이라고 했죠. 증명이 안 되면 크롬은 주소창을 강제로 띄웁니다. 이유는 보안 때문이에요. 증명 없이 아무 앱이나 전체 화면으로 웹사이트를 띄울 수 있다면, 은행 사이트를 똑같이 흉내 낸 피싱 앱이 "진짜 은행 앱인 척" 할 수 있으니까요. 주소창은 "지금 보고 있는 게 어느 사이트인지"를 사용자에게 알려주는 최후의 안전장치인 겁니다.

그럼 증명은 어떻게 하느냐. Digital Asset Links라는 방식을 씁니다. 웹사이트에 JSON 파일 하나를 올려두는 거예요.

https://내도메인.com/.well-known/assetlinks.json
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.myapp",
    "sha256_cert_fingerprints": ["AA:BB:CC:...:FF"]
  }
}]

의미는 단순합니다. "패키지명이 com.example.myapp이고, 이 지문(fingerprint)으로 서명된 앱은 내 사이트의 주인이 맞다"라고 웹사이트가 공개적으로 선언하는 거예요. 앱을 실행하면 크롬이 이 파일을 확인하고, 조건이 맞으면 그제야 주소창을 치워줍니다.

여기서 sha256_cert_fingerprints가 바로 아까 만든 keystore의 지문입니다. 이렇게 뽑아요.

keytool -list -v -keystore android.keystore
# Certificate fingerprints 항목의 SHA256 값을 복사

지문을 넣은 assetlinks.json을 배포하고, 앱을 지웠다 다시 설치했습니다. 주소창이 사라졌습니다! 드디어 앱다운 모습이 됐어요.

이제 스토어에 올리기만 하면 끝... 이라고 생각했습니다.

키가 왜 두 개죠?

Play Console에 개발자 계정을 만들고(가입비 25달러가 있습니다), AAB를 업로드하고, 심사를 통과했습니다. 설레는 마음으로 스토어에서 제 앱을 내려받아 실행했는데요.

주소창이 다시 나타났습니다.

분명히 고쳤잖아요? 내 폰에 APK로 직접 설치했을 때는 멀쩡했는데, 스토어에서 받으니까 다시 회색 바가 떠 있는 겁니다. assetlinks.json도 그대로고, 패키지명도 그대로인데요.

범인은 지문 불일치였습니다. 스토어에서 받은 앱은 제 keystore가 아니라 다른 키로 서명되어 있었던 거예요.

이걸 이해하려면 Play App Signing이라는 구조를 알아야 합니다. Play Store에 AAB를 올리면 구글은 그걸 그대로 배포하지 않습니다. 받아서 자기가 보관하는 키로 다시 서명한 뒤 사용자에게 전달해요. 그래서 키가 두 개가 됩니다.

  • 업로드 키(upload key) — 내가 가진 키. "이 AAB는 내가 올린 게 맞다"를 구글에게 증명하는 용도. Bubblewrap이 만들어준 그 keystore입니다.

  • 앱 서명 키(app signing key) — 구글이 보관하는 키. 사용자 폰에 실제로 설치되는 앱은 이 키로 서명됩니다.

왜 이렇게 하냐면, 개발자가 키를 잃어버리는 사고가 너무 많았기 때문입니다. 서명 키를 잃어버리면 그 앱은 영영 업데이트를 못 하는데, 구글이 서명 키를 대신 보관해 주면 업로드 키는 잃어버려도 재발급받으면 되거든요.

정리하면 이렇게 됩니다.

내 폰에 직접 설치한 APK  →  업로드 키로 서명  →  지문 일치 → 주소창 없음
스토어에서 받은 앱      →  앱 서명 키로 서명  →  지문 불일치 → 주소창 등장

즉 assetlinks.json에 넣어야 할 지문은 내 keystore 지문이 아니라, 구글이 들고 있는 앱 서명 키의 지문이었던 겁니다. 이 지문은 Play Console의 설정 → 앱 무결성(App integrity) 메뉴에서 확인할 수 있어요. 그 값을 assetlinks.json에 추가하고 다시 배포하니, 스토어 버전에서도 드디어 주소창이 사라졌습니다.

참고로 지문은 배열이라 여러 개를 넣을 수 있습니다. 업로드 키 지문과 앱 서명 키 지문을 둘 다 넣어두면, 로컬 테스트 빌드와 스토어 버전 모두에서 검증이 통과합니다.

심사 제출부터 출시까지

기술적인 산은 다 넘었고, 남은 건 절차였습니다. 몇 가지만 짚어둘게요.

스토어 등록 정보가 생각보다 손이 많이 갑니다. 스크린샷(휴대전화용 최소 2장), 512px 앱 아이콘, 그래픽 이미지, 앱 설명, 개인정보처리방침 URL까지. 특히 개인정보처리방침은 데이터를 하나도 안 모으는 앱이어도 필수입니다.

데이터 보안 설문도 채워야 합니다. 어떤 데이터를 수집하고 어디에 쓰는지 항목별로 신고하는 건데, 웹앱이 쓰는 것들(예: 로그인, 애널리틱스)을 기준으로 솔직하게 적으면 됩니다.

그리고 개인 개발자 계정이라면 테스트 요건이 있습니다. 최근에 만든 개인 계정은 정식 출시 전에 비공개 테스트를 일정 기간(테스터 모집 요건 포함) 거쳐야 해요. 저처럼 "만들었으니 바로 출시!"를 꿈꿨다면 이 기간을 일정에 미리 넣어두세요.

심사는 며칠 단위로 걸립니다. 첫 제출은 특히 더 걸릴 수 있어서, 출시일이 정해져 있다면 여유를 두는 게 좋습니다. 저는 제출해 두고 다른 일 하다가 승인 메일을 받았는데, 그 메일이 그렇게 반가울 수가 없더라고요.

돌아보며: 웹 개발자에게 TWA란

출시하고 나서 생각해 보니, 이 여정에서 제가 쓴 "안드로이드 지식"은 사실상 없었습니다. 대신 필요했던 건 이 두 가지에 대한 이해였어요.

  1. 신뢰는 선언으로 증명한다 — 웹사이트가 assetlinks.json으로 앱을 공개 지목하는 구조. 웹의 .well-known 관례가 앱 세계와 만나는 지점이 재미있었습니다.

  2. 서명 키는 신원이다 — "누가 만든 앱인가"를 코드가 아니라 암호학적 지문으로 판별한다는 것. 그리고 그 신원 관리를 구글이 대행하는 게 Play App Signing이라는 것.

TWA를 추천하는 경우는 명확합니다. 이미 잘 만든 PWA가 있고, 스토어라는 유통 채널이 필요할 때. 반대로 카메라 제어나 백그라운드 작업처럼 웹이 못 하는 네이티브 기능이 핵심이라면 TWA로는 해결이 안 됩니다. 앱의 본체는 어디까지나 웹이니까요.

주소창과 씨름했던 며칠이 지금은 이 글의 절반이 됐습니다. 여러분의 첫 출시는 부디 10분 만에 끝나기를 바라며, 막히면 이 글의 지문 이야기를 떠올려 주세요. 십중팔구 범인은 키입니다.

읽기 도구

10분 읽기

이 글이 도움이 되었나요?

Work with GIWorks

프로젝트에 GIWorks의 경험이 필요하신가요?

전시·콘텐츠·엔지니어링 프로젝트의 아이디어와 고민을 들려주세요. 필요한 기술과 실행 방법을 함께 찾겠습니다.

문의하기

다음으로 읽기