web-launch-kit 0.0.7 → 0.0.8
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/README.ko.md +30 -3
- package/README.md +32 -2
- package/dist/index.d.ts +6 -1
- package/dist/launch-kit.cjs +62 -1
- package/dist/launch-kit.cjs.map +1 -1
- package/dist/launch-kit.min.cjs +1 -1
- package/dist/launch-kit.min.cjs.map +1 -1
- package/dist/launch-kit.min.mjs +1 -1
- package/dist/launch-kit.min.mjs.map +1 -1
- package/dist/launch-kit.mjs +62 -1
- package/dist/launch-kit.mjs.map +1 -1
- package/dist/launch-kit.umd.js +62 -1
- package/dist/launch-kit.umd.js.map +1 -1
- package/dist/launch-kit.umd.min.js +1 -1
- package/dist/launch-kit.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -33,7 +33,8 @@ npm install web-launch-kit
|
|
|
33
33
|
| `LaunchKit.map(options?)` | `Promise<AppOpenedBy>` | 검색어·좌표·경로로 지도 열기. OS별 네이티브 앱과 Google Maps 웹 폴백 |
|
|
34
34
|
| `LaunchKit.filepicker(options?)` | `Promise<File[]>` | 파일 또는 디렉터리 선택 (File System Access API, input 폴백) |
|
|
35
35
|
| `LaunchKit.setting(type?)` | `Promise<void>` | 지원되는 환경에서 시스템 설정 화면 열기 |
|
|
36
|
-
| `LaunchKit.
|
|
36
|
+
| `LaunchKit.escapeWebview(options?)` | `Promise<void>` | URL(기본값은 현재 페이지)을 외부 브라우저에서 다시 열어 인앱 웹뷰에서 탈출 |
|
|
37
|
+
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getter와 비동기 `getTrackId` / `getProductId` |
|
|
37
38
|
|
|
38
39
|
`AppOpenedBy`는 `"scheme"`, `"universal"`, `"intent"`, `"fallback"`, `"store"` 중 하나입니다.
|
|
39
40
|
|
|
@@ -82,8 +83,8 @@ LaunchKit.telephone({ to: '+821012345678' })
|
|
|
82
83
|
|
|
83
84
|
싱글톤의 형태는 `LaunchKitInstance`로 export되고, 모든 옵션 객체에 이름이 붙어 있습니다 —
|
|
84
85
|
`AppOpenOptions`, `AndroidAppInfo`, `IOSAppInfo`, `WindowsAppInfo`, `MacOSAppInfo`,
|
|
85
|
-
`TelephoneOptions`, `MessageOptions`, `MailOptions`, `MapOptions`, `FilepickerOptions
|
|
86
|
-
`SettingType`은 값 export이고 `AppOpenedBy`는 타입입니다.
|
|
86
|
+
`TelephoneOptions`, `MessageOptions`, `MailOptions`, `MapOptions`, `FilepickerOptions`,
|
|
87
|
+
`EscapeWebviewOptions`. `SettingType`은 값 export이고 `AppOpenedBy`는 타입입니다.
|
|
87
88
|
|
|
88
89
|
```ts
|
|
89
90
|
import LaunchKit, {
|
|
@@ -313,6 +314,32 @@ if (LaunchKit.utils.canOpenSetting) {
|
|
|
313
314
|
}
|
|
314
315
|
```
|
|
315
316
|
|
|
317
|
+
## 인앱 브라우저 탈출
|
|
318
|
+
|
|
319
|
+
`escapeWebview()`는 URL — 기본값은 현재 페이지 — 을 외부 기본 브라우저에서 다시 열어,
|
|
320
|
+
페이지가 갇혀 있는 인앱 웹뷰에서 탈출합니다.
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
import LaunchKit from 'web-launch-kit'
|
|
324
|
+
|
|
325
|
+
if (LaunchKit.utils.canEscapeWebview) {
|
|
326
|
+
await LaunchKit.escapeWebview()
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// 현재 페이지 대신 특정 URL을 내보낼 수도 있습니다
|
|
330
|
+
await LaunchKit.escapeWebview({ url: 'https://example.com/checkout' })
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
경로는 환경에 따라 결정됩니다. 카카오톡은 전용 `kakaotalk://web/openExternal` 스킴을
|
|
334
|
+
제공하고, LINE은 공식 문서화된 `openExternalBrowser=1` 쿼리 파라미터를 지원합니다 —
|
|
335
|
+
둘 다 안드로이드와 iOS에서 동작합니다. 그 외 웹뷰는 OS 경로로 폴백합니다. 안드로이드는
|
|
336
|
+
Chrome을 고정한 `intent://` URL(원본 URL이 `S.browser_fallback_url`로 실려서 Chrome이
|
|
337
|
+
없는 기기는 제자리에 머뭅니다), iOS는 비공개 `x-safari-` 스킴입니다 — iOS 15와 17+에서
|
|
338
|
+
동작하고 16에서는 동작하지 않으며, 기본 브라우저 설정과 무관하게 항상 Safari를 열고,
|
|
339
|
+
Meta 계열 웹뷰(Facebook, Instagram) 안에서는 차단됩니다. http(s) URL만 다시 열 수
|
|
340
|
+
있습니다. 웹뷰 밖이거나 사용 가능한 경로가 없으면(완전 차단 웹뷰, iOS 16, 데스크톱)
|
|
341
|
+
프로미스가 reject됩니다 — 버튼 노출은 `utils.canEscapeWebview`로 게이트하세요.
|
|
342
|
+
|
|
316
343
|
---
|
|
317
344
|
|
|
318
345
|
## 참고
|
package/README.md
CHANGED
|
@@ -34,7 +34,8 @@ The bundle is self-contained (OS/locale detection is inlined) — no peer script
|
|
|
34
34
|
| `LaunchKit.map(options?)` | `Promise<AppOpenedBy>` | Open a map by query, coordinate, or directions; native app per-OS with a Google Maps web fallback |
|
|
35
35
|
| `LaunchKit.filepicker(options?)` | `Promise<File[]>` | Pick files or a directory (File System Access API, with input fallback) |
|
|
36
36
|
| `LaunchKit.setting(type?)` | `Promise<void>` | Open a system-settings pane where supported |
|
|
37
|
-
| `LaunchKit.
|
|
37
|
+
| `LaunchKit.escapeWebview(options?)` | `Promise<void>` | Reopen a URL (the current page by default) in the external browser, escaping an in-app webview |
|
|
38
|
+
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getters, plus async `getTrackId` / `getProductId` |
|
|
38
39
|
|
|
39
40
|
`AppOpenedBy` is one of: `"scheme"`, `"universal"`, `"intent"`, `"fallback"`, `"store"`.
|
|
40
41
|
|
|
@@ -84,7 +85,8 @@ The global `LaunchKit` is a namespace object; the singleton is `LaunchKit.defaul
|
|
|
84
85
|
The singleton shape is exported as `LaunchKitInstance`, and every option object has a
|
|
85
86
|
named type: `AppOpenOptions`, `AndroidAppInfo`, `IOSAppInfo`, `WindowsAppInfo`,
|
|
86
87
|
`MacOSAppInfo`, `TelephoneOptions`, `MessageOptions`, `MailOptions`, `MapOptions`,
|
|
87
|
-
`FilepickerOptions`. `SettingType` is a value export;
|
|
88
|
+
`FilepickerOptions`, `EscapeWebviewOptions`. `SettingType` is a value export;
|
|
89
|
+
`AppOpenedBy` is a type.
|
|
88
90
|
|
|
89
91
|
```ts
|
|
90
92
|
import LaunchKit, {
|
|
@@ -316,6 +318,34 @@ if (LaunchKit.utils.canOpenSetting) {
|
|
|
316
318
|
}
|
|
317
319
|
```
|
|
318
320
|
|
|
321
|
+
## Escaping in-app browsers
|
|
322
|
+
|
|
323
|
+
`escapeWebview()` reopens a URL — the current page by default — in the external
|
|
324
|
+
default browser, escaping the in-app webview the page is trapped in.
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
import LaunchKit from 'web-launch-kit'
|
|
328
|
+
|
|
329
|
+
if (LaunchKit.utils.canEscapeWebview) {
|
|
330
|
+
await LaunchKit.escapeWebview()
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Or send a specific URL out instead of the current page
|
|
334
|
+
await LaunchKit.escapeWebview({ url: 'https://example.com/checkout' })
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The route depends on the environment. KakaoTalk exposes a dedicated
|
|
338
|
+
`kakaotalk://web/openExternal` scheme and LINE honors the documented
|
|
339
|
+
`openExternalBrowser=1` query parameter — both work on Android and iOS. Other
|
|
340
|
+
webviews fall back to the OS route: a Chrome-pinned `intent://` URL on Android
|
|
341
|
+
(the original URL rides along as `S.browser_fallback_url`, so a Chrome-less
|
|
342
|
+
device stays in place), and the undocumented `x-safari-` scheme on iOS — which
|
|
343
|
+
works on iOS 15 and 17+ but not 16, always opens Safari regardless of the
|
|
344
|
+
default browser, and is blocked inside Meta's webviews (Facebook, Instagram).
|
|
345
|
+
Only http(s) URLs can be reopened. Outside a webview, or where no route is
|
|
346
|
+
available (hard-blocked webviews, iOS 16, desktop), the promise rejects — gate
|
|
347
|
+
the button on `utils.canEscapeWebview`.
|
|
348
|
+
|
|
319
349
|
---
|
|
320
350
|
|
|
321
351
|
## Notes
|
package/dist/index.d.ts
CHANGED
|
@@ -93,10 +93,14 @@ declare interface MapOptions {
|
|
|
93
93
|
fallback?: URLStringOrFallback;
|
|
94
94
|
onAttempt?: (attempt: LaunchAttempt) => void;
|
|
95
95
|
}
|
|
96
|
+
declare interface EscapeWebviewOptions {
|
|
97
|
+
url?: URLCandidate;
|
|
98
|
+
}
|
|
96
99
|
interface LaunchKitUtils {
|
|
97
100
|
get canOpenIntent(): boolean;
|
|
98
101
|
get canOpenUniversal(): boolean;
|
|
99
102
|
get canOpenSetting(): boolean;
|
|
103
|
+
get canEscapeWebview(): boolean;
|
|
100
104
|
getTrackId(bundleId: string): Promise<string | undefined>;
|
|
101
105
|
getProductId(packageFamilyName: string): Promise<string | undefined>;
|
|
102
106
|
}
|
|
@@ -113,8 +117,9 @@ interface LaunchKitInstance {
|
|
|
113
117
|
map(options?: MapOptions): Promise<AppOpenedBy>;
|
|
114
118
|
filepicker(options?: FilepickerOptions): Promise<File[]>;
|
|
115
119
|
setting(type?: SettingType): Promise<void>;
|
|
120
|
+
escapeWebview(options?: EscapeWebviewOptions): Promise<void>;
|
|
116
121
|
}
|
|
117
122
|
declare const LaunchKit: LaunchKitInstance;
|
|
118
123
|
|
|
119
124
|
export { SettingType, LaunchKit as default };
|
|
120
|
-
export type { AndroidAppInfo, AppInfo, AppOpenOptions, AppOpenedBy, FilepickerOptions, IOSAppInfo, LaunchAttempt, LaunchError, LaunchErrorCode, LaunchKitInstance, MacOSAppInfo, MailOptions, MapOptions, MessageOptions, OpenPickerStartIn, TelephoneOptions, WindowsAppInfo };
|
|
125
|
+
export type { AndroidAppInfo, AppInfo, AppOpenOptions, AppOpenedBy, EscapeWebviewOptions, FilepickerOptions, IOSAppInfo, LaunchAttempt, LaunchError, LaunchErrorCode, LaunchKitInstance, MacOSAppInfo, MailOptions, MapOptions, MessageOptions, OpenPickerStartIn, TelephoneOptions, WindowsAppInfo };
|
package/dist/launch-kit.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var version$3 = "0.0.
|
|
5
|
+
var version$3 = "0.0.8";
|
|
6
6
|
var packageJSON$3 = {
|
|
7
7
|
version: version$3};
|
|
8
8
|
|
|
@@ -2526,6 +2526,34 @@ function isFullyBlockedInAppBrowser() {
|
|
|
2526
2526
|
function isPartnerAppOnly() {
|
|
2527
2527
|
return /weibo.*weibo__[\d.]+/i.test(PlatformKit.userAgent);
|
|
2528
2528
|
}
|
|
2529
|
+
function canOpenXSafari() {
|
|
2530
|
+
if (PlatformKit.os.name !== 'ios')
|
|
2531
|
+
return false;
|
|
2532
|
+
var version = PlatformKit.os.version;
|
|
2533
|
+
if (PlatformKit.compareVersion(version, '15.0') < 0)
|
|
2534
|
+
return false;
|
|
2535
|
+
if (PlatformKit.compareVersion(version, '16.0') >= 0 && PlatformKit.compareVersion(version, '17.0') < 0)
|
|
2536
|
+
return false;
|
|
2537
|
+
var inAppBrowser = PlatformKit.inAppBrowser;
|
|
2538
|
+
if (inAppBrowser === 'facebook' || inAppBrowser === 'instagram')
|
|
2539
|
+
return false;
|
|
2540
|
+
return canOpenScheme();
|
|
2541
|
+
}
|
|
2542
|
+
function isInWebview() {
|
|
2543
|
+
return PlatformKit.inAppBrowser !== null || PlatformKit.webview;
|
|
2544
|
+
}
|
|
2545
|
+
function canEscapeWebview() {
|
|
2546
|
+
if (!isInWebview())
|
|
2547
|
+
return false;
|
|
2548
|
+
var inAppBrowser = PlatformKit.inAppBrowser;
|
|
2549
|
+
if (inAppBrowser === 'kakaotalk' || inAppBrowser === 'line')
|
|
2550
|
+
return true;
|
|
2551
|
+
if (PlatformKit.os.name === 'android')
|
|
2552
|
+
return canOpenIntent();
|
|
2553
|
+
if (PlatformKit.os.name === 'ios')
|
|
2554
|
+
return canOpenXSafari();
|
|
2555
|
+
return false;
|
|
2556
|
+
}
|
|
2529
2557
|
function canOpenWindowsSetting(version) {
|
|
2530
2558
|
if (version.length === 0)
|
|
2531
2559
|
return false;
|
|
@@ -2623,6 +2651,24 @@ function createWebStoreURL(id, os) {
|
|
|
2623
2651
|
return os;
|
|
2624
2652
|
}
|
|
2625
2653
|
}
|
|
2654
|
+
function appendURLParameter(url, parameter) {
|
|
2655
|
+
var index = url.indexOf('#');
|
|
2656
|
+
var base = index === -1 ? url : url.substring(0, index);
|
|
2657
|
+
var hash = index === -1 ? '' : url.substring(index);
|
|
2658
|
+
return base + (base.indexOf('?') === -1 ? '?' : '&') + parameter + hash;
|
|
2659
|
+
}
|
|
2660
|
+
function createEscapeWebviewURL(url) {
|
|
2661
|
+
var inAppBrowser = PlatformKit.inAppBrowser;
|
|
2662
|
+
if (inAppBrowser === 'kakaotalk')
|
|
2663
|
+
return 'kakaotalk://web/openExternal?url=' + escapeURIComponentString(url);
|
|
2664
|
+
if (inAppBrowser === 'line')
|
|
2665
|
+
return appendURLParameter(url, 'openExternalBrowser=1');
|
|
2666
|
+
if (PlatformKit.os.name === 'android' && canOpenIntent())
|
|
2667
|
+
return createIntentURL(url, 'com.android.chrome', url);
|
|
2668
|
+
if (PlatformKit.os.name === 'ios' && canOpenXSafari())
|
|
2669
|
+
return 'x-safari-' + url;
|
|
2670
|
+
return undefined;
|
|
2671
|
+
}
|
|
2626
2672
|
function escapeURIComponentString(value) {
|
|
2627
2673
|
return encodeURIComponent(value)
|
|
2628
2674
|
.replace(/[!'()*]/g, function (char) {
|
|
@@ -2896,6 +2942,9 @@ var LaunchKit = {
|
|
|
2896
2942
|
get canOpenSetting() {
|
|
2897
2943
|
return canOpenSetting();
|
|
2898
2944
|
},
|
|
2945
|
+
get canEscapeWebview() {
|
|
2946
|
+
return canEscapeWebview();
|
|
2947
|
+
},
|
|
2899
2948
|
getTrackId: getTrackIdAsync,
|
|
2900
2949
|
getProductId: getProductIdAsync,
|
|
2901
2950
|
},
|
|
@@ -3163,6 +3212,18 @@ var LaunchKit = {
|
|
|
3163
3212
|
return openURLSequential();
|
|
3164
3213
|
});
|
|
3165
3214
|
},
|
|
3215
|
+
escapeWebview: function (options) {
|
|
3216
|
+
if (options === void 0) { options = {}; }
|
|
3217
|
+
if (!isInWebview())
|
|
3218
|
+
return Promise.reject(new Error('Escaping the webview is not needed: the current environment is not an in-app browser or webview. (userAgent: "' + PlatformKit.userAgent + '")'));
|
|
3219
|
+
var url = typeof options.url !== 'undefined' ? stripURL(options.url) : getTopmostWindow().location.href;
|
|
3220
|
+
if (!isWebURL(url))
|
|
3221
|
+
return Promise.reject(new Error('Cannot escape the webview: only http(s) URLs can be reopened in an external browser. (url: "' + url + '")'));
|
|
3222
|
+
var escape = createEscapeWebviewURL(url);
|
|
3223
|
+
if (typeof escape === 'undefined')
|
|
3224
|
+
return Promise.reject(new Error('Failed to escape the webview: no escape route is available in the current environment. (userAgent: "' + PlatformKit.userAgent + '")'));
|
|
3225
|
+
return openURL(0, escape, getDefaultTimeout(), isWebURL(escape));
|
|
3226
|
+
},
|
|
3166
3227
|
};
|
|
3167
3228
|
|
|
3168
3229
|
exports.default = LaunchKit;
|