DEV Community

Cover image for 첫 출시 앱 심사: 인앱 결제(IAP) 버튼 무반응 문제와 해결 전략
바람의평온
바람의평온

Posted on

첫 출시 앱 심사: 인앱 결제(IAP) 버튼 무반응 문제와 해결 전략

첫 출시 앱 심사: 인앱 결제(IAP) 버튼 무반응 문제와 해결 전략

첫 출시 앱 심사: 인앱 결제(IAP) 버튼 무반응 문제와 해결 전략

앱의 첫 출시 심사를 준비하면서 인앱 결제(IAP) 기능 때문에 예상치 못한 난관에 부딪혔습니다. 야심 차게 준비한 구매 버튼이 심사 빌드에서 아무런 반응 없이 먹통이 되는 문제를 겪었던 것이죠. 이는 앱 심사 리젝 사유가 될 수 있는 치명적인 상황이었습니다. 결론부터 말씀드리자면, 스토어 백엔드에서 인앱 결제 상품이 아직 활성화되지 않아 발생하는 문제였고, 첫 출시 심사용 빌드에서는 인앱 결제 기능을 의도적으로 비활성화하여 이 문제를 우회했습니다. 이후 앱이 성공적으로 출시된 뒤 별도 업데이트를 통해 IAP 기능을 다시 활성화하는 단계적 접근으로 해결했습니다. 이 경험은 첫 출시 심사 시 인앱 결제 기능 관리의 중요성을 깨닫게 해주었습니다.

대상: Flutter 앱 개발자, 앱 출시 심사 과정에서 인앱 결제 문제로 고민하는 개발자
난이도: 중급

이 글에서 다루는 것

  • 앱 첫 출시 심사 시 인앱 결제(IAP) 상품 미로드 문제의 원인
  • 스토어 활성화 시점과 앱 심사 타이밍 불일치에 대한 이해
  • 첫 출시 빌드에서 IAP 기능을 안전하게 비활성화하는 방법
  • 인앱 결제 상품 로드 실패 시 UI/UX를 저해하지 않도록 버튼을 처리하는 로직
  • 단계적인 인앱 결제 기능 활성화 전략

앱 심사 중 만난 인앱 결제(IAP) 버튼 무반응 문제

저희 팀이 야심 차게 준비한 Flutter 앱의 첫 출시 심사 과정에서 예상치 못한 문제가 발생했습니다. 인앱 결제(IAP) 기능을 테스트하는데, 구매 버튼이 아무런 반응도 하지 않는 것이었습니다. 개발 환경에서는 분명히 잘 동작하던 기능이었기에, 심사용 빌드에서만 발생하는 이 현상에 당황스러움을 감출 수 없었죠. 이런 무반응 버튼은 사용자 경험을 해칠 뿐만 아니라, 앱 심사팀으로부터 리젝 사유가 될 가능성이 매우 높았습니다.

앱 심사팀은 사용자 관점에서 앱을 테스트하기 때문에, 인앱 결제 기능이 정상적으로 동작하지 않으면 앱의 기능적 결함으로 판단하기 십상입니다. 저희는 즉시 로그를 확인하며 문제의 원인을 파악하기 시작했습니다. 로컬 환경과 심사 빌드 환경의 차이를 좁히는 것이 급선무였죠. 이 과정에서 인앱 결제와 관련된 중요한 사실을 깨달았습니다.

결론적으로, 첫 출시 심사를 위해 제출된 빌드에서는 IAP 기능을 아예 비활성화하는 방식으로 이 문제를 우회하기로 결정했습니다. 기능이 아예 없으면 심사팀에서 테스트할 여지도 없으니, 적어도 리젝 사유는 되지 않을 것이라는 판단이었죠. 이후 앱이 성공적으로 출시되면 별도의 업데이트를 통해 IAP 기능을 다시 활성화하기로 계획을 세웠습니다.

스토어 백엔드와의 타이밍 불일치: 상품 미로드의 원인

