webView로 연동해서 rednerPaymentMethods를 호출하면 TossPayments Unexpected identifier error가 발생합니다.

next.js로 웹을 하나 만들어서 연동 테스트를 하는데 캡쳐 한 것과 같이 에러가 발생합니다. 어떻게 해야 할까요~?
No description
7 Replies
목표를향해
목표를향해OP3y ago
<script type="text/javascript" async src="https://js.tosspayments.com/v1/payment-widget"></script> 다음과 같이 스크립트 추가 되어 있습니다. npm 패키지로 설치를 시도 해보지 않았습니다. npm 패키지로 설치해보겠습니다.
목표를향해
목표를향해OP3y ago
No description
목표를향해
목표를향해OP3y ago
npm 기반으로 변경해서 했더니 SyntaxError: JSON Parse error: Unexpected identifier "undefined" 에러가 발생합니다.
"use client";
import styles from './page.module.css'
import {useEffect, useMemo} from "react";
import {payManager} from "@/manager/payManager";
import {loadPaymentWidget} from "@tosspayments/payment-widget-sdk";

declare global {
interface Window {
ReactNativeWebView: any;
}
}

export default function Home() {
const payStyle = useMemo(() => ({ width: "100vw", height: "auto" }), []);


useEffect(() => {
loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", "test").then((data) => {
payManager.register(data);
});
return () => {
payManager.unregister();
}
})
return (
<main className={styles.main}>
<div id="payments-main" style={payStyle}></div>
</main>
)
}
"use client";
import styles from './page.module.css'
import {useEffect, useMemo} from "react";
import {payManager} from "@/manager/payManager";
import {loadPaymentWidget} from "@tosspayments/payment-widget-sdk";

declare global {
interface Window {
ReactNativeWebView: any;
}
}

