권한은 ‘추가’보다 ‘분기’가 더 어렵습니다.
아래는 Cordova에서 권한 관련 설정을 Android/iOS로 분기할 때, 어디에 무엇을 둬야 안전한지(그리고 어디에 두면 위험한지)를 실무 기준으로 정리한 가이드입니다.
1) 분기 전략 먼저 잡기: “설정의 위치”를 기준으로 나누기
권한은 한 곳에서만 결정되지 않습니다. 보통 아래 4군데에서 섞여 들어옵니다.
- config.xml: 플랫폼별 preference, feature, edit-config 등 “프로젝트 레벨” 설정
- plugin.xml: 플러그인이 플랫폼별로 manifest/plist를 건드리는 정의(변수 포함)
- iOS Info.plist / Entitlements: 사용 목적 문구(NS…UsageDescription), 권한/기능 스위치(주로 플러그인이 edit-config로 넣음)
- AndroidManifest.xml / Gradle: uses-permission, features, dependency, SDK 버전 영향
분기 가이드의 핵심은 간단합니다.
- “앱이 직접 컨트롤할 설정”은 config.xml에서 platform별로 분기
- “플러그인이 요구하는 설정”은 plugin.xml 변수/설치 옵션으로 분기(가능하면)
- 플러그인이 한 번 넣어버린 설정을 억지로 덮는 방식은 마지막 수단(유지보수 비용이 큼)
2) config.xml에서 Android/iOS 분기하는 가장 안전한 패턴
config.xml은 Cordova에서 공식적으로 분기를 지원하는 1순위 지점입니다. 권한 관련으로는 특히 platform별 preference, edit-config, resource-file 같은 항목이 분기 포인트가 됩니다.
실무에서 자주 하는 분기는 이런 형태입니다.
- iOS에만 필요한 사용 목적 문구(예: 카메라/사진/위치): iOS 플랫폼 블록 내부에서만 넣기
- Android에만 필요한 권한(예: POST_NOTIFICATIONS 등): Android 플랫폼 블록 내부에서만 처리(플러그인이 넣는 경우가 많아 “중복 삽입” 주의)
- WebView/네트워크 정책 차이: Android와 iOS의 설정 키가 다르므로 섞어 쓰지 않기
주의할 점도 같이 기억해두면 좋습니다.
- 같은 키를 iOS/Android에 동시에 넣고 “한쪽은 무시되겠지”라고 두면, 플러그인/CLI 버전에 따라 예상 밖 파일이 수정될 수 있습니다.
- edit-config는 강력하지만 위험합니다. 잘못된 부모 노드(target-parent)나 merge 방식 때문에 plist/manifest가 깨지거나 중복 키가 생기기 쉽습니다.
3) iOS 권한(Info.plist) 분기: “사용 목적 문구”는 반드시 iOS 전용으로
iOS 권한 이슈는 대부분 Info.plist의 NS…UsageDescription 누락에서 시작합니다. 기능을 쓰는 코드가 iOS에서 실행될 가능성이 있다면(심지어 특정 화면에서만 쓰더라도), 심사나 런타임 크래시를 피하려면 해당 문구가 필요합니다.
- 카메라: NSCameraUsageDescription
- 사진: NSPhotoLibraryUsageDescription / NSPhotoLibraryAddUsageDescription
- 위치: NSLocationWhenInUseUsageDescription 등
Android에는 없는 키이므로, 문구를 넣는 작업은 iOS 블록에서만 처리하는 게 안전합니다. 또한 문구는 “왜 필요한지”를 사용자 입장에서 짧게 설명하는 형태가 보통 무난합니다.
추가로, iOS는 Entitlements가 필요한 경우가 있습니다(예: Push, Associated Domains 등). 권한과 비슷하게 취급되지만 성격이 다르니, 플러그인이 entitlements를 만지는지(또는 Xcode Signing 설정과 충돌하는지)도 같이 보세요.
4) Android 권한(Manifest) 분기: 필요한 것만, 그리고 중복 삽입을 피하기
Android는 manifest의 uses-permission이 핵심인데, Cordova에서는 플러그인이 manifest를 수정하는 일이 많아서 “내가 넣은 것”과 “플러그인이 넣은 것”이 겹치기 쉽습니다. 겹치면 보통은 빌드가 되지만, 특정 조합에서는 merge 경고/실패로 이어질 수 있습니다.
- 가능하면 권한은 플러그인에서 자동으로 넣게 두고, 앱(config.xml)에서 별도 삽입은 최소화합니다.
- Android 13+의 POST_NOTIFICATIONS처럼 런타임 권한이 추가된 항목은, “manifest만 추가”로 끝이 아닙니다. 실제 요청 로직이 있는지(플러그인이 처리하는지)도 확인해야 합니다.
- Android 전용 설정을 iOS와 한 파일에서 억지로 공유하지 말고, platform별 블록으로 분리하세요.
또 하나의 흔한 함정은 “권한을 넣었는데 기능이 안 됨”입니다. 이 경우는 권한이 아니라 AndroidX/SDK/Gradle dependency 충돌일 수 있으니, 권한 문제로 단정하기 전에 빌드 로그에서 실제 실패 지점을 먼저 보세요.
5) plugin.xml 변수로 분기하기: 플러그인 옵션을 플랫폼별로 관리하는 요령
같은 플러그인이라도 iOS/Android 설정 값이 다를 수 있습니다. 예를 들어 iOS에만 필요한 UsageDescription 문구, Android에만 필요한 dependency 버전, 특정 기능 플래그 등이 그렇습니다.
가능한 경우에는 다음 우선순위를 추천합니다.
- 1순위: 플러그인이 제공하는 install variable을 사용해 설정(예: --variable SOME_KEY=...)
- 2순위: config.xml의 platform 블록에서 해당 플러그인 관련 preference/변수를 “플랫폼별로” 제공
- 3순위(마지막 수단): hooks로 파일을 직접 패치(유지보수 난이도 큼)
플러그인을 직접 수정해야 하는 상황이라면(사내 포크 등), plugin.xml에서 <platform name="ios">, <platform name="android"> 블록을 명확히 나누고, 같은 키를 양쪽에 중복 정의하지 않도록 정리하는 것만으로도 사고가 많이 줄어듭니다.
6) 점검 체크리스트: 분기 후에 꼭 확인할 것
- iOS: Info.plist에 NS…UsageDescription이 “중복 없이” 들어갔는가
- iOS: 사용하지 않는 권한 문구를 습관적으로 넣지 않았는가(심사 질문 포인트가 될 수 있음)
- Android: AndroidManifest.xml에 uses-permission이 과도하게 늘지 않았는가
- Android: 권한이 런타임 권한인 경우(예: notifications/위치 등) 실제 요청 로직이 존재하는가
- 공통: 플러그인이 넣는 설정과 config.xml이 서로 덮어쓰거나 충돌하지 않는가
- 공통: 플랫폼별 분기 코드가 “빌드 타임”인지 “런타임”인지 구분했는가(예: device.platform 체크는 런타임)
마무리
Cordova 권한 설정은 “어디서 바꾸는지”가 절반입니다. config.xml, plugin.xml, Info.plist, AndroidManifest.xml 중 무엇이 진짜 소스 오브 트루스(source of truth)인지 정리하고, 플랫폼별로 분리해두면 나중에 플러그인 업데이트나 빌드 환경 변경에도 덜 흔들립니다.
분기한 뒤에는 꼭 생성된 결과물(Info.plist/AndroidManifest.xml)을 직접 확인해서, 의도대로 들어갔는지 마지막 검증까지 해두면 운영 사고가 크게 줄어듭니다.