@apps-in-toss/framework 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +150 -9
- package/dist/index.d.cts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +146 -6
- package/package.json +7 -7
- package/src/async-bridges.ts +1 -0
package/dist/index.cjs
CHANGED
|
@@ -44,6 +44,7 @@ __export(src_exports, {
|
|
|
44
44
|
getDeviceId: () => getDeviceId,
|
|
45
45
|
getOperationalEnvironment: () => getOperationalEnvironment,
|
|
46
46
|
getTossAppVersion: () => getTossAppVersion,
|
|
47
|
+
getTossShareLink: () => getTossShareLink,
|
|
47
48
|
openCamera: () => openCamera,
|
|
48
49
|
setClipboardText: () => setClipboardText,
|
|
49
50
|
startUpdateLocation: () => startUpdateLocation,
|
|
@@ -99,7 +100,10 @@ function TDSContainer({ children }) {
|
|
|
99
100
|
function registerApp(container, { context }) {
|
|
100
101
|
return import_react_native_bedrock.Bedrock.registerApp(AppsInTossContainer.bind(null, container), {
|
|
101
102
|
appName: getAppName(),
|
|
102
|
-
context
|
|
103
|
+
context,
|
|
104
|
+
defaultScreenOption: {
|
|
105
|
+
statusBarStyle: "dark"
|
|
106
|
+
}
|
|
103
107
|
});
|
|
104
108
|
}
|
|
105
109
|
function getAppName() {
|
|
@@ -318,6 +322,15 @@ var Storage = {
|
|
|
318
322
|
clearItems
|
|
319
323
|
};
|
|
320
324
|
|
|
325
|
+
// src/native-modules/getTossShareLink.ts
|
|
326
|
+
async function getTossShareLink(path) {
|
|
327
|
+
const { shareLink } = await AppsInTossModule.getTossShareLink({});
|
|
328
|
+
const shareUrl = new URL(shareLink);
|
|
329
|
+
shareUrl.searchParams.set("deep_link_value", path);
|
|
330
|
+
shareUrl.searchParams.set("af_dp", path);
|
|
331
|
+
return shareUrl.toString();
|
|
332
|
+
}
|
|
333
|
+
|
|
321
334
|
// src/native-modules/index.ts
|
|
322
335
|
var TossPay = {
|
|
323
336
|
checkoutPayment,
|
|
@@ -327,7 +340,7 @@ var TossPay = {
|
|
|
327
340
|
// src/components/WebView.tsx
|
|
328
341
|
var import_react_native12 = require("@toss-design-system/react-native");
|
|
329
342
|
var import_private = require("@toss-design-system/react-native/private");
|
|
330
|
-
var
|
|
343
|
+
var import_react4 = require("react");
|
|
331
344
|
var import_react_native_bedrock5 = require("react-native-bedrock");
|
|
332
345
|
var bedrockAsyncBridges = __toESM(require("react-native-bedrock/async-bridges"), 1);
|
|
333
346
|
var bedrockConstantBridges = __toESM(require("react-native-bedrock/constant-bridges"), 1);
|
|
@@ -487,10 +500,137 @@ __export(async_bridges_exports, {
|
|
|
487
500
|
fetchContacts: () => fetchContacts,
|
|
488
501
|
getClipboardText: () => getClipboardText,
|
|
489
502
|
getCurrentLocation: () => getCurrentLocation,
|
|
503
|
+
getTossShareLink: () => getTossShareLink,
|
|
490
504
|
openCamera: () => openCamera,
|
|
491
505
|
setClipboardText: () => setClipboardText
|
|
492
506
|
});
|
|
493
507
|
|
|
508
|
+
// src/bridge-handler/useBridgeHandler.tsx
|
|
509
|
+
var import_react3 = require("react");
|
|
510
|
+
function serializeError(error) {
|
|
511
|
+
return JSON.stringify(error, (_, value) => {
|
|
512
|
+
if (value instanceof Error) {
|
|
513
|
+
return {
|
|
514
|
+
name: value.name,
|
|
515
|
+
message: value.message,
|
|
516
|
+
stack: value.stack,
|
|
517
|
+
__isError: true
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
return value;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function methodHandler({
|
|
524
|
+
args,
|
|
525
|
+
eventId,
|
|
526
|
+
functionName,
|
|
527
|
+
handlerMap,
|
|
528
|
+
injectJavaScript
|
|
529
|
+
}) {
|
|
530
|
+
const func = async (...args2) => {
|
|
531
|
+
const result = await handlerMap[functionName](...args2);
|
|
532
|
+
return result;
|
|
533
|
+
};
|
|
534
|
+
if (!func) {
|
|
535
|
+
console.error(`${functionName} is not a function`);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
func(...args).then((result) => {
|
|
539
|
+
injectJavaScript?.(`
|
|
540
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/resolve/${eventId}', ${JSON.stringify(result, null, 0)});
|
|
541
|
+
`);
|
|
542
|
+
}).catch((error) => {
|
|
543
|
+
const serializedError = serializeError(error);
|
|
544
|
+
injectJavaScript?.(`
|
|
545
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/reject/${eventId}', ${serializedError});
|
|
546
|
+
`);
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
var globalEventListenerMap = /* @__PURE__ */ new Map();
|
|
550
|
+
function useBridgeHandler({
|
|
551
|
+
onMessage,
|
|
552
|
+
constantHandlerMap,
|
|
553
|
+
asyncHandlerMap,
|
|
554
|
+
eventListenerMap,
|
|
555
|
+
injectedJavaScript: originalInjectedJavaScript
|
|
556
|
+
}) {
|
|
557
|
+
const ref = (0, import_react3.useRef)(null);
|
|
558
|
+
const injectedJavaScript = (0, import_react3.useMemo)(
|
|
559
|
+
() => [
|
|
560
|
+
`window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
|
|
561
|
+
Object.entries(constantHandlerMap).reduce(
|
|
562
|
+
(acc, [key, value]) => {
|
|
563
|
+
acc[key] = typeof value === "function" ? value() : value;
|
|
564
|
+
return acc;
|
|
565
|
+
},
|
|
566
|
+
{}
|
|
567
|
+
)
|
|
568
|
+
)}`,
|
|
569
|
+
originalInjectedJavaScript,
|
|
570
|
+
"true"
|
|
571
|
+
].join("\n"),
|
|
572
|
+
[constantHandlerMap, originalInjectedJavaScript]
|
|
573
|
+
);
|
|
574
|
+
const createHandleOnEvent = (functionName, eventId) => (response) => {
|
|
575
|
+
ref.current?.injectJavaScript(`
|
|
576
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onEvent/${eventId}', ${JSON.stringify(response, null, 0)});
|
|
577
|
+
`);
|
|
578
|
+
};
|
|
579
|
+
const createHandleOnError = (functionName, eventId) => (error) => {
|
|
580
|
+
ref.current?.injectJavaScript(`
|
|
581
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${JSON.stringify(error, null, 0)});
|
|
582
|
+
`);
|
|
583
|
+
};
|
|
584
|
+
const $onMessage = (0, import_react3.useCallback)(
|
|
585
|
+
async (e) => {
|
|
586
|
+
onMessage?.(e);
|
|
587
|
+
const data = JSON.parse(e.nativeEvent.data);
|
|
588
|
+
if (typeof data !== "object" || data === null || typeof data.functionName !== "string" || typeof data.eventId !== "string" || typeof data.type !== "string" || !["addEventListener", "removeEventListener", "method"].includes(data.type)) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
switch (data.type) {
|
|
592
|
+
case "addEventListener": {
|
|
593
|
+
const handleOnEvent = createHandleOnEvent(data.functionName, data.eventId);
|
|
594
|
+
const handleOnError = createHandleOnError(data.functionName, data.eventId);
|
|
595
|
+
const remove = eventListenerMap[data.functionName]?.({
|
|
596
|
+
onEvent: handleOnEvent,
|
|
597
|
+
onError: handleOnError,
|
|
598
|
+
options: data.args
|
|
599
|
+
});
|
|
600
|
+
if (remove) {
|
|
601
|
+
globalEventListenerMap.set(`${data.functionName}/${data.eventId}`, remove);
|
|
602
|
+
}
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
case "removeEventListener": {
|
|
606
|
+
const key = `${data.functionName}/${data.eventId}`;
|
|
607
|
+
const remove = globalEventListenerMap.get(key);
|
|
608
|
+
remove?.();
|
|
609
|
+
globalEventListenerMap.delete(key);
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
case "method": {
|
|
613
|
+
methodHandler({
|
|
614
|
+
args: data.args,
|
|
615
|
+
eventId: data.eventId,
|
|
616
|
+
functionName: data.functionName,
|
|
617
|
+
handlerMap: asyncHandlerMap,
|
|
618
|
+
injectJavaScript: ref.current?.injectJavaScript
|
|
619
|
+
});
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
625
|
+
[onMessage]
|
|
626
|
+
);
|
|
627
|
+
return {
|
|
628
|
+
ref,
|
|
629
|
+
injectedJavaScript,
|
|
630
|
+
onMessage: $onMessage
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
494
634
|
// src/constant-bridges.ts
|
|
495
635
|
var constant_bridges_exports = {};
|
|
496
636
|
__export(constant_bridges_exports, {
|
|
@@ -546,10 +686,10 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
546
686
|
throw new Error(`Invalid WebView type: '${type}'`);
|
|
547
687
|
}
|
|
548
688
|
const bedrockEvent = (0, import_react_native_bedrock5.useBedrockEvent)();
|
|
549
|
-
const uri = (0,
|
|
689
|
+
const uri = (0, import_react4.useMemo)(() => getWebViewUri(local), [local]);
|
|
550
690
|
const top = (0, import_private.useSafeAreaTop)();
|
|
551
691
|
const bottom = (0, import_private.useSafeAreaBottom)();
|
|
552
|
-
const handler =
|
|
692
|
+
const handler = useBridgeHandler({
|
|
553
693
|
onMessage,
|
|
554
694
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
555
695
|
eventListenerMap: {
|
|
@@ -578,7 +718,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
578
718
|
clearItems: Storage.clearItems
|
|
579
719
|
}
|
|
580
720
|
});
|
|
581
|
-
const baseProps = (0,
|
|
721
|
+
const baseProps = (0, import_react4.useMemo)(() => {
|
|
582
722
|
switch (type) {
|
|
583
723
|
case "partner": {
|
|
584
724
|
const headerOnlyProp = {
|
|
@@ -608,7 +748,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
608
748
|
}
|
|
609
749
|
}, [type, props]);
|
|
610
750
|
const BaseWebView = WEBVIEW_TYPES[type];
|
|
611
|
-
const webviewDebuggingEnabled = (0,
|
|
751
|
+
const webviewDebuggingEnabled = (0, import_react4.useMemo)(
|
|
612
752
|
() => getOperationalEnvironment() === "sandbox",
|
|
613
753
|
[]
|
|
614
754
|
);
|
|
@@ -636,12 +776,12 @@ function ensureValue(value, name) {
|
|
|
636
776
|
}
|
|
637
777
|
|
|
638
778
|
// src/hooks/useGeolocation.ts
|
|
639
|
-
var
|
|
779
|
+
var import_react5 = require("react");
|
|
640
780
|
var import_react_native_bedrock6 = require("react-native-bedrock");
|
|
641
781
|
function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
642
782
|
const isVisible = (0, import_react_native_bedrock6.useVisibility)();
|
|
643
|
-
const [location, setLocation] = (0,
|
|
644
|
-
(0,
|
|
783
|
+
const [location, setLocation] = (0, import_react5.useState)(null);
|
|
784
|
+
(0, import_react5.useEffect)(() => {
|
|
645
785
|
if (!isVisible) {
|
|
646
786
|
return;
|
|
647
787
|
}
|
|
@@ -684,6 +824,7 @@ var Accuracy2 = /* @__PURE__ */ ((Accuracy3) => {
|
|
|
684
824
|
getDeviceId,
|
|
685
825
|
getOperationalEnvironment,
|
|
686
826
|
getTossAppVersion,
|
|
827
|
+
getTossShareLink,
|
|
687
828
|
openCamera,
|
|
688
829
|
setClipboardText,
|
|
689
830
|
startUpdateLocation,
|
package/dist/index.d.cts
CHANGED
|
@@ -70,7 +70,7 @@ interface Location {
|
|
|
70
70
|
*/
|
|
71
71
|
timestamp: number;
|
|
72
72
|
/**
|
|
73
|
-
* @description 위치 정보를 나타내는 객체예요. 자세한 내용은 [LocationCoords](/reference/framework/Types/LocationCoords.html)을 참고해주세요.
|
|
73
|
+
* @description 위치 정보를 나타내는 객체예요. 자세한 내용은 [LocationCoords](/react-native/reference/framework/Types/LocationCoords.html)을 참고해주세요.
|
|
74
74
|
*/
|
|
75
75
|
coords: LocationCoords;
|
|
76
76
|
}
|
|
@@ -154,7 +154,7 @@ interface UpdateLocationEventEmitter extends EventEmitterSchema<'updateLocation'
|
|
|
154
154
|
* @param {number} [options.accuracy] 위치 정확도를 설정해요.
|
|
155
155
|
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
156
156
|
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
157
|
-
* @param {(location: Location) => void} [options.callback] 위치 정보가 변경될 때 호출되는 콜백 함수예요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
157
|
+
* @param {(location: Location) => void} [options.callback] 위치 정보가 변경될 때 호출되는 콜백 함수예요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
158
158
|
*
|
|
159
159
|
* @example
|
|
160
160
|
* ### 위치 정보 변경 감지하기
|
|
@@ -858,7 +858,7 @@ interface GetCurrentLocationOptions {
|
|
|
858
858
|
*
|
|
859
859
|
* @param {GetCurrentLocationOptions} options 위치 정보를 가져올 때 사용하는 옵션 객체예요.
|
|
860
860
|
* @param {Accuracy} [options.accuracy] 위치 정보의 정확도 수준이에요. 정확도는 `Accuracy` 타입으로 설정돼요.
|
|
861
|
-
* @returns {Promise<Location>} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
861
|
+
* @returns {Promise<Location>} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
862
862
|
*
|
|
863
863
|
* @example
|
|
864
864
|
* ### 디바이스의 현재 위치 정보 가져오기
|
|
@@ -1171,6 +1171,36 @@ declare const Storage: {
|
|
|
1171
1171
|
clearItems: typeof clearItems;
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
+
/**
|
|
1175
|
+
* @public
|
|
1176
|
+
* @category 공유
|
|
1177
|
+
* @kind function
|
|
1178
|
+
* @name getTossShareLink
|
|
1179
|
+
* @description
|
|
1180
|
+
* `getTossShareLink` 함수는 사용자가 지정한 경로를 토스 앱에서 열 수 공유 링크를 반환해요.
|
|
1181
|
+
* 이 링크를 다른 사람과 공유하면 토스 앱이 실행되면서 지정한 경로로 진입해요. 토스앱이 없는 사람은 iOS 일 때는 앱스토어로 이동하고, Android 일 때는 플레이스토어로 이동해요.
|
|
1182
|
+
*
|
|
1183
|
+
* 경로는 토스 앱 내부 특정 화면을 나타내는 딥링크(deep link) 형식이어야 해요.
|
|
1184
|
+
* 예를 들어 `intoss://<앱 이름>`이나 `intoss://<앱 이름>/about?name=test`처럼 작성해요.
|
|
1185
|
+
*
|
|
1186
|
+
* 이 함수를 사용하면 `deep_link_value`를 포함한 완성된 공유 링크를 만들 수 있어요.
|
|
1187
|
+
*
|
|
1188
|
+
* @param path - 딥링크로 열고 싶은 경로예요. `intoss://`로 시작하는 문자열이어야 해요.
|
|
1189
|
+
* @returns {Promise<string>} `deep_link_value`가 포함된 토스 공유 링크를 반환해요.
|
|
1190
|
+
*
|
|
1191
|
+
* @example
|
|
1192
|
+
* ```tsx
|
|
1193
|
+
* import { getTossShareLink, share } from '@apps-in-toss/framework';
|
|
1194
|
+
*
|
|
1195
|
+
* // '/' 경로를 딥링크로 포함한 토스 공유 링크를 생성해요.
|
|
1196
|
+
* const tossLink = await getTossShareLink('intoss://my-app');
|
|
1197
|
+
*
|
|
1198
|
+
* // 생성한 링크를 메시지로 공유해요.
|
|
1199
|
+
* await share({ message: tossLink });
|
|
1200
|
+
* ```
|
|
1201
|
+
*/
|
|
1202
|
+
declare function getTossShareLink(path: string): Promise<string>;
|
|
1203
|
+
|
|
1174
1204
|
/**
|
|
1175
1205
|
* @public
|
|
1176
1206
|
* @category 토스페이
|
|
@@ -1220,7 +1250,7 @@ type UseGeolocationOptions = Omit<StartUpdateLocationOptions, 'callback'>;
|
|
|
1220
1250
|
* @param {Accuracy} [options.accuracy] 위치 정확도를 설정해요. `Accuracy.Lowest`: 오차범위 3KM 이내, `Accuracy.Low`: 오차범위 1KM 이내, `Accuracy.Balanced`: 오차범위 몇 백미터 이내, `Accuracy.High`: 오차범위 10M 이내, `Accuracy.Highest`: 가장 높은 정확도, `Accuracy.BestForNavigation`: 네비게이션을 위한 최고 정확도
|
|
1221
1251
|
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
1222
1252
|
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
1223
|
-
* @returns {Location | null} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
1253
|
+
* @returns {Location | null} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
1224
1254
|
*
|
|
1225
1255
|
* @example
|
|
1226
1256
|
* ### 위치 정보 변경 감지하기
|
|
@@ -1256,4 +1286,4 @@ declare const env: {
|
|
|
1256
1286
|
getDeploymentId: () => string | undefined;
|
|
1257
1287
|
};
|
|
1258
1288
|
|
|
1259
|
-
export { Accuracy, AppsInToss, type ContactEntity, type ExternalWebViewProps, type FetchAlbumPhotosOptions, type GameWebViewProps, type GetCurrentLocationOptions, type ImageResponse, type Location, type LocationCoords, type OpenCameraOptions, type PartnerWebViewProps, type StartUpdateLocationOptions, type StartUpdateLocationSubscription, Storage, TossPay, type UpdateLocationEventEmitter, type UseGeolocationOptions, WebView, type WebViewProps, appLogin, env, fetchAlbumPhotos, fetchContacts, getClipboardText, getCurrentLocation, getDeviceId, getOperationalEnvironment, getTossAppVersion, openCamera, setClipboardText, startUpdateLocation, useGeolocation };
|
|
1289
|
+
export { Accuracy, AppsInToss, type ContactEntity, type ExternalWebViewProps, type FetchAlbumPhotosOptions, type GameWebViewProps, type GetCurrentLocationOptions, type ImageResponse, type Location, type LocationCoords, type OpenCameraOptions, type PartnerWebViewProps, type StartUpdateLocationOptions, type StartUpdateLocationSubscription, Storage, TossPay, type UpdateLocationEventEmitter, type UseGeolocationOptions, WebView, type WebViewProps, appLogin, env, fetchAlbumPhotos, fetchContacts, getClipboardText, getCurrentLocation, getDeviceId, getOperationalEnvironment, getTossAppVersion, getTossShareLink, openCamera, setClipboardText, startUpdateLocation, useGeolocation };
|
package/dist/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ interface Location {
|
|
|
70
70
|
*/
|
|
71
71
|
timestamp: number;
|
|
72
72
|
/**
|
|
73
|
-
* @description 위치 정보를 나타내는 객체예요. 자세한 내용은 [LocationCoords](/reference/framework/Types/LocationCoords.html)을 참고해주세요.
|
|
73
|
+
* @description 위치 정보를 나타내는 객체예요. 자세한 내용은 [LocationCoords](/react-native/reference/framework/Types/LocationCoords.html)을 참고해주세요.
|
|
74
74
|
*/
|
|
75
75
|
coords: LocationCoords;
|
|
76
76
|
}
|
|
@@ -154,7 +154,7 @@ interface UpdateLocationEventEmitter extends EventEmitterSchema<'updateLocation'
|
|
|
154
154
|
* @param {number} [options.accuracy] 위치 정확도를 설정해요.
|
|
155
155
|
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
156
156
|
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
157
|
-
* @param {(location: Location) => void} [options.callback] 위치 정보가 변경될 때 호출되는 콜백 함수예요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
157
|
+
* @param {(location: Location) => void} [options.callback] 위치 정보가 변경될 때 호출되는 콜백 함수예요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
158
158
|
*
|
|
159
159
|
* @example
|
|
160
160
|
* ### 위치 정보 변경 감지하기
|
|
@@ -858,7 +858,7 @@ interface GetCurrentLocationOptions {
|
|
|
858
858
|
*
|
|
859
859
|
* @param {GetCurrentLocationOptions} options 위치 정보를 가져올 때 사용하는 옵션 객체예요.
|
|
860
860
|
* @param {Accuracy} [options.accuracy] 위치 정보의 정확도 수준이에요. 정확도는 `Accuracy` 타입으로 설정돼요.
|
|
861
|
-
* @returns {Promise<Location>} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
861
|
+
* @returns {Promise<Location>} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
862
862
|
*
|
|
863
863
|
* @example
|
|
864
864
|
* ### 디바이스의 현재 위치 정보 가져오기
|
|
@@ -1171,6 +1171,36 @@ declare const Storage: {
|
|
|
1171
1171
|
clearItems: typeof clearItems;
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
+
/**
|
|
1175
|
+
* @public
|
|
1176
|
+
* @category 공유
|
|
1177
|
+
* @kind function
|
|
1178
|
+
* @name getTossShareLink
|
|
1179
|
+
* @description
|
|
1180
|
+
* `getTossShareLink` 함수는 사용자가 지정한 경로를 토스 앱에서 열 수 공유 링크를 반환해요.
|
|
1181
|
+
* 이 링크를 다른 사람과 공유하면 토스 앱이 실행되면서 지정한 경로로 진입해요. 토스앱이 없는 사람은 iOS 일 때는 앱스토어로 이동하고, Android 일 때는 플레이스토어로 이동해요.
|
|
1182
|
+
*
|
|
1183
|
+
* 경로는 토스 앱 내부 특정 화면을 나타내는 딥링크(deep link) 형식이어야 해요.
|
|
1184
|
+
* 예를 들어 `intoss://<앱 이름>`이나 `intoss://<앱 이름>/about?name=test`처럼 작성해요.
|
|
1185
|
+
*
|
|
1186
|
+
* 이 함수를 사용하면 `deep_link_value`를 포함한 완성된 공유 링크를 만들 수 있어요.
|
|
1187
|
+
*
|
|
1188
|
+
* @param path - 딥링크로 열고 싶은 경로예요. `intoss://`로 시작하는 문자열이어야 해요.
|
|
1189
|
+
* @returns {Promise<string>} `deep_link_value`가 포함된 토스 공유 링크를 반환해요.
|
|
1190
|
+
*
|
|
1191
|
+
* @example
|
|
1192
|
+
* ```tsx
|
|
1193
|
+
* import { getTossShareLink, share } from '@apps-in-toss/framework';
|
|
1194
|
+
*
|
|
1195
|
+
* // '/' 경로를 딥링크로 포함한 토스 공유 링크를 생성해요.
|
|
1196
|
+
* const tossLink = await getTossShareLink('intoss://my-app');
|
|
1197
|
+
*
|
|
1198
|
+
* // 생성한 링크를 메시지로 공유해요.
|
|
1199
|
+
* await share({ message: tossLink });
|
|
1200
|
+
* ```
|
|
1201
|
+
*/
|
|
1202
|
+
declare function getTossShareLink(path: string): Promise<string>;
|
|
1203
|
+
|
|
1174
1204
|
/**
|
|
1175
1205
|
* @public
|
|
1176
1206
|
* @category 토스페이
|
|
@@ -1220,7 +1250,7 @@ type UseGeolocationOptions = Omit<StartUpdateLocationOptions, 'callback'>;
|
|
|
1220
1250
|
* @param {Accuracy} [options.accuracy] 위치 정확도를 설정해요. `Accuracy.Lowest`: 오차범위 3KM 이내, `Accuracy.Low`: 오차범위 1KM 이내, `Accuracy.Balanced`: 오차범위 몇 백미터 이내, `Accuracy.High`: 오차범위 10M 이내, `Accuracy.Highest`: 가장 높은 정확도, `Accuracy.BestForNavigation`: 네비게이션을 위한 최고 정확도
|
|
1221
1251
|
* @param {number} [options.timeInterval] 위치 정보를 업데이트하는 최소 주기로, 단위는 밀리초(ms)예요. 이 값은 위치 업데이트가 발생하는 가장 짧은 간격을 설정하지만, 시스템이나 환경의 영향을 받아 지정한 주기보다 더 긴 간격으로 업데이트될 수 있어요.
|
|
1222
1252
|
* @param {number} [options.distanceInterval] 위치 변경 거리를 미터(m) 단위로 설정해요.
|
|
1223
|
-
* @returns {Location | null} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/reference/framework/Types/Location.html)을 참고해주세요.
|
|
1253
|
+
* @returns {Location | null} 디바이스의 위치 정보가 담긴 객체를 반환해요. 자세한 내용은 [Location](/react-native/reference/framework/Types/Location.html)을 참고해주세요.
|
|
1224
1254
|
*
|
|
1225
1255
|
* @example
|
|
1226
1256
|
* ### 위치 정보 변경 감지하기
|
|
@@ -1256,4 +1286,4 @@ declare const env: {
|
|
|
1256
1286
|
getDeploymentId: () => string | undefined;
|
|
1257
1287
|
};
|
|
1258
1288
|
|
|
1259
|
-
export { Accuracy, AppsInToss, type ContactEntity, type ExternalWebViewProps, type FetchAlbumPhotosOptions, type GameWebViewProps, type GetCurrentLocationOptions, type ImageResponse, type Location, type LocationCoords, type OpenCameraOptions, type PartnerWebViewProps, type StartUpdateLocationOptions, type StartUpdateLocationSubscription, Storage, TossPay, type UpdateLocationEventEmitter, type UseGeolocationOptions, WebView, type WebViewProps, appLogin, env, fetchAlbumPhotos, fetchContacts, getClipboardText, getCurrentLocation, getDeviceId, getOperationalEnvironment, getTossAppVersion, openCamera, setClipboardText, startUpdateLocation, useGeolocation };
|
|
1289
|
+
export { Accuracy, AppsInToss, type ContactEntity, type ExternalWebViewProps, type FetchAlbumPhotosOptions, type GameWebViewProps, type GetCurrentLocationOptions, type ImageResponse, type Location, type LocationCoords, type OpenCameraOptions, type PartnerWebViewProps, type StartUpdateLocationOptions, type StartUpdateLocationSubscription, Storage, TossPay, type UpdateLocationEventEmitter, type UseGeolocationOptions, WebView, type WebViewProps, appLogin, env, fetchAlbumPhotos, fetchContacts, getClipboardText, getCurrentLocation, getDeviceId, getOperationalEnvironment, getTossAppVersion, getTossShareLink, openCamera, setClipboardText, startUpdateLocation, useGeolocation };
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,10 @@ function TDSContainer({ children }) {
|
|
|
52
52
|
function registerApp(container, { context }) {
|
|
53
53
|
return Bedrock.registerApp(AppsInTossContainer.bind(null, container), {
|
|
54
54
|
appName: getAppName(),
|
|
55
|
-
context
|
|
55
|
+
context,
|
|
56
|
+
defaultScreenOption: {
|
|
57
|
+
statusBarStyle: "dark"
|
|
58
|
+
}
|
|
56
59
|
});
|
|
57
60
|
}
|
|
58
61
|
function getAppName() {
|
|
@@ -271,6 +274,15 @@ var Storage = {
|
|
|
271
274
|
clearItems
|
|
272
275
|
};
|
|
273
276
|
|
|
277
|
+
// src/native-modules/getTossShareLink.ts
|
|
278
|
+
async function getTossShareLink(path) {
|
|
279
|
+
const { shareLink } = await AppsInTossModule.getTossShareLink({});
|
|
280
|
+
const shareUrl = new URL(shareLink);
|
|
281
|
+
shareUrl.searchParams.set("deep_link_value", path);
|
|
282
|
+
shareUrl.searchParams.set("af_dp", path);
|
|
283
|
+
return shareUrl.toString();
|
|
284
|
+
}
|
|
285
|
+
|
|
274
286
|
// src/native-modules/index.ts
|
|
275
287
|
var TossPay = {
|
|
276
288
|
checkoutPayment,
|
|
@@ -283,8 +295,8 @@ import {
|
|
|
283
295
|
ExternalWebViewScreen
|
|
284
296
|
} from "@toss-design-system/react-native";
|
|
285
297
|
import { useSafeAreaBottom, useSafeAreaTop as useSafeAreaTop2 } from "@toss-design-system/react-native/private";
|
|
286
|
-
import { useMemo } from "react";
|
|
287
|
-
import { getSchemeUri,
|
|
298
|
+
import { useMemo as useMemo2 } from "react";
|
|
299
|
+
import { getSchemeUri, useBedrockEvent } from "react-native-bedrock";
|
|
288
300
|
import * as bedrockAsyncBridges from "react-native-bedrock/async-bridges";
|
|
289
301
|
import * as bedrockConstantBridges from "react-native-bedrock/constant-bridges";
|
|
290
302
|
|
|
@@ -445,10 +457,137 @@ __export(async_bridges_exports, {
|
|
|
445
457
|
fetchContacts: () => fetchContacts,
|
|
446
458
|
getClipboardText: () => getClipboardText,
|
|
447
459
|
getCurrentLocation: () => getCurrentLocation,
|
|
460
|
+
getTossShareLink: () => getTossShareLink,
|
|
448
461
|
openCamera: () => openCamera,
|
|
449
462
|
setClipboardText: () => setClipboardText
|
|
450
463
|
});
|
|
451
464
|
|
|
465
|
+
// src/bridge-handler/useBridgeHandler.tsx
|
|
466
|
+
import { useCallback as useCallback2, useMemo, useRef } from "react";
|
|
467
|
+
function serializeError(error) {
|
|
468
|
+
return JSON.stringify(error, (_, value) => {
|
|
469
|
+
if (value instanceof Error) {
|
|
470
|
+
return {
|
|
471
|
+
name: value.name,
|
|
472
|
+
message: value.message,
|
|
473
|
+
stack: value.stack,
|
|
474
|
+
__isError: true
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
return value;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
function methodHandler({
|
|
481
|
+
args,
|
|
482
|
+
eventId,
|
|
483
|
+
functionName,
|
|
484
|
+
handlerMap,
|
|
485
|
+
injectJavaScript
|
|
486
|
+
}) {
|
|
487
|
+
const func = async (...args2) => {
|
|
488
|
+
const result = await handlerMap[functionName](...args2);
|
|
489
|
+
return result;
|
|
490
|
+
};
|
|
491
|
+
if (!func) {
|
|
492
|
+
console.error(`${functionName} is not a function`);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
func(...args).then((result) => {
|
|
496
|
+
injectJavaScript?.(`
|
|
497
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/resolve/${eventId}', ${JSON.stringify(result, null, 0)});
|
|
498
|
+
`);
|
|
499
|
+
}).catch((error) => {
|
|
500
|
+
const serializedError = serializeError(error);
|
|
501
|
+
injectJavaScript?.(`
|
|
502
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/reject/${eventId}', ${serializedError});
|
|
503
|
+
`);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
var globalEventListenerMap = /* @__PURE__ */ new Map();
|
|
507
|
+
function useBridgeHandler({
|
|
508
|
+
onMessage,
|
|
509
|
+
constantHandlerMap,
|
|
510
|
+
asyncHandlerMap,
|
|
511
|
+
eventListenerMap,
|
|
512
|
+
injectedJavaScript: originalInjectedJavaScript
|
|
513
|
+
}) {
|
|
514
|
+
const ref = useRef(null);
|
|
515
|
+
const injectedJavaScript = useMemo(
|
|
516
|
+
() => [
|
|
517
|
+
`window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
|
|
518
|
+
Object.entries(constantHandlerMap).reduce(
|
|
519
|
+
(acc, [key, value]) => {
|
|
520
|
+
acc[key] = typeof value === "function" ? value() : value;
|
|
521
|
+
return acc;
|
|
522
|
+
},
|
|
523
|
+
{}
|
|
524
|
+
)
|
|
525
|
+
)}`,
|
|
526
|
+
originalInjectedJavaScript,
|
|
527
|
+
"true"
|
|
528
|
+
].join("\n"),
|
|
529
|
+
[constantHandlerMap, originalInjectedJavaScript]
|
|
530
|
+
);
|
|
531
|
+
const createHandleOnEvent = (functionName, eventId) => (response) => {
|
|
532
|
+
ref.current?.injectJavaScript(`
|
|
533
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onEvent/${eventId}', ${JSON.stringify(response, null, 0)});
|
|
534
|
+
`);
|
|
535
|
+
};
|
|
536
|
+
const createHandleOnError = (functionName, eventId) => (error) => {
|
|
537
|
+
ref.current?.injectJavaScript(`
|
|
538
|
+
window.__BEDROCK_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${JSON.stringify(error, null, 0)});
|
|
539
|
+
`);
|
|
540
|
+
};
|
|
541
|
+
const $onMessage = useCallback2(
|
|
542
|
+
async (e) => {
|
|
543
|
+
onMessage?.(e);
|
|
544
|
+
const data = JSON.parse(e.nativeEvent.data);
|
|
545
|
+
if (typeof data !== "object" || data === null || typeof data.functionName !== "string" || typeof data.eventId !== "string" || typeof data.type !== "string" || !["addEventListener", "removeEventListener", "method"].includes(data.type)) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
switch (data.type) {
|
|
549
|
+
case "addEventListener": {
|
|
550
|
+
const handleOnEvent = createHandleOnEvent(data.functionName, data.eventId);
|
|
551
|
+
const handleOnError = createHandleOnError(data.functionName, data.eventId);
|
|
552
|
+
const remove = eventListenerMap[data.functionName]?.({
|
|
553
|
+
onEvent: handleOnEvent,
|
|
554
|
+
onError: handleOnError,
|
|
555
|
+
options: data.args
|
|
556
|
+
});
|
|
557
|
+
if (remove) {
|
|
558
|
+
globalEventListenerMap.set(`${data.functionName}/${data.eventId}`, remove);
|
|
559
|
+
}
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
case "removeEventListener": {
|
|
563
|
+
const key = `${data.functionName}/${data.eventId}`;
|
|
564
|
+
const remove = globalEventListenerMap.get(key);
|
|
565
|
+
remove?.();
|
|
566
|
+
globalEventListenerMap.delete(key);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case "method": {
|
|
570
|
+
methodHandler({
|
|
571
|
+
args: data.args,
|
|
572
|
+
eventId: data.eventId,
|
|
573
|
+
functionName: data.functionName,
|
|
574
|
+
handlerMap: asyncHandlerMap,
|
|
575
|
+
injectJavaScript: ref.current?.injectJavaScript
|
|
576
|
+
});
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
582
|
+
[onMessage]
|
|
583
|
+
);
|
|
584
|
+
return {
|
|
585
|
+
ref,
|
|
586
|
+
injectedJavaScript,
|
|
587
|
+
onMessage: $onMessage
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
452
591
|
// src/constant-bridges.ts
|
|
453
592
|
var constant_bridges_exports = {};
|
|
454
593
|
__export(constant_bridges_exports, {
|
|
@@ -504,7 +643,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
504
643
|
throw new Error(`Invalid WebView type: '${type}'`);
|
|
505
644
|
}
|
|
506
645
|
const bedrockEvent = useBedrockEvent();
|
|
507
|
-
const uri =
|
|
646
|
+
const uri = useMemo2(() => getWebViewUri(local), [local]);
|
|
508
647
|
const top = useSafeAreaTop2();
|
|
509
648
|
const bottom = useSafeAreaBottom();
|
|
510
649
|
const handler = useBridgeHandler({
|
|
@@ -536,7 +675,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
536
675
|
clearItems: Storage.clearItems
|
|
537
676
|
}
|
|
538
677
|
});
|
|
539
|
-
const baseProps =
|
|
678
|
+
const baseProps = useMemo2(() => {
|
|
540
679
|
switch (type) {
|
|
541
680
|
case "partner": {
|
|
542
681
|
const headerOnlyProp = {
|
|
@@ -566,7 +705,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
566
705
|
}
|
|
567
706
|
}, [type, props]);
|
|
568
707
|
const BaseWebView = WEBVIEW_TYPES[type];
|
|
569
|
-
const webviewDebuggingEnabled =
|
|
708
|
+
const webviewDebuggingEnabled = useMemo2(
|
|
570
709
|
() => getOperationalEnvironment() === "sandbox",
|
|
571
710
|
[]
|
|
572
711
|
);
|
|
@@ -641,6 +780,7 @@ export {
|
|
|
641
780
|
getDeviceId,
|
|
642
781
|
getOperationalEnvironment,
|
|
643
782
|
getTossAppVersion,
|
|
783
|
+
getTossShareLink,
|
|
644
784
|
openCamera,
|
|
645
785
|
setClipboardText,
|
|
646
786
|
startUpdateLocation,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apps-in-toss/framework",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.22",
|
|
5
5
|
"description": "The framework for Apps In Toss",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prepack": "yarn build",
|
|
@@ -56,13 +56,13 @@
|
|
|
56
56
|
"ait": "./bin/ait.js"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@apps-in-toss/cli": "0.0.
|
|
60
|
-
"@apps-in-toss/plugins": "0.0.
|
|
59
|
+
"@apps-in-toss/cli": "0.0.22",
|
|
60
|
+
"@apps-in-toss/plugins": "0.0.22",
|
|
61
61
|
"es-hangul": "^2.3.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@react-native-bedrock/mpack-next": "0.0.
|
|
65
|
-
"@react-native-bedrock/native": "0.0.
|
|
64
|
+
"@react-native-bedrock/mpack-next": "0.0.21",
|
|
65
|
+
"@react-native-bedrock/native": "0.0.21",
|
|
66
66
|
"@toss-design-system/react-native": "^0.5.0",
|
|
67
67
|
"@types/kill-port": "^2.0.1",
|
|
68
68
|
"@types/react": "18.3.3",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"kill-port": "^2.0.1",
|
|
74
74
|
"react": "18.2.0",
|
|
75
75
|
"react-native": "0.72.6",
|
|
76
|
-
"react-native-bedrock": "0.0.
|
|
76
|
+
"react-native-bedrock": "0.0.21",
|
|
77
77
|
"tsup": "^8.3.5",
|
|
78
78
|
"typescript": "4.9.5",
|
|
79
79
|
"vitest": "^3.0.3",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"publishConfig": {
|
|
92
92
|
"access": "public"
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "2a6cea952ba0db69fc2f0c9a94a190b9dfabe8ef"
|
|
95
95
|
}
|
package/src/async-bridges.ts
CHANGED