구매 버튼이 무반응이었던 근본적인 원인은 앱이 스토어 백엔드로부터 인앱 결제 상품 정보를 제대로 로드하지 못했기 때문이었습니다. 첫 출시 심사 시점에는 아직 스토어 콘솔에 등록된 인앱 결제 상품들이 ‘활성화’되지 않은 상태였던 것이죠. 스토어 심사 프로세스와 인앱 상품의 활성화 타이밍이 동기화되지 않는다는 사실을 미처 간과하고 있었던 것입니다.

저희 앱의 인앱 결제 로직은 상품 정보를 성공적으로 로드했을 때만 구매 버튼을 활성화하도록 구현되어 있었습니다. 만약 상품 목록이 비어 있으면, 즉 _products 리스트가 비어 있으면 구매 버튼의 onPressed 콜백이 null로 설정되어 버튼이 비활성화되거나 아무런 동작을 하지 않도록 되어 있었죠. 이는 평소에는 안전한 구현 방식이지만, 상품 로드 자체가 실패하는 특수한 상황에서는 의도치 않은 문제를 발생시켰습니다.

결국, 앱은 상품이 없다고 판단했고, 그에 따라 구매 버튼이 무반응 상태가 된 것이었습니다. 이 문제를 해결하기 위해서는 단순히 상품이 로드되지 않았을 때의 UI 처리뿐만 아니라, 첫 출시 심사라는 특수한 상황에서 인앱 결제 상품 활성화 여부를 전략적으로 다룰 필요가 있음을 깨닫게 되었습니다.

첫 출시 빌드를 위한 IAP 기능 일시 비활성화 전략

저희는 첫 출시 심사용 빌드에 한해 인앱 결제 기능을 완전히 비활성화하는 전략을 택했습니다. 이를 위해 코드 내부에 간단한 상수를 정의하여 인앱 결제 기능의 활성화 여부를 제어하도록 만들었습니다. 다음과 같은 플래그를 추가했죠.

const bool kEnableIapForFirstRelease = false; // 첫 출시 심사용 빌드에서 false로 설정
Enter fullscreen mode Exit fullscreen mode

kEnableIapForFirstRelease 상수는 첫 출시 심사를 위한 빌드를 만들 때만 false로 설정하고, 앱이 스토어에 출시된 이후에는 true로 변경하여 업데이트 빌드를 제출하는 방식으로 활용했습니다. 이 플래그를 통해 인앱 결제 초기화 로직을 조건부로 실행하도록 했습니다.

if (kEnableIapForFirstRelease) { await InAppPurchase.instance.initialize(); }
Enter fullscreen mode Exit fullscreen mode

위 코드처럼 initialize() 호출 자체를 조건부로 감싸면, kEnableIapForFirstReleasefalse일 때는 인앱 결제 모듈이 아예 초기화되지 않아 상품 로드를 시도조차 하지 않게 됩니다. 이는 불필요한 네트워크 요청과 에러 발생 가능성을 원천적으로 차단하는 효과를 가져다주었습니다. 덕분에 심사 빌드에서는 인앱 결제 관련 로직이 전혀 실행되지 않아 안정성을 확보할 수 있었지요.

사용자 경험을 해치지 않는 구매 버튼 UI 처리

인앱 결제 기능을 일시적으로 비활성화하더라도, 사용자 인터페이스(UI)는 여전히 적절하게 처리되어야 합니다. 단순히 버튼이 사라지거나 오류 메시지만 표시되는 것보다는, 기능이 현재 사용 불가능하다는 것을 명확하게 인지시키는 것이 중요합니다. 저희는 kEnableIapForFirstRelease 플래그와 함께 _products 리스트의 상태를 이용하여 구매 버튼의 동작을 제어했습니다.

ElevatedButton(
  onPressed: _products.isNotEmpty && kEnableIapForFirstRelease ? () => _buyProduct() : null,
  child: Text('구매하기'),
)
Enter fullscreen mode Exit fullscreen mode

