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

next.js로 웹을 하나 만들어서 연동 테스트를 하는데 캡쳐 한 것과 같이 에러가 발생합니다. 어떻게 해야 할까요~?
No description
25 Replies
Ayaan이안
Ayaan이안2y ago
토스페이먼츠 sdk 를 귀사 넥스트앱에 설치 및 임포트 하셨을까요~?
목표를향해
목표를향해OP2y ago
<script type="text/javascript" async src="https://js.tosspayments.com/v1/payment-widget"></script> 다음과 같이 스크립트 추가 되어 있습니다.
Ayaan이안
Ayaan이안2y ago
npm 패키지로는 설치가 안되어있나요?
목표를향해
목표를향해OP2y ago
npm 패키지로 설치를 시도 해보지 않았습니다. npm 패키지로 설치해보겠습니다.
Ayaan이안
Ayaan이안2y ago
리엑트 기반서는 script 설치시 오류가 납니다.
목표를향해
목표를향해OP2y ago
No description
목표를향해
목표를향해OP2y 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>
)
}
Ayaan이안
Ayaan이안2y ago
v13 이신가요?
목표를향해
목표를향해OP2y ago
{
"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"
}
}
Ayaan이안
Ayaan이안2y ago
아하 베타버전이군요
목표를향해
목표를향해OP2y ago
loadPayments는 해결했는데~ 맨 처음 문제인 Unexpected identifier "TossPayments"가 여전히 나오네요~
Ayaan이안
Ayaan이안2y ago
import TossPayments from (sdk) 이런식으로 한다음에 load도 TossPayments를 init하여 돌려보시겠어요?
목표를향해
목표를향해OP2y ago
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";
Ayaan이안
Ayaan이안2y ago
흠.. 일반 웹에서 결제창이 뜨나요?
목표를향해
목표를향해OP2y ago
네~ 일반웹에서는 떠요~ 로컬에서 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
라는 이벤트를 발생하고 있나보네요~
Ayaan이안
Ayaan이안2y ago
음.. 그렇군요 그러면 지금 타입때문에 TossPayments를 다이렛트로 임포트가 안되는거죠?
목표를향해
목표를향해OP2y ago
네~ 다이렉트로는 안되고~ 샘플 예제 보고 처리 했습니다~
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 내부에서 보내고 있는거 같네요~
Ayaan이안
Ayaan이안2y ago
흠 일단 한번 토스쪽에 전달해야할거 같네요
today.lastday
today.lastday2y ago
next.js에서 위젯 구현 중이신가요?
today.lastday
today.lastday2y ago
GitHub
GitHub - tosspayments/payment-widget-sample: 토스페이먼츠 결제위젯 샘플 앱입니다.
토스페이먼츠 결제위젯 샘플 앱입니다. . Contribute to tosspayments/payment-widget-sample development by creating an account on GitHub.
Ayaan이안
Ayaan이안2y ago
@목표를향해 혹시 13버전 쓰시는거 같은데 app directory를 사용하고 계신가요?
목표를향해
목표를향해OP2y 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 이 모두 값이 없다고 나오네요~
Ayaan이안
Ayaan이안2y ago
토스쪽에서 보내는 드리고 있습니다만, 앱 디렉토리의 경우에는 아직 공식적으로 지원하지 않아서요.
목표를향해
목표를향해OP2y ago
아 그럼 page 형태로 내려서 해야겠군요~ 알겠습니다.
토스페이먼츠 BOT
❤️ 기술문의 경험이 어떠셨나요?!
간단히 코멘트 남겨주세요! 제품 발전에 큰 힘이 됩니다.

Did you find this page helpful?