@apps-in-toss/framework 1.4.5 → 1.4.7
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 +157 -50
- package/dist/index.js +145 -38
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -1377,10 +1377,11 @@ var import_native_modules18 = require("@apps-in-toss/native-modules");
|
|
|
1377
1377
|
var appsInTossAsyncBridges = __toESM(require("@apps-in-toss/native-modules/async-bridges"), 1);
|
|
1378
1378
|
var appsInTossConstantBridges = __toESM(require("@apps-in-toss/native-modules/constant-bridges"), 1);
|
|
1379
1379
|
var appsInTossEventBridges = __toESM(require("@apps-in-toss/native-modules/event-bridges"), 1);
|
|
1380
|
+
var import_react_native_safe_area_context4 = require("@granite-js/native/react-native-safe-area-context");
|
|
1380
1381
|
var import_react_native32 = require("@granite-js/react-native");
|
|
1381
1382
|
var import_tds_react_native14 = require("@toss/tds-react-native");
|
|
1382
1383
|
var import_private9 = require("@toss/tds-react-native/private");
|
|
1383
|
-
var
|
|
1384
|
+
var import_react29 = require("react");
|
|
1384
1385
|
var import_react_native33 = require("react-native");
|
|
1385
1386
|
|
|
1386
1387
|
// src/components/GameWebView.tsx
|
|
@@ -1594,26 +1595,24 @@ function useBridgeHandler({
|
|
|
1594
1595
|
onMessage,
|
|
1595
1596
|
constantHandlerMap,
|
|
1596
1597
|
asyncHandlerMap,
|
|
1597
|
-
eventListenerMap
|
|
1598
|
-
injectedJavaScript: originalInjectedJavaScript
|
|
1598
|
+
eventListenerMap
|
|
1599
1599
|
}) {
|
|
1600
1600
|
const ref = (0, import_react23.useRef)(null);
|
|
1601
1601
|
const injectedJavaScript = (0, import_react23.useMemo)(
|
|
1602
|
-
() =>
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
originalInjectedJavaScript,
|
|
1613
|
-
"true"
|
|
1614
|
-
].join("\n"),
|
|
1615
|
-
[constantHandlerMap, originalInjectedJavaScript]
|
|
1602
|
+
() => `window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
|
|
1603
|
+
Object.entries(constantHandlerMap).reduce(
|
|
1604
|
+
(acc, [key, value]) => {
|
|
1605
|
+
acc[key] = typeof value === "function" ? value() : value;
|
|
1606
|
+
return acc;
|
|
1607
|
+
},
|
|
1608
|
+
{}
|
|
1609
|
+
)
|
|
1610
|
+
)};`,
|
|
1611
|
+
[constantHandlerMap]
|
|
1616
1612
|
);
|
|
1613
|
+
(0, import_react23.useEffect)(() => {
|
|
1614
|
+
ref.current?.injectJavaScript(injectedJavaScript);
|
|
1615
|
+
}, [injectedJavaScript]);
|
|
1617
1616
|
const createHandleOnEvent = (functionName, eventId) => (response) => {
|
|
1618
1617
|
ref.current?.injectJavaScript(`
|
|
1619
1618
|
window.__GRANITE_NATIVE_EMITTER.emit('${functionName}/onEvent/${eventId}', ${JSON.stringify(response, null, 0)});
|
|
@@ -1628,7 +1627,7 @@ function useBridgeHandler({
|
|
|
1628
1627
|
const $onMessage = (0, import_react23.useCallback)(
|
|
1629
1628
|
async (e) => {
|
|
1630
1629
|
onMessage?.(e);
|
|
1631
|
-
const data =
|
|
1630
|
+
const data = parseNativeEventData(e.nativeEvent.data);
|
|
1632
1631
|
if (typeof data !== "object" || data === null || typeof data.functionName !== "string" || typeof data.eventId !== "string" || typeof data.type !== "string" || !["addEventListener", "removeEventListener", "method"].includes(data.type)) {
|
|
1633
1632
|
return;
|
|
1634
1633
|
}
|
|
@@ -1674,15 +1673,59 @@ function useBridgeHandler({
|
|
|
1674
1673
|
onMessage: $onMessage
|
|
1675
1674
|
};
|
|
1676
1675
|
}
|
|
1676
|
+
function parseNativeEventData(data) {
|
|
1677
|
+
try {
|
|
1678
|
+
return JSON.parse(data);
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
console.error(error);
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// src/core/hooks/useSafeAreaInsetsEmitter.tsx
|
|
1686
|
+
var import_react_native_safe_area_context3 = require("@granite-js/native/react-native-safe-area-context");
|
|
1687
|
+
var import_react24 = require("react");
|
|
1688
|
+
var EventEmitter = class {
|
|
1689
|
+
listeners = {};
|
|
1690
|
+
on(event, listener) {
|
|
1691
|
+
if (!this.listeners[event]) {
|
|
1692
|
+
this.listeners[event] = [];
|
|
1693
|
+
}
|
|
1694
|
+
this.listeners[event].push(listener);
|
|
1695
|
+
}
|
|
1696
|
+
emit(event, ...args) {
|
|
1697
|
+
if (!this.listeners[event]) {
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
this.listeners[event].forEach((listener) => listener(...args));
|
|
1701
|
+
}
|
|
1702
|
+
off(event, listener) {
|
|
1703
|
+
if (!this.listeners[event]) {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
this.listeners[event] = this.listeners[event].filter((l) => l !== listener);
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
function useSafeAreaInsetsEmitter() {
|
|
1710
|
+
const insets = (0, import_react_native_safe_area_context3.useSafeAreaInsets)();
|
|
1711
|
+
const emitter = (0, import_react24.useMemo)(() => new EventEmitter(), []);
|
|
1712
|
+
(0, import_react24.useEffect)(() => {
|
|
1713
|
+
emitter.emit("safeAreaInsetsChange", insets);
|
|
1714
|
+
return () => {
|
|
1715
|
+
emitter.off("safeAreaInsetsChange", (listener) => listener(insets));
|
|
1716
|
+
};
|
|
1717
|
+
}, [emitter, insets]);
|
|
1718
|
+
return emitter;
|
|
1719
|
+
}
|
|
1677
1720
|
|
|
1678
1721
|
// src/core/hooks/useWebBackHandler.tsx
|
|
1679
1722
|
var import_react_native27 = require("@granite-js/react-native");
|
|
1680
1723
|
var import_tds_react_native13 = require("@toss/tds-react-native");
|
|
1681
1724
|
var import_es_hangul5 = require("es-hangul");
|
|
1682
|
-
var
|
|
1725
|
+
var import_react26 = require("react");
|
|
1683
1726
|
|
|
1684
1727
|
// src/hooks/useWebviewHistoryStack.tsx
|
|
1685
|
-
var
|
|
1728
|
+
var import_react25 = require("react");
|
|
1686
1729
|
var INITIAL_STATE = { stack: [], index: -1 };
|
|
1687
1730
|
function reducer(state, action) {
|
|
1688
1731
|
switch (action.type) {
|
|
@@ -1713,11 +1756,11 @@ function reducer(state, action) {
|
|
|
1713
1756
|
}
|
|
1714
1757
|
}
|
|
1715
1758
|
function useWebViewHistory() {
|
|
1716
|
-
const [state, dispatch] = (0,
|
|
1717
|
-
const onNavigationStateChange = (0,
|
|
1759
|
+
const [state, dispatch] = (0, import_react25.useReducer)(reducer, INITIAL_STATE);
|
|
1760
|
+
const onNavigationStateChange = (0, import_react25.useCallback)(({ url, canGoForward: canGoForward2 }) => {
|
|
1718
1761
|
dispatch({ type: "NAVIGATION_CHANGE", url, canGoForward: canGoForward2 });
|
|
1719
1762
|
}, []);
|
|
1720
|
-
const { canGoBack, canGoForward } = (0,
|
|
1763
|
+
const { canGoBack, canGoForward } = (0, import_react25.useMemo)(() => {
|
|
1721
1764
|
const canBack = state.index > 0;
|
|
1722
1765
|
const canFwd = state.index >= 0 && state.index < state.stack.length - 1;
|
|
1723
1766
|
return { canGoBack: canBack, canGoForward: canFwd };
|
|
@@ -1750,19 +1793,19 @@ function useWebBackHandler(webViewRef) {
|
|
|
1750
1793
|
const logging = useNavigationBarLogging();
|
|
1751
1794
|
const { openConfirm } = (0, import_tds_react_native13.useDialog)();
|
|
1752
1795
|
const global2 = getAppsInTossGlobals();
|
|
1753
|
-
const addEventListener = (0,
|
|
1796
|
+
const addEventListener = (0, import_react26.useCallback)(
|
|
1754
1797
|
(handler) => {
|
|
1755
1798
|
addWebBackEventListener(handler);
|
|
1756
1799
|
},
|
|
1757
1800
|
[addWebBackEventListener]
|
|
1758
1801
|
);
|
|
1759
|
-
const removeEventListener = (0,
|
|
1802
|
+
const removeEventListener = (0, import_react26.useCallback)(
|
|
1760
1803
|
(handler) => {
|
|
1761
1804
|
removeWebBackEventListener(handler);
|
|
1762
1805
|
},
|
|
1763
1806
|
[removeWebBackEventListener]
|
|
1764
1807
|
);
|
|
1765
|
-
const handleWebBack = (0,
|
|
1808
|
+
const handleWebBack = (0, import_react26.useCallback)(async () => {
|
|
1766
1809
|
if (hasWebBackEvent) {
|
|
1767
1810
|
for (const handler of webBackHandlersRef) {
|
|
1768
1811
|
handler();
|
|
@@ -1795,7 +1838,7 @@ function useWebBackHandler(webViewRef) {
|
|
|
1795
1838
|
openConfirm,
|
|
1796
1839
|
webViewRef
|
|
1797
1840
|
]);
|
|
1798
|
-
const handleWebHome = (0,
|
|
1841
|
+
const handleWebHome = (0, import_react26.useCallback)(() => {
|
|
1799
1842
|
logging.homeButtonClick();
|
|
1800
1843
|
if (hasWebBackEvent) {
|
|
1801
1844
|
for (const handler of webBackHandlersRef) {
|
|
@@ -1805,7 +1848,7 @@ function useWebBackHandler(webViewRef) {
|
|
|
1805
1848
|
}
|
|
1806
1849
|
webViewRef.current?.injectJavaScript(HISTORY_HOME_SCRIPT);
|
|
1807
1850
|
}, [hasWebBackEvent, webBackHandlersRef, logging, webViewRef]);
|
|
1808
|
-
return (0,
|
|
1851
|
+
return (0, import_react26.useMemo)(
|
|
1809
1852
|
() => ({ addEventListener, removeEventListener, handleWebBack, handleWebHome, onNavigationStateChange }),
|
|
1810
1853
|
[addEventListener, removeEventListener, handleWebBack, handleWebHome, onNavigationStateChange]
|
|
1811
1854
|
);
|
|
@@ -1983,11 +2026,11 @@ function useCreateUserAgent({
|
|
|
1983
2026
|
// src/hooks/useGeolocation.ts
|
|
1984
2027
|
var import_native_modules16 = require("@apps-in-toss/native-modules");
|
|
1985
2028
|
var import_react_native29 = require("@granite-js/react-native");
|
|
1986
|
-
var
|
|
2029
|
+
var import_react27 = require("react");
|
|
1987
2030
|
function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
1988
2031
|
const isVisible = (0, import_react_native29.useVisibility)();
|
|
1989
|
-
const [location, setLocation] = (0,
|
|
1990
|
-
(0,
|
|
2032
|
+
const [location, setLocation] = (0, import_react27.useState)(null);
|
|
2033
|
+
(0, import_react27.useEffect)(() => {
|
|
1991
2034
|
if (!isVisible) {
|
|
1992
2035
|
return;
|
|
1993
2036
|
}
|
|
@@ -2006,11 +2049,11 @@ function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
|
2006
2049
|
|
|
2007
2050
|
// src/hooks/useWaitForReturnNavigator.tsx
|
|
2008
2051
|
var import_react_native30 = require("@granite-js/react-native");
|
|
2009
|
-
var
|
|
2052
|
+
var import_react28 = require("react");
|
|
2010
2053
|
function useWaitForReturnNavigator() {
|
|
2011
|
-
const callbacks = (0,
|
|
2054
|
+
const callbacks = (0, import_react28.useRef)([]).current;
|
|
2012
2055
|
const navigation = (0, import_react_native30.useNavigation)();
|
|
2013
|
-
const startNavigating = (0,
|
|
2056
|
+
const startNavigating = (0, import_react28.useCallback)(
|
|
2014
2057
|
(route, params) => {
|
|
2015
2058
|
return new Promise((resolve) => {
|
|
2016
2059
|
callbacks.push(resolve);
|
|
@@ -2019,7 +2062,7 @@ function useWaitForReturnNavigator() {
|
|
|
2019
2062
|
},
|
|
2020
2063
|
[callbacks, navigation]
|
|
2021
2064
|
);
|
|
2022
|
-
const handleVisibilityChange = (0,
|
|
2065
|
+
const handleVisibilityChange = (0, import_react28.useCallback)(
|
|
2023
2066
|
(state) => {
|
|
2024
2067
|
if (state === "visible" && callbacks.length > 0) {
|
|
2025
2068
|
for (const callback of callbacks) {
|
|
@@ -2127,26 +2170,20 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2127
2170
|
if (!TYPES.includes(type)) {
|
|
2128
2171
|
throw new Error(`Invalid WebView type: '${type}'`);
|
|
2129
2172
|
}
|
|
2130
|
-
const webViewRef = (0,
|
|
2173
|
+
const webViewRef = (0, import_react29.useRef)(null);
|
|
2131
2174
|
const webBackHandler = useWebBackHandler(webViewRef);
|
|
2132
|
-
const uri = (0,
|
|
2175
|
+
const uri = (0, import_react29.useMemo)(() => getWebViewUri(local), [local]);
|
|
2133
2176
|
const top = (0, import_private9.useSafeAreaTop)();
|
|
2134
2177
|
const bottom = (0, import_private9.useSafeAreaBottom)();
|
|
2178
|
+
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
2135
2179
|
const global2 = getAppsInTossGlobals();
|
|
2136
2180
|
const navigationBarContext = useNavigationBarContext();
|
|
2137
|
-
const
|
|
2138
|
-
|
|
2139
|
-
const style = document.createElement('style');
|
|
2140
|
-
style.textContent = '*:not(input):not(textarea) { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-touch-callout: none; }';
|
|
2141
|
-
document.head.appendChild(style);
|
|
2142
|
-
})();
|
|
2143
|
-
`;
|
|
2144
|
-
const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = (0, import_react28.useState)(
|
|
2181
|
+
const safeAreaInsetsEmitter = useSafeAreaInsetsEmitter();
|
|
2182
|
+
const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = (0, import_react29.useState)(
|
|
2145
2183
|
props.allowsBackForwardNavigationGestures
|
|
2146
2184
|
);
|
|
2147
2185
|
const handler = useBridgeHandler({
|
|
2148
2186
|
onMessage,
|
|
2149
|
-
injectedJavaScript: [disableTextSelectionCSS].join("\n"),
|
|
2150
2187
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2151
2188
|
eventListenerMap: {
|
|
2152
2189
|
...appsInTossEventBridges,
|
|
@@ -2159,6 +2196,12 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2159
2196
|
},
|
|
2160
2197
|
entryMessageExited: ({ onEvent, onError }) => import_native_modules18.appsInTossEvent.addEventListener("entryMessageExited", { onEvent, onError }),
|
|
2161
2198
|
updateLocationEvent: ({ onEvent, onError, options }) => import_native_modules18.appsInTossEvent.addEventListener("updateLocationEvent", { onEvent, onError, options }),
|
|
2199
|
+
safeAreaInsetsChange: ({ onEvent }) => {
|
|
2200
|
+
safeAreaInsetsEmitter.on("safeAreaInsetsChange", onEvent);
|
|
2201
|
+
return () => {
|
|
2202
|
+
safeAreaInsetsEmitter.off("safeAreaInsetsChange", onEvent);
|
|
2203
|
+
};
|
|
2204
|
+
},
|
|
2162
2205
|
/** @internal */
|
|
2163
2206
|
appBridgeCallbackEvent: ({ onEvent, onError, options }) => import_native_modules18.appsInTossEvent.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
|
|
2164
2207
|
/** AdMob */
|
|
@@ -2177,6 +2220,8 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2177
2220
|
...appsInTossConstantBridges,
|
|
2178
2221
|
getSafeAreaTop: () => top,
|
|
2179
2222
|
getSafeAreaBottom: () => bottom,
|
|
2223
|
+
getSafeAreaLeft: () => insets.left,
|
|
2224
|
+
getSafeAreaRight: () => insets.right,
|
|
2180
2225
|
...Object.fromEntries(Object.entries(global2).map(([key, value]) => [key, () => value])),
|
|
2181
2226
|
/** AdMob */
|
|
2182
2227
|
loadAdMobInterstitialAd_isSupported: import_native_modules18.GoogleAdMob.loadAdMobInterstitialAd.isSupported,
|
|
@@ -2221,7 +2266,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2221
2266
|
completeProductGrant: import_native_modules18.IAP.completeProductGrant
|
|
2222
2267
|
}
|
|
2223
2268
|
});
|
|
2224
|
-
const headerPropForExternalWebView = (0,
|
|
2269
|
+
const headerPropForExternalWebView = (0, import_react29.useMemo)(() => {
|
|
2225
2270
|
const parsedNavigationBar = global2.navigationBar != null ? safeParseNavigationBar(global2.navigationBar) : null;
|
|
2226
2271
|
const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
|
|
2227
2272
|
const withBackButton = parsedNavigationBar?.withBackButton ?? true;
|
|
@@ -2242,7 +2287,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2242
2287
|
colorPreference: "light"
|
|
2243
2288
|
});
|
|
2244
2289
|
const refs = mergeRefs(handler.ref, webViewRef);
|
|
2245
|
-
(0,
|
|
2290
|
+
(0, import_react29.useEffect)(() => {
|
|
2246
2291
|
const callback = () => {
|
|
2247
2292
|
webBackHandler.handleWebBack();
|
|
2248
2293
|
return true;
|
|
@@ -2250,6 +2295,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2250
2295
|
import_react_native33.BackHandler.addEventListener("hardwareBackPress", callback);
|
|
2251
2296
|
return () => import_react_native33.BackHandler.removeEventListener("hardwareBackPress", callback);
|
|
2252
2297
|
}, [webBackHandler]);
|
|
2298
|
+
const globalScripts = useGlobalScripts();
|
|
2253
2299
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
2254
2300
|
BaseWebView,
|
|
2255
2301
|
{
|
|
@@ -2277,13 +2323,74 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2277
2323
|
webviewDebuggingEnabled: webViewDebuggingEnabled,
|
|
2278
2324
|
thirdPartyCookiesEnabled: true,
|
|
2279
2325
|
onMessage: handler.onMessage,
|
|
2280
|
-
injectedJavaScript:
|
|
2281
|
-
injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript,
|
|
2326
|
+
injectedJavaScript: globalScripts.afterLoad,
|
|
2327
|
+
injectedJavaScriptBeforeContentLoaded: mergeScripts(handler.injectedJavaScript, globalScripts.beforeLoad),
|
|
2282
2328
|
decelerationRate: import_react_native33.Platform.OS === "ios" ? 1 : void 0,
|
|
2283
2329
|
allowsBackForwardNavigationGestures
|
|
2284
2330
|
}
|
|
2285
2331
|
);
|
|
2286
2332
|
}
|
|
2333
|
+
function useGlobalScripts() {
|
|
2334
|
+
const global2 = getAppsInTossGlobals();
|
|
2335
|
+
const disableTextSelectionCSS = `
|
|
2336
|
+
const style = document.createElement('style');
|
|
2337
|
+
style.textContent = '*:not(input):not(textarea) { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-touch-callout: none; }';
|
|
2338
|
+
document.head.appendChild(style);
|
|
2339
|
+
`;
|
|
2340
|
+
const applyGameResourcesCache = `
|
|
2341
|
+
(function () {
|
|
2342
|
+
if (typeof caches === 'undefined') {
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2345
|
+
const cacheKeyPrefix = '@apps-in-toss/caches/';
|
|
2346
|
+
const cacheKey = \`\${cacheKeyPrefix}${global2.deploymentId}\`;
|
|
2347
|
+
window.addEventListener('load', async () => {
|
|
2348
|
+
const keys = await caches.keys();
|
|
2349
|
+
for (const key of keys) {
|
|
2350
|
+
if (key.startsWith(cacheKeyPrefix) && key !== cacheKey) {
|
|
2351
|
+
await caches.delete(key);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
});
|
|
2355
|
+
window.fetch = new Proxy(window.fetch, {
|
|
2356
|
+
async apply(originalFetch, thisArg, args) {
|
|
2357
|
+
const request = new Request(args[0], args[1]);
|
|
2358
|
+
if (!/\\.(data|wasm|framework\\.js)(?:\\.gz|\\.br|\\.unityweb)?$/.test(request.url)) {
|
|
2359
|
+
return await originalFetch.call(thisArg, request);
|
|
2360
|
+
}
|
|
2361
|
+
const cache = await caches.open(cacheKey);
|
|
2362
|
+
const cached = await cache.match(request);
|
|
2363
|
+
if (cached) {
|
|
2364
|
+
const eTag = cached.headers.get('ETag');
|
|
2365
|
+
const lastModified = cached.headers.get('Last-Modified');
|
|
2366
|
+
if (eTag) {
|
|
2367
|
+
request.headers.set('If-None-Match', eTag);
|
|
2368
|
+
}
|
|
2369
|
+
if (lastModified) {
|
|
2370
|
+
request.headers.set('If-Modified-Since', lastModified);
|
|
2371
|
+
}
|
|
2372
|
+
const revalidated = await originalFetch.call(thisArg, request);
|
|
2373
|
+
if (revalidated.status === 304) {
|
|
2374
|
+
return cached;
|
|
2375
|
+
}
|
|
2376
|
+
cache.put(request, revalidated.clone());
|
|
2377
|
+
return revalidated;
|
|
2378
|
+
}
|
|
2379
|
+
const response = await originalFetch.call(thisArg, request);
|
|
2380
|
+
cache.put(request, response.clone());
|
|
2381
|
+
return response;
|
|
2382
|
+
},
|
|
2383
|
+
});
|
|
2384
|
+
})();
|
|
2385
|
+
`;
|
|
2386
|
+
return {
|
|
2387
|
+
beforeLoad: mergeScripts(global2.webViewType === "game" && applyGameResourcesCache),
|
|
2388
|
+
afterLoad: mergeScripts(disableTextSelectionCSS)
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2391
|
+
function mergeScripts(...scripts) {
|
|
2392
|
+
return scripts.filter((script) => typeof script === "string").join("\n");
|
|
2393
|
+
}
|
|
2287
2394
|
|
|
2288
2395
|
// src/index.ts
|
|
2289
2396
|
__reExport(src_exports, require("@apps-in-toss/analytics"), module.exports);
|
package/dist/index.js
CHANGED
|
@@ -1358,10 +1358,11 @@ import {
|
|
|
1358
1358
|
import * as appsInTossAsyncBridges from "@apps-in-toss/native-modules/async-bridges";
|
|
1359
1359
|
import * as appsInTossConstantBridges from "@apps-in-toss/native-modules/constant-bridges";
|
|
1360
1360
|
import * as appsInTossEventBridges from "@apps-in-toss/native-modules/event-bridges";
|
|
1361
|
+
import { useSafeAreaInsets as useSafeAreaInsets4 } from "@granite-js/native/react-native-safe-area-context";
|
|
1361
1362
|
import { getSchemeUri as getSchemeUri6 } from "@granite-js/react-native";
|
|
1362
1363
|
import { ExternalWebViewScreen, tdsEvent } from "@toss/tds-react-native";
|
|
1363
1364
|
import { useSafeAreaBottom, useSafeAreaTop as useSafeAreaTop3 } from "@toss/tds-react-native/private";
|
|
1364
|
-
import { useEffect as
|
|
1365
|
+
import { useEffect as useEffect14, useMemo as useMemo7, useRef as useRef6, useState as useState8 } from "react";
|
|
1365
1366
|
import { BackHandler as BackHandler2, Platform as Platform6 } from "react-native";
|
|
1366
1367
|
|
|
1367
1368
|
// src/components/GameWebView.tsx
|
|
@@ -1529,7 +1530,7 @@ var PartnerWebView = forwardRef2(function PartnerWebViewScreen({ onBackButtonCli
|
|
|
1529
1530
|
});
|
|
1530
1531
|
|
|
1531
1532
|
// src/bridge-handler/useBridgeHandler.tsx
|
|
1532
|
-
import { useCallback as useCallback10, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
1533
|
+
import { useCallback as useCallback10, useEffect as useEffect11, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
1533
1534
|
function serializeError(error) {
|
|
1534
1535
|
return JSON.stringify(error, (_, value) => {
|
|
1535
1536
|
if (value instanceof Error) {
|
|
@@ -1579,26 +1580,24 @@ function useBridgeHandler({
|
|
|
1579
1580
|
onMessage,
|
|
1580
1581
|
constantHandlerMap,
|
|
1581
1582
|
asyncHandlerMap,
|
|
1582
|
-
eventListenerMap
|
|
1583
|
-
injectedJavaScript: originalInjectedJavaScript
|
|
1583
|
+
eventListenerMap
|
|
1584
1584
|
}) {
|
|
1585
1585
|
const ref = useRef4(null);
|
|
1586
1586
|
const injectedJavaScript = useMemo3(
|
|
1587
|
-
() =>
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
originalInjectedJavaScript,
|
|
1598
|
-
"true"
|
|
1599
|
-
].join("\n"),
|
|
1600
|
-
[constantHandlerMap, originalInjectedJavaScript]
|
|
1587
|
+
() => `window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
|
|
1588
|
+
Object.entries(constantHandlerMap).reduce(
|
|
1589
|
+
(acc, [key, value]) => {
|
|
1590
|
+
acc[key] = typeof value === "function" ? value() : value;
|
|
1591
|
+
return acc;
|
|
1592
|
+
},
|
|
1593
|
+
{}
|
|
1594
|
+
)
|
|
1595
|
+
)};`,
|
|
1596
|
+
[constantHandlerMap]
|
|
1601
1597
|
);
|
|
1598
|
+
useEffect11(() => {
|
|
1599
|
+
ref.current?.injectJavaScript(injectedJavaScript);
|
|
1600
|
+
}, [injectedJavaScript]);
|
|
1602
1601
|
const createHandleOnEvent = (functionName, eventId) => (response) => {
|
|
1603
1602
|
ref.current?.injectJavaScript(`
|
|
1604
1603
|
window.__GRANITE_NATIVE_EMITTER.emit('${functionName}/onEvent/${eventId}', ${JSON.stringify(response, null, 0)});
|
|
@@ -1613,7 +1612,7 @@ function useBridgeHandler({
|
|
|
1613
1612
|
const $onMessage = useCallback10(
|
|
1614
1613
|
async (e) => {
|
|
1615
1614
|
onMessage?.(e);
|
|
1616
|
-
const data =
|
|
1615
|
+
const data = parseNativeEventData(e.nativeEvent.data);
|
|
1617
1616
|
if (typeof data !== "object" || data === null || typeof data.functionName !== "string" || typeof data.eventId !== "string" || typeof data.type !== "string" || !["addEventListener", "removeEventListener", "method"].includes(data.type)) {
|
|
1618
1617
|
return;
|
|
1619
1618
|
}
|
|
@@ -1659,15 +1658,59 @@ function useBridgeHandler({
|
|
|
1659
1658
|
onMessage: $onMessage
|
|
1660
1659
|
};
|
|
1661
1660
|
}
|
|
1661
|
+
function parseNativeEventData(data) {
|
|
1662
|
+
try {
|
|
1663
|
+
return JSON.parse(data);
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
console.error(error);
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// src/core/hooks/useSafeAreaInsetsEmitter.tsx
|
|
1671
|
+
import { useSafeAreaInsets as useSafeAreaInsets3 } from "@granite-js/native/react-native-safe-area-context";
|
|
1672
|
+
import { useEffect as useEffect12, useMemo as useMemo4 } from "react";
|
|
1673
|
+
var EventEmitter = class {
|
|
1674
|
+
listeners = {};
|
|
1675
|
+
on(event, listener) {
|
|
1676
|
+
if (!this.listeners[event]) {
|
|
1677
|
+
this.listeners[event] = [];
|
|
1678
|
+
}
|
|
1679
|
+
this.listeners[event].push(listener);
|
|
1680
|
+
}
|
|
1681
|
+
emit(event, ...args) {
|
|
1682
|
+
if (!this.listeners[event]) {
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
this.listeners[event].forEach((listener) => listener(...args));
|
|
1686
|
+
}
|
|
1687
|
+
off(event, listener) {
|
|
1688
|
+
if (!this.listeners[event]) {
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
this.listeners[event] = this.listeners[event].filter((l) => l !== listener);
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
function useSafeAreaInsetsEmitter() {
|
|
1695
|
+
const insets = useSafeAreaInsets3();
|
|
1696
|
+
const emitter = useMemo4(() => new EventEmitter(), []);
|
|
1697
|
+
useEffect12(() => {
|
|
1698
|
+
emitter.emit("safeAreaInsetsChange", insets);
|
|
1699
|
+
return () => {
|
|
1700
|
+
emitter.off("safeAreaInsetsChange", (listener) => listener(insets));
|
|
1701
|
+
};
|
|
1702
|
+
}, [emitter, insets]);
|
|
1703
|
+
return emitter;
|
|
1704
|
+
}
|
|
1662
1705
|
|
|
1663
1706
|
// src/core/hooks/useWebBackHandler.tsx
|
|
1664
1707
|
import { closeView as closeView6, useBackEventState } from "@granite-js/react-native";
|
|
1665
1708
|
import { useDialog as useDialog7 } from "@toss/tds-react-native";
|
|
1666
1709
|
import { josa as josa5 } from "es-hangul";
|
|
1667
|
-
import { useCallback as useCallback12, useMemo as
|
|
1710
|
+
import { useCallback as useCallback12, useMemo as useMemo6 } from "react";
|
|
1668
1711
|
|
|
1669
1712
|
// src/hooks/useWebviewHistoryStack.tsx
|
|
1670
|
-
import { useCallback as useCallback11, useMemo as
|
|
1713
|
+
import { useCallback as useCallback11, useMemo as useMemo5, useReducer } from "react";
|
|
1671
1714
|
var INITIAL_STATE = { stack: [], index: -1 };
|
|
1672
1715
|
function reducer(state, action) {
|
|
1673
1716
|
switch (action.type) {
|
|
@@ -1702,7 +1745,7 @@ function useWebViewHistory() {
|
|
|
1702
1745
|
const onNavigationStateChange = useCallback11(({ url, canGoForward: canGoForward2 }) => {
|
|
1703
1746
|
dispatch({ type: "NAVIGATION_CHANGE", url, canGoForward: canGoForward2 });
|
|
1704
1747
|
}, []);
|
|
1705
|
-
const { canGoBack, canGoForward } =
|
|
1748
|
+
const { canGoBack, canGoForward } = useMemo5(() => {
|
|
1706
1749
|
const canBack = state.index > 0;
|
|
1707
1750
|
const canFwd = state.index >= 0 && state.index < state.stack.length - 1;
|
|
1708
1751
|
return { canGoBack: canBack, canGoForward: canFwd };
|
|
@@ -1790,7 +1833,7 @@ function useWebBackHandler(webViewRef) {
|
|
|
1790
1833
|
}
|
|
1791
1834
|
webViewRef.current?.injectJavaScript(HISTORY_HOME_SCRIPT);
|
|
1792
1835
|
}, [hasWebBackEvent, webBackHandlersRef, logging, webViewRef]);
|
|
1793
|
-
return
|
|
1836
|
+
return useMemo6(
|
|
1794
1837
|
() => ({ addEventListener, removeEventListener, handleWebBack, handleWebHome, onNavigationStateChange }),
|
|
1795
1838
|
[addEventListener, removeEventListener, handleWebBack, handleWebHome, onNavigationStateChange]
|
|
1796
1839
|
);
|
|
@@ -1968,11 +2011,11 @@ function useCreateUserAgent({
|
|
|
1968
2011
|
// src/hooks/useGeolocation.ts
|
|
1969
2012
|
import { startUpdateLocation } from "@apps-in-toss/native-modules";
|
|
1970
2013
|
import { useVisibility as useVisibility3 } from "@granite-js/react-native";
|
|
1971
|
-
import { useEffect as
|
|
2014
|
+
import { useEffect as useEffect13, useState as useState7 } from "react";
|
|
1972
2015
|
function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
|
|
1973
2016
|
const isVisible = useVisibility3();
|
|
1974
2017
|
const [location, setLocation] = useState7(null);
|
|
1975
|
-
|
|
2018
|
+
useEffect13(() => {
|
|
1976
2019
|
if (!isVisible) {
|
|
1977
2020
|
return;
|
|
1978
2021
|
}
|
|
@@ -2114,24 +2157,18 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2114
2157
|
}
|
|
2115
2158
|
const webViewRef = useRef6(null);
|
|
2116
2159
|
const webBackHandler = useWebBackHandler(webViewRef);
|
|
2117
|
-
const uri =
|
|
2160
|
+
const uri = useMemo7(() => getWebViewUri(local), [local]);
|
|
2118
2161
|
const top = useSafeAreaTop3();
|
|
2119
2162
|
const bottom = useSafeAreaBottom();
|
|
2163
|
+
const insets = useSafeAreaInsets4();
|
|
2120
2164
|
const global2 = getAppsInTossGlobals();
|
|
2121
2165
|
const navigationBarContext = useNavigationBarContext();
|
|
2122
|
-
const
|
|
2123
|
-
(function() {
|
|
2124
|
-
const style = document.createElement('style');
|
|
2125
|
-
style.textContent = '*:not(input):not(textarea) { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-touch-callout: none; }';
|
|
2126
|
-
document.head.appendChild(style);
|
|
2127
|
-
})();
|
|
2128
|
-
`;
|
|
2166
|
+
const safeAreaInsetsEmitter = useSafeAreaInsetsEmitter();
|
|
2129
2167
|
const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = useState8(
|
|
2130
2168
|
props.allowsBackForwardNavigationGestures
|
|
2131
2169
|
);
|
|
2132
2170
|
const handler = useBridgeHandler({
|
|
2133
2171
|
onMessage,
|
|
2134
|
-
injectedJavaScript: [disableTextSelectionCSS].join("\n"),
|
|
2135
2172
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2136
2173
|
eventListenerMap: {
|
|
2137
2174
|
...appsInTossEventBridges,
|
|
@@ -2144,6 +2181,12 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2144
2181
|
},
|
|
2145
2182
|
entryMessageExited: ({ onEvent, onError }) => appsInTossEvent4.addEventListener("entryMessageExited", { onEvent, onError }),
|
|
2146
2183
|
updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent4.addEventListener("updateLocationEvent", { onEvent, onError, options }),
|
|
2184
|
+
safeAreaInsetsChange: ({ onEvent }) => {
|
|
2185
|
+
safeAreaInsetsEmitter.on("safeAreaInsetsChange", onEvent);
|
|
2186
|
+
return () => {
|
|
2187
|
+
safeAreaInsetsEmitter.off("safeAreaInsetsChange", onEvent);
|
|
2188
|
+
};
|
|
2189
|
+
},
|
|
2147
2190
|
/** @internal */
|
|
2148
2191
|
appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent4.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
|
|
2149
2192
|
/** AdMob */
|
|
@@ -2162,6 +2205,8 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2162
2205
|
...appsInTossConstantBridges,
|
|
2163
2206
|
getSafeAreaTop: () => top,
|
|
2164
2207
|
getSafeAreaBottom: () => bottom,
|
|
2208
|
+
getSafeAreaLeft: () => insets.left,
|
|
2209
|
+
getSafeAreaRight: () => insets.right,
|
|
2165
2210
|
...Object.fromEntries(Object.entries(global2).map(([key, value]) => [key, () => value])),
|
|
2166
2211
|
/** AdMob */
|
|
2167
2212
|
loadAdMobInterstitialAd_isSupported: GoogleAdMob.loadAdMobInterstitialAd.isSupported,
|
|
@@ -2206,7 +2251,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2206
2251
|
completeProductGrant: IAP.completeProductGrant
|
|
2207
2252
|
}
|
|
2208
2253
|
});
|
|
2209
|
-
const headerPropForExternalWebView =
|
|
2254
|
+
const headerPropForExternalWebView = useMemo7(() => {
|
|
2210
2255
|
const parsedNavigationBar = global2.navigationBar != null ? safeParseNavigationBar(global2.navigationBar) : null;
|
|
2211
2256
|
const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
|
|
2212
2257
|
const withBackButton = parsedNavigationBar?.withBackButton ?? true;
|
|
@@ -2227,7 +2272,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2227
2272
|
colorPreference: "light"
|
|
2228
2273
|
});
|
|
2229
2274
|
const refs = mergeRefs(handler.ref, webViewRef);
|
|
2230
|
-
|
|
2275
|
+
useEffect14(() => {
|
|
2231
2276
|
const callback = () => {
|
|
2232
2277
|
webBackHandler.handleWebBack();
|
|
2233
2278
|
return true;
|
|
@@ -2235,6 +2280,7 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2235
2280
|
BackHandler2.addEventListener("hardwareBackPress", callback);
|
|
2236
2281
|
return () => BackHandler2.removeEventListener("hardwareBackPress", callback);
|
|
2237
2282
|
}, [webBackHandler]);
|
|
2283
|
+
const globalScripts = useGlobalScripts();
|
|
2238
2284
|
return /* @__PURE__ */ jsx16(
|
|
2239
2285
|
BaseWebView,
|
|
2240
2286
|
{
|
|
@@ -2262,13 +2308,74 @@ function WebView({ type, local, onMessage, ...props }) {
|
|
|
2262
2308
|
webviewDebuggingEnabled: webViewDebuggingEnabled,
|
|
2263
2309
|
thirdPartyCookiesEnabled: true,
|
|
2264
2310
|
onMessage: handler.onMessage,
|
|
2265
|
-
injectedJavaScript:
|
|
2266
|
-
injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript,
|
|
2311
|
+
injectedJavaScript: globalScripts.afterLoad,
|
|
2312
|
+
injectedJavaScriptBeforeContentLoaded: mergeScripts(handler.injectedJavaScript, globalScripts.beforeLoad),
|
|
2267
2313
|
decelerationRate: Platform6.OS === "ios" ? 1 : void 0,
|
|
2268
2314
|
allowsBackForwardNavigationGestures
|
|
2269
2315
|
}
|
|
2270
2316
|
);
|
|
2271
2317
|
}
|
|
2318
|
+
function useGlobalScripts() {
|
|
2319
|
+
const global2 = getAppsInTossGlobals();
|
|
2320
|
+
const disableTextSelectionCSS = `
|
|
2321
|
+
const style = document.createElement('style');
|
|
2322
|
+
style.textContent = '*:not(input):not(textarea) { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-touch-callout: none; }';
|
|
2323
|
+
document.head.appendChild(style);
|
|
2324
|
+
`;
|
|
2325
|
+
const applyGameResourcesCache = `
|
|
2326
|
+
(function () {
|
|
2327
|
+
if (typeof caches === 'undefined') {
|
|
2328
|
+
return;
|
|
2329
|
+
}
|
|
2330
|
+
const cacheKeyPrefix = '@apps-in-toss/caches/';
|
|
2331
|
+
const cacheKey = \`\${cacheKeyPrefix}${global2.deploymentId}\`;
|
|
2332
|
+
window.addEventListener('load', async () => {
|
|
2333
|
+
const keys = await caches.keys();
|
|
2334
|
+
for (const key of keys) {
|
|
2335
|
+
if (key.startsWith(cacheKeyPrefix) && key !== cacheKey) {
|
|
2336
|
+
await caches.delete(key);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
});
|
|
2340
|
+
window.fetch = new Proxy(window.fetch, {
|
|
2341
|
+
async apply(originalFetch, thisArg, args) {
|
|
2342
|
+
const request = new Request(args[0], args[1]);
|
|
2343
|
+
if (!/\\.(data|wasm|framework\\.js)(?:\\.gz|\\.br|\\.unityweb)?$/.test(request.url)) {
|
|
2344
|
+
return await originalFetch.call(thisArg, request);
|
|
2345
|
+
}
|
|
2346
|
+
const cache = await caches.open(cacheKey);
|
|
2347
|
+
const cached = await cache.match(request);
|
|
2348
|
+
if (cached) {
|
|
2349
|
+
const eTag = cached.headers.get('ETag');
|
|
2350
|
+
const lastModified = cached.headers.get('Last-Modified');
|
|
2351
|
+
if (eTag) {
|
|
2352
|
+
request.headers.set('If-None-Match', eTag);
|
|
2353
|
+
}
|
|
2354
|
+
if (lastModified) {
|
|
2355
|
+
request.headers.set('If-Modified-Since', lastModified);
|
|
2356
|
+
}
|
|
2357
|
+
const revalidated = await originalFetch.call(thisArg, request);
|
|
2358
|
+
if (revalidated.status === 304) {
|
|
2359
|
+
return cached;
|
|
2360
|
+
}
|
|
2361
|
+
cache.put(request, revalidated.clone());
|
|
2362
|
+
return revalidated;
|
|
2363
|
+
}
|
|
2364
|
+
const response = await originalFetch.call(thisArg, request);
|
|
2365
|
+
cache.put(request, response.clone());
|
|
2366
|
+
return response;
|
|
2367
|
+
},
|
|
2368
|
+
});
|
|
2369
|
+
})();
|
|
2370
|
+
`;
|
|
2371
|
+
return {
|
|
2372
|
+
beforeLoad: mergeScripts(global2.webViewType === "game" && applyGameResourcesCache),
|
|
2373
|
+
afterLoad: mergeScripts(disableTextSelectionCSS)
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
function mergeScripts(...scripts) {
|
|
2377
|
+
return scripts.filter((script) => typeof script === "string").join("\n");
|
|
2378
|
+
}
|
|
2272
2379
|
|
|
2273
2380
|
// src/index.ts
|
|
2274
2381
|
export * from "@apps-in-toss/analytics";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apps-in-toss/framework",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.7",
|
|
5
5
|
"description": "The framework for Apps In Toss",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prepack": "yarn build",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"ait": "./bin/ait.js"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@apps-in-toss/analytics": "1.4.
|
|
60
|
-
"@apps-in-toss/cli": "1.4.
|
|
61
|
-
"@apps-in-toss/native-modules": "1.4.
|
|
62
|
-
"@apps-in-toss/plugins": "1.4.
|
|
63
|
-
"@apps-in-toss/types": "1.4.
|
|
59
|
+
"@apps-in-toss/analytics": "1.4.7",
|
|
60
|
+
"@apps-in-toss/cli": "1.4.7",
|
|
61
|
+
"@apps-in-toss/native-modules": "1.4.7",
|
|
62
|
+
"@apps-in-toss/plugins": "1.4.7",
|
|
63
|
+
"@apps-in-toss/types": "1.4.7",
|
|
64
64
|
"es-hangul": "^2.3.2"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
@@ -96,5 +96,5 @@
|
|
|
96
96
|
"publishConfig": {
|
|
97
97
|
"access": "public"
|
|
98
98
|
},
|
|
99
|
-
"gitHead": "
|
|
99
|
+
"gitHead": "9c3df99aae50b27ef775840416e7cc912de13c6a"
|
|
100
100
|
}
|