이 글의 성격은 무엇인가요?
질문 / 문제 해결
내용을 설명해주세요
안녕하세요. WebView 미니앱에서 방 초대 링크를 구현하는 과정에서 의도한 화면으로 진입하지 않는 현상이 있어 문의드립니다.
문제 상황
미니앱 내부에서 방을 만든 뒤, room과 invite 값을 포함한 intoss-private:// 주소를 구성하고 getTossShareLink()를 호출하고 있습니다.
구현 형태는 다음과 같습니다.
const queryParams = encodeURIComponent(
JSON.stringify({
room: "<roomId>",
invite: "<inviteCapability>",
}),
);
const deepLink =
"intoss-private://who-packs?_deploymentId=" + deploymentId +
"&queryParams=" + queryParams;
const shareUrl = await getTossShareLink(deepLink);
getTossShareLink()를 통해 생성된 링크를 열면 미니앱 자체는 실행됩니다. 다만 초대받은 참가자가 이름을 입력하는 화면이 아니라 앱의 초기 화면이 표시되고 있습니다.
현재로서는 공유 링크 진입 과정에서 파라미터가 전달되지 않는 것인지, 앱에서 진입 URI를 확인하는 시점이나 방법이 잘못된 것인지, 비공개 번들 테스트 환경에 별도 제약이 있는 것인지는 확실하지 않습니다.
실제 재현 링크
아래 링크는 getTossShareLink()를 통해 생성한 테스트용 초대 링크입니다.
앱의 구현 의도상 위 링크를 열면 해당 방의 참가자 이름 입력 화면이 표시되어야 합니다.
하지만 현재 확인한 환경에서는 미니앱이 실행된 후 앱 초기 화면이 표시됩니다.
기대한 동작
- 사용자가 공유된 minion.toss.im 링크를 엽니다.
- Toss 앱에서 who-packs 미니앱이 실행됩니다.
- 공유 링크에 포함한 room, invite 값이 앱에서 확인됩니다.
- 해당 방의 참가자 이름 입력 화면이 표시됩니다.
실제로 확인한 동작
- 사용자가 공유된 minion.toss.im 링크를 엽니다.
- Toss 앱에서 who-packs 미니앱이 실행됩니다.
- 별도의 오류 화면은 표시되지 않습니다.
- 참가자 이름 입력 화면이 아닌 앱 초기 화면이 표시됩니다.
미니앱 실행 자체는 정상적으로 보이지만, 초대 링크 진입으로 인식되지 않는 것으로 추정하고 있습니다.
일반 웹 환경과의 차이
동일한 방 참가 흐름을 일반 웹 환경에서 실행하면 다음 과정이 정상적으로 동작합니다.
- 방 생성
- 초대 링크 복사
- 초대 링크 접속
- 참가자 이름 입력 화면 표시
따라서 방 데이터나 참가 화면 자체의 문제보다는 Apps in Toss 공유 링크 진입 처리와 관련된 문제일 가능성을 우선 확인하고 있습니다. 다만 정확한 원인은 아직 확인하지 못했습니다.
트러블슈팅 및 개선 이력
1. 최신 비공개 번들 주소 사용
최신 비공개 번들의 _deploymentId를 포함해 다음과 같은 형태로 주소를 구성했습니다.
intoss-private://who-packs?_deploymentId=<latestDeploymentId>&queryParams=<URL-encoded JSON>
이후에는 테스트 권한이 있는 상대방 기기에서 미니앱 자체가 실행되는 것을 확인했습니다. 다만 앱이 실행된 뒤에도 참가자 이름 입력 화면이 아니라 초기 화면이 표시됐습니다.
2. queryParams 인코딩 및 파싱 보완
room, invite 값을 JSON으로 만든 뒤 전체 값을 encodeURIComponent()로 인코딩했습니다.
앱에서는 다음 형태를 처리할 수 있도록 진입 URI 파싱 로직을 보완했습니다.
- 일반 쿼리 파라미터로 전달되는 경우
- queryParams 안에 URL 인코딩된 JSON으로 전달되는 경우
- 값이 중첩 인코딩되어 전달되는 경우
로컬 환경에서 동일한 형태의 URI를 앱에 전달했을 때는 room, invite가 복원되고 참가자 이름 입력 화면으로 이동했습니다.
다만 실제 Toss 앱에서 앱이 수신하는 값도 로컬에서 사용한 URI와 완전히 동일한지는 확인하지 못했습니다.
3. 공유 링크의 리다이렉트 주소 확인
getTossShareLink()가 반환한 minion.toss.im 링크의 리다이렉트 주소를 확인했습니다.
확인한 URL 문자열에는 다음 항목이 포함된 것으로 보였습니다.
- intoss-private://who-packs
- 최신 _deploymentId
- URL 인코딩된 queryParams
- 테스트용 room, invite 값
따라서 공유 링크를 생성하는 시점에는 필요한 값이 포함되는 것으로 추정했습니다. 다만 실제 Toss 앱에서 WebView까지 동일한 값이 전달되는지는 확인하지 못했습니다.
4. 외부 스킴 래핑 가능성 대응
공유 링크 진입 과정에서 URI가 다음과 유사한 외부 스킴에 포함되어 전달될 가능성을 고려했습니다.
supertoss://total-services?redirect=<encoded URI>
이러한 형태라면 redirect 내부 URI를 다시 해석하도록 처리했습니다.
해당 로직을 적용한 뒤에도 실제 재현 링크에서는 앱 초기 화면이 표시됐습니다. 따라서 외부 스킴 래핑이 실제 원인인지는 확실하지 않습니다.
5. getSchemeUri() 호출 시점 보완
WebView 초기화 직후에는 getSchemeUri()가 아직 진입 URI를 반환하지 않을 가능성을 고려했습니다.
앱 시작 시 한 번만 확인하지 않고 다음과 같이 짧은 간격으로 제한적으로 다시 확인하도록 보완했습니다.
진입 직후 → 100ms 후 → 400ms 후
로컬 테스트에서 초기 호출은 비어 있고 이후 호출에서 URI가 반환되는 상황을 구성했을 때는 참가자 이름 입력 화면으로 정상 전환됐습니다.
다만 실제 Toss 앱에서도 동일한 시점 차이가 발생하는지는 확인하지 못했으며, 재확인 로직 적용 후에도 실제 공유 링크에서는 초기 화면이 표시됐습니다.
6. 로컬 회귀 테스트
다음 경우를 대상으로 로컬 테스트를 진행했습니다.
- 완전한 intoss-private:// URI 파싱
- URL 인코딩된 queryParams 파싱
- 외부 스킴의 redirect 파라미터 해석
- 초기 getSchemeUri() 값이 비어 있다가 이후 전달되는 경우
- 초대 정보를 확인한 뒤 참가자 이름 입력 화면으로 전환되는지 확인
구성한 로컬 테스트에서는 참가자 이름 입력 화면으로 이동했습니다.
다만 로컬에서 구성한 테스트가 실제 Toss 앱의 공유 링크 진입 동작을 정확히 재현한다고 단정하기는 어려운 상황입니다.
문의드리는 내용
- 비공개 번들 테스트에서도 intoss-private:// 주소를 getTossShareLink()에 전달하는 방식이 맞을까요?
- minion.toss.im 공유 링크를 통해 진입했을 때 getSchemeUri()가 반환하는 정상적인 문자열 형태를 확인할 수 있을까요?
- 비공개 번들에서는 _deploymentId와 queryParams의 위치 또는 인코딩 방식을 다르게 구성해야 할까요?
- 앱은 정상적으로 실행되지만 의도한 하위 화면으로 이동하지 않는 경우 추가로 확인해야 할 항목이 있을까요?
- getSchemeUri()를 확인해야 하는 권장 시점이나 별도의 진입 이벤트가 있을까요?
- 위 재현 링크가 운영 환경에서도 초기 화면으로 연결되는지 확인해 주실 수 있을까요?
개발 환경
- 개발 환경: WebView
- SDK: @apps-in-toss/web-framework@2.10.7
- 테스트 환경: .ait 비공개 번들 QR 테스트
- appName: who-packs
- 재현 링크: 토스
실제 테스트에 사용한 room, invite 값은 공개 게시글에서는 별도로 노출하지 않았습니다. 문제 확인에 필요하다면 민감한 값을 제거한 진입 URI와 getSchemeUri() 진단 정보를 추가로 전달드리겠습니다.
appName (선택)
who-packs