위 코드에서 보듯이, 구매 버튼의 onPressed 콜백은 두 가지 조건이 모두 충족될 때만 활성화됩니다. 첫째, _products.isNotEmpty는 인앱 결제 상품 목록이 비어 있지 않아야 한다는 것을 의미합니다. 상품이 로드되지 않았으면 구매 버튼이 활성화될 이유가 없으니까요. 둘째, kEnableIapForFirstRelease는 인앱 결제 기능 자체가 활성화되어 있어야 함을 나타냅니다. 이 두 조건 중 하나라도 만족하지 않으면 onPressednull이 되어 버튼은 자동으로 비활성화됩니다.

이러한 조건부 로직 덕분에 첫 출시 심사 빌드에서는 kEnableIapForFirstReleasefalse였으므로, 설령 _products가 채워지더라도 버튼이 비활성화 상태를 유지했습니다. 이는 심사팀이 무반응 버튼을 발견하고 리젝하는 상황을 효과적으로 방지할 수 있었죠. 버튼이 비활성화되면 사용자에게 명확하게 '지금은 구매할 수 없다'는 메시지를 전달하는 효과도 있습니다. 앱의 기능은 명확하게 전달하되, 심사 과정에서는 불필요한 오해를 사지 않도록 설계한 셈입니다.

안정적인 출시와 인앱 결제 기능의 단계적 활성화

인앱 결제 기능이 비활성화된 첫 번째 빌드는 별다른 문제 없이 앱 심사를 통과했습니다. 이로써 우리는 첫 출시의 가장 큰 허들 중 하나를 안전하게 넘길 수 있었죠. 심사 통과 후 앱이 공식적으로 스토어에 출시되었을 때, 인앱 결제 상품들도 스토어 백엔드에서 정상적으로 활성화되는 것을 확인했습니다. 이제는 인앱 결제 기능을 다시 켜야 할 때가 된 것이었습니다.

저희는 kEnableIapForFirstRelease 상수를 true로 변경하고, 인앱 결제 기능을 활성화한 새로운 업데이트 빌드를 제출했습니다. 이 빌드는 다시 한번 스토어 심사를 거쳐야 했지만, 이미 상품들이 활성화된 상태였기 때문에 별다른 이슈 없이 심사를 통과할 수 있었습니다. 이후 앱 내에서 모든 인앱 결제 상품이 정상적으로 로드되고, 구매 프로세스 또한 원활하게 작동하는 것을 최종적으로 확인했습니다.

이러한 단계적 접근 방식은 첫 출시 심사 과정에서 발생할 수 있는 잠재적인 문제를 효과적으로 회피하며, 안정적인 앱 출시를 가능하게 했습니다. 만약 처음부터 인앱 결제 기능을 완전히 활성화한 채로 심사를 진행했다면, 상품 미로드로 인한 리젝과 그에 따른 출시 지연을 겪었을지도 모릅니다. 저희의 경험은 첫 출시 심사 시 인앱 결제 상품의 스토어 활성화 시점과 앱 심사 타이밍이 항상 일치하지 않을 수 있다는 점을 상기시켜 주었습니다.

마치며

앱의 첫 출시 심사는 여러 변수가 많아 개발자에게 긴장감을 안겨주는 과정입니다. 특히 인앱 결제와 같은 외부 의존성이 큰 기능은 스토어 백엔드와의 동기화 문제로 예상치 못한 난관을 초래할 수 있습니다. 저희는 첫 출시 심사 시 인앱 결제 상품 미로드로 인한 버튼 무반응 문제를 겪었지만, IAP 기능을 일시적으로 비활성화하고 단계적으로 활성화하는 전략을 통해 이를 성공적으로 해결했습니다. 이 경험이 첫 출시를 준비하는 다른 Flutter 개발자분들께도 도움이 되기를 바랍니다.

Top comments (0)