라벨이 권한처리인 게시물 표시

안드로이드 웹뷰에서 파일 업로드(input type="file") 구현 및 콜백 오류 해결 방법

하이브리드 앱을 운영하다 보면 웹 페이지의 <input type="file"> 버튼을 눌러도 아무 반응이 없다는 고객 피드백을 마주할 때가 있습니다. 안드로이드 웹뷰는 기본적으로 파일 선택 요청만 던질 뿐, 실제 파일 탐색기를 띄우고 결과를 받아오는 UI 처리는 앱(Native)이 직접 중개해야 하기 때문입니다. 저의 경우도 최근 작업 중에 "파일 선택을 한 번 취소하고 나면, 그 다음부터 버튼이 아예 먹통이 되는 현상"을 겪었습니다. 원인을 파악해 보니 웹뷰의 파일 선택 콜백( ValueCallback ) 생명주기 관리 문제였습니다. 나중에 또 같은 문제로 헤매지 않기 위해, 실제 서비스 적용이 가능한 구현 코드와 운영 시 꼭 챙겨야 할 주의점을 정리해 둡니다. 내가 겪은 문제와 원인 웹 페이지가 파일 선택을 요청하면 앱은 WebChromeClient.onShowFileChooser() 에서 이 요청을 받게 됩니다. 이때 웹뷰는 결과를 기다리는 대기 상태로 들어가며, 앱은 ValueCallback<Uri[]> 객체에 사용자가 선택한 파일 경로를 담아 웹뷰에 돌려줘야 합니다. 여기서 가장 자주 하는 실수가 "사용자가 파일 선택을 취소했을 때 아무런 처리를 하지 않는 것"입니다. 콜백에 결과를 돌려주지 않고 그냥 끝나버리면, 웹뷰는 여전히 이전 요청을 대기하는 상태로 남아있게 되어 다음 번 클릭부터는 아예 반응을 하지 않게 됩니다. 해결 코드 (바로 적용하는 구현 예시) 최근 안드로이드 개발 표준에 맞춰 기존의 startActivityForResult 대신 Activity Result API ( registerForActivityResult )를 사용해 구현한 코드입니다. 보안을 위해 실제 업로드 URL이나 로컬 파일 경로는 제외하고 틀만 잡았습니다. Kotlin class UploadWebViewActivity : AppCompatActivity () { private ...

Android 13 이상 푸시 알림 권한(POST_NOTIFICATIONS) 대응 및 타이밍 설계 정리

앱 타겟 버전을 Android 13(API 33) 이상으로 올리면서 알림 기능 운영에 큰 변화가 생겼습니다. 예전에는 알림 채널만 만들어서 푸시를 보내면 사용자가 알아서 설정에서 끄는 방식이었는데, 이제는 POST_NOTIFICATIONS 라는 런타임 권한을 직접 받아야 합니다. 새로 설치한 앱은 알림이 기본적으로 꺼져 있기 때문에, 예전 생각만 하고 개발하면 푸시가 아예 안 가는 상황이 발생합니다. 운영을 하다 보니 "코드를 어디에 넣을까"보다 "어느 타이밍에 권한을 요청할까"가 훨씬 중요하더군요. 앱 시작하자마자 아무 설명 없이 팝업부터 띄우면 사용자는 대부분 거부합니다. 게다가 한 번 거부당하면 다시 권한을 유도하기가 꽤 까다롭습니다. 나중에 제가 다시 보려고 실무 기준으로 핵심만 짧게 정리해 둡니다. 1. 핵심 개념: 헷갈리기 쉬운 3가지 요소 분리하기 개발하다 보면 FCM 토큰 발급, 알림 채널 생성, 런타임 권한 요청을 다 같은 하나로 묶어서 생각하기 쉬운데, 이거 확실히 분리해서 처리해야 운영 데이터가 안 꼬입니다. 항목 필요한 버전 역할 및 특징 POST_NOTIFICATIONS Android 13 이상 앱이 기기에 일반 알림을 표시할 수 있는 최종 허가권입니다. NotificationChannel Android 8.0 이상 알림의 종류(배송, 채팅, 공지 등)와 중요도를 나누는 기준입니다. FCM Token 모든 버전 Firebase 사용 시 기기를 식별하기 위한 고유 키값입니다. 주의: FCM 토큰이 정상적으로 발급되었고 서버로 전송 성공했어도, 기기에서 POST_NOTIFICATIONS 권한이 거부되어 있으면 사용자는 푸시 알림을 구경도 못 합니다. 두 상태를 매칭해서 서버에서 관리해야 비용과 리소스를 아낍니다. 2. Manifest 설정 및 권한 요청 예시 코드 먼저 AndroidManifest.xml 에 권한을 선언해 줍니다. XML < manifest xmlns:android = ...