export default function Home() {
const payStyle = useMemo(() => ({ width: "100vw", height: "auto" }), []);


useEffect(() => {
loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", "test").then((data) => {
payManager.register(data);
});
return () => {
payManager.unregister();
}
})
return (
<main className={styles.main}>
<div id="payments-main" style={payStyle}></div>
</main>
)
}
{
"name": "tosspayments-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@tosspayments/payment-widget-sdk": "^0.7.1",
"@types/node": "20.1.3",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"eslint": "8.40.0",
"eslint-config-next": "13.4.2",
"next": "13.4.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "5.0.4"
}
}
{
"name": "tosspayments-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@tosspayments/payment-widget-sdk": "^0.7.1",
"@types/node": "20.1.3",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"eslint": "8.40.0",
"eslint-config-next": "13.4.2",
"next": "13.4.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "5.0.4"
}
}
loadPayments는 해결했는데~ 맨 처음 문제인 Unexpected identifier "TossPayments"가 여전히 나오네요~
async handleInit(postData: PostData) {
const data = postData.data as InitDataType;
alert(`customerKey: ${data.customerKey}`)
alert(`amount: ${data.amount}`)

this.paymentWidget = await loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", data.customerKey);
this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
// ------ 결제위젯 초기화 ------
// this.paymentMethods = this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
}
async handleInit(postData: PostData) {
const data = postData.data as InitDataType;
alert(`customerKey: ${data.customerKey}`)
alert(`amount: ${data.amount}`)

this.paymentWidget = await loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", data.customerKey);
this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
// ------ 결제위젯 초기화 ------
// this.paymentMethods = this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
}
제가 RN에서 postMessage로 통신해서 init을 시도하는데~ TossPayments from sdk 형태로 한번 해보자는 말씀이신거죠~?
./src/manager/payManager.ts
Attempted import error: '@tosspayments/payment-widget-sdk' does not contain a default export (imported as 'TossPayments').
./src/manager/payManager.ts
Attempted import error: '@tosspayments/payment-widget-sdk' does not contain a default export (imported as 'TossPayments').
typescript define형태를 보니 바로 가져다가 못쓰는 형태로 되어 있네요~
export type { PaymentWidgetInstance } from '@tosspayments/payment-widget__types';
export { loadPaymentWidget } from './loadPaymentWidget';
export { clearPaymentWidget } from './clearPaymentWidget';
export declare const ANONYMOUS = "@@ANONYMOUS";
export type { PaymentWidgetInstance } from '@tosspayments/payment-widget__types';
export { loadPaymentWidget } from './loadPaymentWidget';
export { clearPaymentWidget } from './clearPaymentWidget';
export declare const ANONYMOUS = "@@ANONYMOUS";
네~ 일반웹에서는 떠요~ 로컬에서 localhost:3000으로 하면 결제창이 뜨더라구요~ 그래서 RN에서 테스트 하기 위해서 ngrok http 3000 으로 해서~ 테스트 해보고 있는데~ 여기에서도
export default function Home() {
const payStyle = useMemo(() => ({ width: "100vw", height: "auto" }), []);


useEffect(() => {
payManager.register();
return () => {
payManager.unregister();
}
})
return (
<main className={styles.main}>
<div id="payments-main" style={payStyle}></div>
</main>
)
}
export default function Home() {
const payStyle = useMemo(() => ({ width: "100vw", height: "auto" }), []);


useEffect(() => {
payManager.register();
return () => {
payManager.unregister();
}
})
return (
<main className={styles.main}>
<div id="payments-main" style={payStyle}></div>
</main>
)
}
useEffect안에서 다 넣어 버리면 문제 없이 창이 뜨긴 하는데~ payManager에서 postMessage로 handleInit으로 부르면 저 객체가 없다고 발생하고 있으니~
async handleInit(postData: PostData) {
const data = postData.data as InitDataType;

this.paymentWidget = await loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", data.customerKey);
this.paymentWidget.renderPaymentMethods("#payments-main", 1000);
// ------ 결제위젯 초기화 ------
// this.paymentMethods = this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
}
async handleInit(postData: PostData) {
const data = postData.data as InitDataType;

this.paymentWidget = await loadPaymentWidget("test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq", data.customerKey);
this.paymentWidget.renderPaymentMethods("#payments-main", 1000);
// ------ 결제위젯 초기화 ------
// this.paymentMethods = this.paymentWidget.renderPaymentMethods("#payments-main", data.amount);
}
여기서 loadPaymentWidget까지는 문제 없고, renderPaymentMethods를 호출하면 에러가 발생하네요~ 아 이제 알았네요~ 내부에서 postMessageData Event를 보내고 있네요~
TossPayments.PaymentWidget:initalize:payment-methods
TossPayments.PaymentWidget:initalize:payment-methods
라는 이벤트를 발생하고 있나보네요~ 네~ 다이렉트로는 안되고~ 샘플 예제 보고 처리 했습니다~
register() {
if (this.checkMobile() === "ios") {
window.addEventListener("message", this.receive.bind(this))
} else {
document.addEventListener("message", this.receive.bind(this))
}
this.postMessage({
message: "MESSAGE_READY"
})
}
register() {
if (this.checkMobile() === "ios") {
window.addEventListener("message", this.receive.bind(this))
} else {
document.addEventListener("message", this.receive.bind(this))
}
this.postMessage({
message: "MESSAGE_READY"
})
}
message를 TossPayments 내부에서 보내고 있는거 같네요~
today.lastday
today.lastday3y ago
next.js에서 위젯 구현 중이신가요?
today.lastday
today.lastday3y ago
GitHub
GitHub - tosspayments/payment-widget-sample: 토스페이먼츠 결제위젯 샘플 앱입니다.
토스페이먼츠 결제위젯 샘플 앱입니다. . Contribute to tosspayments/payment-widget-sample development by creating an account on GitHub.
목표를향해
목표를향해OP3y ago
네~ 대답이 늦었습니다. app directory를 사용하고 있습니다.
'use client';

import {useSearchParams} from 'next/navigation';
import {payManager} from "@/manager/payManager";

export default function SuccessPage() {
const searchParams = useSearchParams();
const paymentKey = searchParams.get("paymentKey") ?? ""
const orderId = searchParams.get("orderId") ?? ""
const amount = parseInt(searchParams.get("amount") ?? "0")

payManager.postMessage({
message: "REQUEST_CONFIRM_TOSS_PAY",
data: {
paymentKey,
orderId,
amount,
}
})

return <main></main>
}
'use client';

import {useSearchParams} from 'next/navigation';
import {payManager} from "@/manager/payManager";

export default function SuccessPage() {
const searchParams = useSearchParams();
const paymentKey = searchParams.get("paymentKey") ?? ""
const orderId = searchParams.get("orderId") ?? ""
const amount = parseInt(searchParams.get("amount") ?? "0")

payManager.postMessage({
message: "REQUEST_CONFIRM_TOSS_PAY",
data: {
paymentKey,
orderId,
amount,
}
})

return <main></main>
}
success url에 해당 쿼리가 불려지지가 않는데요~ 이건 어떻게 디버깅해봐야 할까요~? 토스쪽에서 보내주고 있는지가 궁금합니다. paymentKey, orderId, amount 이 모두 값이 없다고 나오네요~ 아 그럼 page 형태로 내려서 해야겠군요~ 알겠습니다.
토스페이먼츠 BOT
❤️ 기술문의 경험이 어떠셨나요?!
간단히 코멘트 남겨주세요! 제품 발전에 큰 힘이 됩니다.

Did you find this page helpful?