@jaeyeonee/capacitor-ios-webview 0.0.1
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/CustomWebview.podspec +17 -0
- package/Package.swift +28 -0
- package/README.md +45 -0
- package/dist/docs.json +41 -0
- package/dist/esm/definitions.d.ts +7 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +8 -0
- package/dist/esm/web.js +10 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +24 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +27 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CustomWebViewPlugin/CustomWebView.swift +162 -0
- package/ios/Sources/CustomWebViewPlugin/CustomWebViewPlugin.swift +43 -0
- package/ios/Tests/CustomWebViewPluginTests/CustomWebViewTests.swift +15 -0
- package/package.json +75 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapacitorIosCustomWebView'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '15.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.swift_version = '5.1'
|
|
17
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapacitorIosCustomWebView",
|
|
6
|
+
platforms: [.iOS(.v15)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "CapacitorIosCustomWebView",
|
|
10
|
+
targets: ["CapacitorIosCustomWebView"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
|
|
14
|
+
],
|
|
15
|
+
targets: [
|
|
16
|
+
.target(
|
|
17
|
+
name: "CapacitorIosCustomWebView",
|
|
18
|
+
dependencies: [
|
|
19
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
|
+
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
|
+
],
|
|
22
|
+
path: "ios/Sources/CustomWebViewPlugin"),
|
|
23
|
+
.testTarget(
|
|
24
|
+
name: "CapacitorIosCustomWebViewTests",
|
|
25
|
+
dependencies: ["CapacitorIosCustomWebView"],
|
|
26
|
+
path: "ios/Tests/CustomWebViewPluginTests")
|
|
27
|
+
]
|
|
28
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# capacitor-iosCustomWebView
|
|
2
|
+
|
|
3
|
+
capacitor iosCustomWebView
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install capacitor-iosCustomWebView
|
|
9
|
+
npx cap sync
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## API
|
|
13
|
+
|
|
14
|
+
<docgen-index>
|
|
15
|
+
|
|
16
|
+
* [`open(...)`](#open)
|
|
17
|
+
* [`close()`](#close)
|
|
18
|
+
|
|
19
|
+
</docgen-index>
|
|
20
|
+
|
|
21
|
+
<docgen-api>
|
|
22
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
23
|
+
|
|
24
|
+
### open(...)
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
open(options: { url: string; closeButtonText?: string; }) => Promise<void>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Param | Type |
|
|
31
|
+
| ------------- | ------------------------------------------------------- |
|
|
32
|
+
| **`options`** | <code>{ url: string; closeButtonText?: string; }</code> |
|
|
33
|
+
|
|
34
|
+
--------------------
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### close()
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
close() => Promise<void>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
--------------------
|
|
44
|
+
|
|
45
|
+
</docgen-api>
|
package/dist/docs.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"api": {
|
|
3
|
+
"name": "CustomWebViewPlugin",
|
|
4
|
+
"slug": "customwebviewplugin",
|
|
5
|
+
"docs": "",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"methods": [
|
|
8
|
+
{
|
|
9
|
+
"name": "open",
|
|
10
|
+
"signature": "(options: { url: string; closeButtonText?: string; }) => Promise<void>",
|
|
11
|
+
"parameters": [
|
|
12
|
+
{
|
|
13
|
+
"name": "options",
|
|
14
|
+
"docs": "",
|
|
15
|
+
"type": "{ url: string; closeButtonText?: string | undefined; }"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"returns": "Promise<void>",
|
|
19
|
+
"tags": [],
|
|
20
|
+
"docs": "",
|
|
21
|
+
"complexTypes": [],
|
|
22
|
+
"slug": "open"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "close",
|
|
26
|
+
"signature": "() => Promise<void>",
|
|
27
|
+
"parameters": [],
|
|
28
|
+
"returns": "Promise<void>",
|
|
29
|
+
"tags": [],
|
|
30
|
+
"docs": "",
|
|
31
|
+
"complexTypes": [],
|
|
32
|
+
"slug": "close"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"properties": []
|
|
36
|
+
},
|
|
37
|
+
"interfaces": [],
|
|
38
|
+
"enums": [],
|
|
39
|
+
"typeAliases": [],
|
|
40
|
+
"pluginConfigs": []
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface CustomWebViewPlugin {\n open(options: { url: string, closeButtonText?: string }): Promise<void>;\n\n close(): Promise<void>;\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
const CustomWebView = registerPlugin('CustomWebView', {
|
|
3
|
+
web: () => import('./web').then((m) => new m.CustomWebViewWeb()),
|
|
4
|
+
});
|
|
5
|
+
export * from './definitions';
|
|
6
|
+
export { CustomWebView };
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,aAAa,GAAG,cAAc,CAAsB,eAAe,EAAE;IACzE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;CACjE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { CustomWebViewPlugin } from './definitions';\n\nconst CustomWebView = registerPlugin<CustomWebViewPlugin>('CustomWebView', {\n web: () => import('./web').then((m) => new m.CustomWebViewWeb()),\n});\n\nexport * from './definitions';\nexport { CustomWebView };\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { CustomWebViewPlugin } from './definitions';
|
|
3
|
+
export declare class CustomWebViewWeb extends WebPlugin implements CustomWebViewPlugin {
|
|
4
|
+
open(options: {
|
|
5
|
+
url: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class CustomWebViewWeb extends WebPlugin {
|
|
3
|
+
async open(options) {
|
|
4
|
+
console.warn('[CustomWebView] open() is not supported on web', options);
|
|
5
|
+
}
|
|
6
|
+
async close() {
|
|
7
|
+
console.warn('[CustomWebView] close() is not supported on web');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IAC7C,KAAK,CAAC,IAAI,CAAC,OAAwB;QACjC,OAAO,CAAC,IAAI,CAAC,gDAAgD,EAAE,OAAO,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IAClE,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { CustomWebViewPlugin } from './definitions';\n\nexport class CustomWebViewWeb extends WebPlugin implements CustomWebViewPlugin {\n async open(options: { url: string }): Promise<void> {\n console.warn('[CustomWebView] open() is not supported on web', options);\n }\n\n async close(): Promise<void> {\n console.warn('[CustomWebView] close() is not supported on web');\n }\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@capacitor/core');
|
|
4
|
+
|
|
5
|
+
const CustomWebView = core.registerPlugin('CustomWebView', {
|
|
6
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CustomWebViewWeb()),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
class CustomWebViewWeb extends core.WebPlugin {
|
|
10
|
+
async open(options) {
|
|
11
|
+
console.warn('[CustomWebView] open() is not supported on web', options);
|
|
12
|
+
}
|
|
13
|
+
async close() {
|
|
14
|
+
console.warn('[CustomWebView] close() is not supported on web');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
19
|
+
__proto__: null,
|
|
20
|
+
CustomWebViewWeb: CustomWebViewWeb
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
exports.CustomWebView = CustomWebView;
|
|
24
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CustomWebView = registerPlugin('CustomWebView', {\n web: () => import('./web').then((m) => new m.CustomWebViewWeb()),\n});\nexport * from './definitions';\nexport { CustomWebView };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CustomWebViewWeb extends WebPlugin {\n async open(options) {\n console.warn('[CustomWebView] open() is not supported on web', options);\n }\n async close() {\n console.warn('[CustomWebView] close() is not supported on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;AACtD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AACpE,CAAC;;ACFM,MAAM,gBAAgB,SAASC,cAAS,CAAC;AAChD,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE;AACxB,QAAQ,OAAO,CAAC,IAAI,CAAC,gDAAgD,EAAE,OAAO,CAAC;AAC/E,IAAI;AACJ,IAAI,MAAM,KAAK,GAAG;AAClB,QAAQ,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC;AACvE,IAAI;AACJ;;;;;;;;;"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
var capacitorCustomWebView = (function (exports, core) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const CustomWebView = core.registerPlugin('CustomWebView', {
|
|
5
|
+
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CustomWebViewWeb()),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
class CustomWebViewWeb extends core.WebPlugin {
|
|
9
|
+
async open(options) {
|
|
10
|
+
console.warn('[CustomWebView] open() is not supported on web', options);
|
|
11
|
+
}
|
|
12
|
+
async close() {
|
|
13
|
+
console.warn('[CustomWebView] close() is not supported on web');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
18
|
+
__proto__: null,
|
|
19
|
+
CustomWebViewWeb: CustomWebViewWeb
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
exports.CustomWebView = CustomWebView;
|
|
23
|
+
|
|
24
|
+
return exports;
|
|
25
|
+
|
|
26
|
+
})({}, capacitorExports);
|
|
27
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst CustomWebView = registerPlugin('CustomWebView', {\n web: () => import('./web').then((m) => new m.CustomWebViewWeb()),\n});\nexport * from './definitions';\nexport { CustomWebView };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class CustomWebViewWeb extends WebPlugin {\n async open(options) {\n console.warn('[CustomWebView] open() is not supported on web', options);\n }\n async close() {\n console.warn('[CustomWebView] close() is not supported on web');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;IACtD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;IACpE,CAAC;;ICFM,MAAM,gBAAgB,SAASC,cAAS,CAAC;IAChD,IAAI,MAAM,IAAI,CAAC,OAAO,EAAE;IACxB,QAAQ,OAAO,CAAC,IAAI,CAAC,gDAAgD,EAAE,OAAO,CAAC;IAC/E,IAAI;IACJ,IAAI,MAAM,KAAK,GAAG;IAClB,QAAQ,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC;IACvE,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import WebKit
|
|
3
|
+
|
|
4
|
+
final class CustomWebViewController: UIViewController, UIGestureRecognizerDelegate, WKNavigationDelegate {
|
|
5
|
+
|
|
6
|
+
private let url: URL
|
|
7
|
+
private let closeButtonText: String
|
|
8
|
+
private let webView = WKWebView()
|
|
9
|
+
private var backButton: UIButton!
|
|
10
|
+
|
|
11
|
+
init(url: URL, closeButtonText: String? = nil) {
|
|
12
|
+
self.url = url
|
|
13
|
+
self.closeButtonText = closeButtonText ?? "Close"
|
|
14
|
+
super.init(nibName: nil, bundle: nil)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
required init?(coder: NSCoder) {
|
|
18
|
+
fatalError()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override func viewDidLoad() {
|
|
22
|
+
super.viewDidLoad()
|
|
23
|
+
view.backgroundColor = .white
|
|
24
|
+
|
|
25
|
+
setupHeader()
|
|
26
|
+
setupWebView()
|
|
27
|
+
load()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private func setupHeader() {
|
|
31
|
+
let header = UIView()
|
|
32
|
+
header.backgroundColor = .white
|
|
33
|
+
header.translatesAutoresizingMaskIntoConstraints = false
|
|
34
|
+
view.addSubview(header)
|
|
35
|
+
|
|
36
|
+
let back = UIButton(type: .system)
|
|
37
|
+
back.setImage(UIImage(systemName: "chevron.left"), for: .normal)
|
|
38
|
+
back.addTarget(self, action: #selector(backTapped), for: .touchUpInside)
|
|
39
|
+
back.translatesAutoresizingMaskIntoConstraints = false
|
|
40
|
+
header.addSubview(back)
|
|
41
|
+
self.backButton = back
|
|
42
|
+
|
|
43
|
+
let close = UIButton(type: .system)
|
|
44
|
+
close.setTitle(closeButtonText, for: .normal)
|
|
45
|
+
close.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
|
|
46
|
+
close.translatesAutoresizingMaskIntoConstraints = false
|
|
47
|
+
header.addSubview(close)
|
|
48
|
+
|
|
49
|
+
NSLayoutConstraint.activate([
|
|
50
|
+
header.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
|
|
51
|
+
header.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
52
|
+
header.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
53
|
+
header.heightAnchor.constraint(equalToConstant: 48),
|
|
54
|
+
|
|
55
|
+
back.leadingAnchor.constraint(equalTo: header.leadingAnchor, constant: 8),
|
|
56
|
+
back.centerYAnchor.constraint(equalTo: header.centerYAnchor),
|
|
57
|
+
back.widthAnchor.constraint(equalToConstant: 44),
|
|
58
|
+
back.heightAnchor.constraint(equalToConstant: 44),
|
|
59
|
+
|
|
60
|
+
close.leadingAnchor.constraint(equalTo: back.trailingAnchor, constant: 4),
|
|
61
|
+
close.centerYAnchor.constraint(equalTo: header.centerYAnchor)
|
|
62
|
+
])
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
private func setupWebView() {
|
|
67
|
+
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
68
|
+
webView.allowsBackForwardNavigationGestures = true
|
|
69
|
+
webView.navigationDelegate = self
|
|
70
|
+
view.addSubview(webView)
|
|
71
|
+
|
|
72
|
+
NSLayoutConstraint.activate([
|
|
73
|
+
webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 48),
|
|
74
|
+
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
75
|
+
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
76
|
+
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
|
77
|
+
])
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private func load() {
|
|
81
|
+
webView.load(URLRequest(url: url))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@objc private func closeTapped() {
|
|
85
|
+
dismiss(animated: true)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private var toastView: UIView?
|
|
93
|
+
|
|
94
|
+
private func showToast(_ message: String) {
|
|
95
|
+
toastView?.removeFromSuperview()
|
|
96
|
+
|
|
97
|
+
let label = UILabel()
|
|
98
|
+
label.text = message
|
|
99
|
+
label.textColor = .white
|
|
100
|
+
label.font = UIFont.preferredFont(forTextStyle: .callout)
|
|
101
|
+
label.textAlignment = .center
|
|
102
|
+
label.numberOfLines = 0
|
|
103
|
+
|
|
104
|
+
let container = UIView()
|
|
105
|
+
container.backgroundColor = UIColor.black.withAlphaComponent(0.7)
|
|
106
|
+
container.layer.cornerRadius = 10
|
|
107
|
+
container.clipsToBounds = true
|
|
108
|
+
container.alpha = 0
|
|
109
|
+
|
|
110
|
+
label.translatesAutoresizingMaskIntoConstraints = false
|
|
111
|
+
container.translatesAutoresizingMaskIntoConstraints = false
|
|
112
|
+
|
|
113
|
+
container.addSubview(label)
|
|
114
|
+
view.addSubview(container)
|
|
115
|
+
toastView = container
|
|
116
|
+
|
|
117
|
+
NSLayoutConstraint.activate([
|
|
118
|
+
label.topAnchor.constraint(equalTo: container.topAnchor, constant: 10),
|
|
119
|
+
label.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -10),
|
|
120
|
+
label.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 14),
|
|
121
|
+
label.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -14),
|
|
122
|
+
|
|
123
|
+
container.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
|
124
|
+
container.bottomAnchor.constraint(
|
|
125
|
+
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
|
126
|
+
constant: -20
|
|
127
|
+
),
|
|
128
|
+
container.widthAnchor.constraint(lessThanOrEqualToConstant: 320)
|
|
129
|
+
])
|
|
130
|
+
|
|
131
|
+
UIView.animate(withDuration: 0.25) {
|
|
132
|
+
container.alpha = 1
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.8) {
|
|
136
|
+
UIView.animate(withDuration: 0.25, animations: {
|
|
137
|
+
container.alpha = 0
|
|
138
|
+
}) { _ in
|
|
139
|
+
container.removeFromSuperview()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private var lastBackPressedAt: Date?
|
|
145
|
+
|
|
146
|
+
@objc private func backTapped() {
|
|
147
|
+
if webView.canGoBack {
|
|
148
|
+
webView.goBack()
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let now = Date()
|
|
153
|
+
|
|
154
|
+
if let last = lastBackPressedAt,
|
|
155
|
+
now.timeIntervalSince(last) < 2 {
|
|
156
|
+
dismiss(animated: true)
|
|
157
|
+
} else {
|
|
158
|
+
lastBackPressedAt = now
|
|
159
|
+
showToast("한 번 더 누르면 웹뷰가 종료됩니다.")
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
@objc(CustomWebViewPlugin)
|
|
5
|
+
public class CustomWebViewPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
6
|
+
|
|
7
|
+
public let identifier = "CustomWebViewPlugin"
|
|
8
|
+
public let jsName = "CustomWebView"
|
|
9
|
+
|
|
10
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
11
|
+
CAPPluginMethod(name: "open", returnType: CAPPluginReturnPromise),
|
|
12
|
+
CAPPluginMethod(name: "close", returnType: CAPPluginReturnNone)
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
private var webVC: CustomWebViewController?
|
|
16
|
+
|
|
17
|
+
@objc func open(_ call: CAPPluginCall) {
|
|
18
|
+
let urlString = call.getString("url") ?? ""
|
|
19
|
+
let closeButtonText = call.getString("closeButtonText") ?? ""
|
|
20
|
+
guard let url = URL(string: urlString) else {
|
|
21
|
+
call.reject("Invalid URL")
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
DispatchQueue.main.async {
|
|
27
|
+
let vc = CustomWebViewController(url: url, closeButtonText: closeButtonText)
|
|
28
|
+
vc.modalPresentationStyle = .fullScreen
|
|
29
|
+
self.bridge?.viewController?.present(vc, animated: true)
|
|
30
|
+
self.webVC = vc
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
call.resolve()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@objc func close(_ call: CAPPluginCall) {
|
|
37
|
+
DispatchQueue.main.async {
|
|
38
|
+
self.webVC?.dismiss(animated: true)
|
|
39
|
+
self.webVC = nil
|
|
40
|
+
}
|
|
41
|
+
call.resolve()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import CustomWebViewPlugin
|
|
3
|
+
|
|
4
|
+
class CustomWebViewTests: XCTestCase {
|
|
5
|
+
func testEcho() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
|
|
9
|
+
let implementation = CustomWebView()
|
|
10
|
+
let value = "Hello, World!"
|
|
11
|
+
let result = implementation.echo(value)
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(value, result)
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jaeyeonee/capacitor-ios-webview",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "capacitor-iosCustomWebView",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
16
|
+
"CustomWebview.podspec"
|
|
17
|
+
],
|
|
18
|
+
"author": "jaeyeonee",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/JaeyeoneeJ/capacitor-iosCustomWebView.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/JaeyeoneeJ/capacitor-iosCustomWebView/issues"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"capacitor",
|
|
29
|
+
"plugin",
|
|
30
|
+
"native"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"verify": "npm run verify:ios && npm run verify:web",
|
|
34
|
+
"verify:ios": "xcodebuild -scheme CustomWebview -destination generic/platform=iOS",
|
|
35
|
+
"verify:web": "npm run build",
|
|
36
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
37
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
38
|
+
"eslint": "eslint . --ext ts",
|
|
39
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
40
|
+
"swiftlint": "node-swiftlint",
|
|
41
|
+
"docgen": "docgen --api CustomWebViewPlugin --output-readme README.md --output-json dist/docs.json",
|
|
42
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
43
|
+
"clean": "rimraf ./dist",
|
|
44
|
+
"watch": "tsc --watch",
|
|
45
|
+
"prepublishOnly": "npm run build"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@capacitor/core": "^8.0.0",
|
|
49
|
+
"@capacitor/docgen": "^0.3.1",
|
|
50
|
+
"@capacitor/ios": "^8.0.0",
|
|
51
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
52
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
53
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
54
|
+
"eslint": "^8.57.1",
|
|
55
|
+
"prettier": "^3.6.2",
|
|
56
|
+
"prettier-plugin-java": "^2.7.7",
|
|
57
|
+
"rimraf": "^6.1.0",
|
|
58
|
+
"rollup": "^4.53.2",
|
|
59
|
+
"swiftlint": "^2.0.0",
|
|
60
|
+
"typescript": "^5.9.3"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@capacitor/core": ">=8.0.0"
|
|
64
|
+
},
|
|
65
|
+
"prettier": "@ionic/prettier-config",
|
|
66
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
67
|
+
"eslintConfig": {
|
|
68
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
69
|
+
},
|
|
70
|
+
"capacitor": {
|
|
71
|
+
"ios": {
|
|
72
|
+
"src": "ios"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|