@tokamakdev/platform-ios-simulator-x64 0.1.1-beta.100
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/ios-simulator-x64/build/entrypoint +245 -0
- package/ios-simulator-x64/build/ios-deployment-target +1 -0
- package/ios-simulator-x64/build/macos-deployment-target +1 -0
- package/ios-simulator-x64/frameworks/TokamakRuntime.framework/Headers/TokamakRuntime.h +67 -0
- package/ios-simulator-x64/frameworks/TokamakRuntime.framework/Modules/module.modulemap +4 -0
- package/ios-simulator-x64/frameworks/TokamakRuntime.framework/TokamakRuntime +0 -0
- package/ios-simulator-x64/native-shell/TokamakApp.swift +569 -0
- package/ios-simulator-x64/native-shell/TokamakOrigin.swift +20 -0
- package/ios-simulator-x64/native-shell/TokamakPlugins.swift +309 -0
- package/ios-simulator-x64/native-shell/TokamakShell.swift +515 -0
- package/ios-simulator-x64/platform-pack.json +36 -0
- package/ios-simulator-x64/tools/tokamak-apple-signing +0 -0
- package/package.json +23 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Network
|
|
3
|
+
import Security
|
|
4
|
+
import WebKit
|
|
5
|
+
|
|
6
|
+
#if os(macOS)
|
|
7
|
+
import AppKit
|
|
8
|
+
#else
|
|
9
|
+
import UIKit
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
private let failurePage =
|
|
13
|
+
"<h1>App failed to start</h1><p>Check startup-error.log for details.</p>"
|
|
14
|
+
|
|
15
|
+
private final class NavigationDelegate: NSObject, WKNavigationDelegate, WKUIDelegate {
|
|
16
|
+
private let runtime: RuntimeHandle
|
|
17
|
+
private let pluginBridge: TokamakPluginBridge
|
|
18
|
+
|
|
19
|
+
init(runtime: RuntimeHandle, pluginBridge: TokamakPluginBridge) {
|
|
20
|
+
self.runtime = runtime
|
|
21
|
+
self.pluginBridge = pluginBridge
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func webView(
|
|
25
|
+
_ webView: WKWebView,
|
|
26
|
+
didStartProvisionalNavigation navigation: WKNavigation?
|
|
27
|
+
) {
|
|
28
|
+
pluginBridge.close()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func webView(
|
|
32
|
+
_ webView: WKWebView,
|
|
33
|
+
decidePolicyFor navigationAction: WKNavigationAction,
|
|
34
|
+
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
|
|
35
|
+
) {
|
|
36
|
+
guard let url = navigationAction.request.url else {
|
|
37
|
+
decisionHandler(.cancel)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if navigationAction.targetFrame?.isMainFrame == false {
|
|
42
|
+
decisionHandler(.allow)
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if url.isAppOrigin(runtime.appHost) {
|
|
47
|
+
if navigationAction.targetFrame == nil {
|
|
48
|
+
webView.load(navigationAction.request)
|
|
49
|
+
decisionHandler(.cancel)
|
|
50
|
+
} else {
|
|
51
|
+
decisionHandler(.allow)
|
|
52
|
+
}
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
openExternal(url)
|
|
57
|
+
decisionHandler(.cancel)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func webView(
|
|
61
|
+
_ webView: WKWebView,
|
|
62
|
+
decidePolicyFor navigationResponse: WKNavigationResponse,
|
|
63
|
+
decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void
|
|
64
|
+
) {
|
|
65
|
+
guard
|
|
66
|
+
navigationResponse.isForMainFrame,
|
|
67
|
+
let url = navigationResponse.response.url
|
|
68
|
+
else {
|
|
69
|
+
decisionHandler(.allow)
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if url.isAppOrigin(runtime.appHost) {
|
|
74
|
+
decisionHandler(.allow)
|
|
75
|
+
} else {
|
|
76
|
+
openExternal(url)
|
|
77
|
+
decisionHandler(.cancel)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func webView(
|
|
82
|
+
_ webView: WKWebView,
|
|
83
|
+
createWebViewWith configuration: WKWebViewConfiguration,
|
|
84
|
+
for navigationAction: WKNavigationAction,
|
|
85
|
+
windowFeatures: WKWindowFeatures
|
|
86
|
+
) -> WKWebView? {
|
|
87
|
+
guard let url = navigationAction.request.url else { return nil }
|
|
88
|
+
if url.isAppOrigin(runtime.appHost) {
|
|
89
|
+
webView.load(navigationAction.request)
|
|
90
|
+
} else {
|
|
91
|
+
openExternal(url)
|
|
92
|
+
}
|
|
93
|
+
return nil
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// The app's own usage descriptions cover its origin; other origins keep
|
|
97
|
+
/// WebKit's prompt.
|
|
98
|
+
func webView(
|
|
99
|
+
_ webView: WKWebView,
|
|
100
|
+
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
|
|
101
|
+
initiatedByFrame frame: WKFrameInfo,
|
|
102
|
+
type: WKMediaCaptureType,
|
|
103
|
+
decisionHandler: @escaping (WKPermissionDecision) -> Void
|
|
104
|
+
) {
|
|
105
|
+
decisionHandler(origin.isAppOrigin(runtime.appHost) ? .grant : .prompt)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
func webView(
|
|
109
|
+
_ webView: WKWebView,
|
|
110
|
+
didReceive challenge: URLAuthenticationChallenge,
|
|
111
|
+
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
|
112
|
+
) {
|
|
113
|
+
let space = challenge.protectionSpace
|
|
114
|
+
switch space.authenticationMethod {
|
|
115
|
+
case NSURLAuthenticationMethodServerTrust:
|
|
116
|
+
answer(
|
|
117
|
+
runtime.serverAuthority(host: space.host),
|
|
118
|
+
trust: space.serverTrust,
|
|
119
|
+
completion: completionHandler
|
|
120
|
+
)
|
|
121
|
+
case NSURLAuthenticationMethodClientCertificate:
|
|
122
|
+
answer(
|
|
123
|
+
runtime.clientIdentity(
|
|
124
|
+
host: space.host,
|
|
125
|
+
previousFailures: challenge.previousFailureCount
|
|
126
|
+
),
|
|
127
|
+
completion: completionHandler
|
|
128
|
+
)
|
|
129
|
+
default:
|
|
130
|
+
completionHandler(.performDefaultHandling, nil)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func webView(
|
|
135
|
+
_ webView: WKWebView,
|
|
136
|
+
didFailProvisionalNavigation navigation: WKNavigation?,
|
|
137
|
+
withError error: Error
|
|
138
|
+
) {
|
|
139
|
+
print("tokamak WebView navigation failed: \(error)")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private func openExternal(_ url: URL) {
|
|
143
|
+
#if os(iOS)
|
|
144
|
+
UIApplication.shared.open(url)
|
|
145
|
+
#else
|
|
146
|
+
NSWorkspace.shared.open(url)
|
|
147
|
+
#endif
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private func answer(
|
|
151
|
+
_ material: AuthenticationMaterial<Data>,
|
|
152
|
+
trust: SecTrust?,
|
|
153
|
+
completion: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
|
154
|
+
) {
|
|
155
|
+
switch material {
|
|
156
|
+
case .defaultHandling:
|
|
157
|
+
completion(.performDefaultHandling, nil)
|
|
158
|
+
case .cancel:
|
|
159
|
+
completion(.cancelAuthenticationChallenge, nil)
|
|
160
|
+
case .use(let authority):
|
|
161
|
+
guard
|
|
162
|
+
let trust,
|
|
163
|
+
let certificate = SecCertificateCreateWithData(nil, authority as CFData),
|
|
164
|
+
SecTrustSetAnchorCertificates(trust, [certificate] as CFArray) == errSecSuccess,
|
|
165
|
+
SecTrustSetAnchorCertificatesOnly(trust, true) == errSecSuccess
|
|
166
|
+
else {
|
|
167
|
+
completion(.cancelAuthenticationChallenge, nil)
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
let queue = DispatchQueue.global(qos: .userInitiated)
|
|
171
|
+
queue.async {
|
|
172
|
+
SecTrustEvaluateAsyncWithError(trust, queue) { trust, trusted, error in
|
|
173
|
+
DispatchQueue.main.async {
|
|
174
|
+
guard trusted else {
|
|
175
|
+
print("tokamak refused the gateway's certificate: \(String(describing: error))")
|
|
176
|
+
completion(.cancelAuthenticationChallenge, nil)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
completion(.useCredential, URLCredential(trust: trust))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private func answer(
|
|
187
|
+
_ material: AuthenticationMaterial<(Data, Data)>,
|
|
188
|
+
completion: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
|
|
189
|
+
) {
|
|
190
|
+
switch material {
|
|
191
|
+
case .defaultHandling:
|
|
192
|
+
completion(.performDefaultHandling, nil)
|
|
193
|
+
case .cancel:
|
|
194
|
+
completion(.cancelAuthenticationChallenge, nil)
|
|
195
|
+
case .use(let value):
|
|
196
|
+
guard let identity = identity(certificate: value.0, privateKey: value.1) else {
|
|
197
|
+
completion(.cancelAuthenticationChallenge, nil)
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
let credential = URLCredential(identity: identity, certificates: nil, persistence: .none)
|
|
201
|
+
completion(.useCredential, credential)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private func identity(certificate: Data, privateKey: Data) -> SecIdentity? {
|
|
206
|
+
guard let certificate = SecCertificateCreateWithData(nil, certificate as CFData) else {
|
|
207
|
+
return nil
|
|
208
|
+
}
|
|
209
|
+
let attributes: [CFString: Any] = [
|
|
210
|
+
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
|
|
211
|
+
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
|
|
212
|
+
kSecAttrKeySizeInBits: 256,
|
|
213
|
+
]
|
|
214
|
+
guard let key = SecKeyCreateWithData(privateKey as CFData, attributes as CFDictionary, nil)
|
|
215
|
+
else {
|
|
216
|
+
return nil
|
|
217
|
+
}
|
|
218
|
+
return SecIdentityCreate(nil, certificate, key)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private final class TokamakController {
|
|
223
|
+
private let app: TokamakApp
|
|
224
|
+
private var runtime: RuntimeHandle?
|
|
225
|
+
private var navigation: NavigationDelegate?
|
|
226
|
+
private var pluginBridge: TokamakPluginBridge?
|
|
227
|
+
private weak var activeWebView: WKWebView?
|
|
228
|
+
private var dataStore: WKWebsiteDataStore?
|
|
229
|
+
private var proxyPort: UInt16?
|
|
230
|
+
|
|
231
|
+
init(app: TokamakApp) {
|
|
232
|
+
self.app = app
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
deinit {
|
|
236
|
+
pluginBridge?.close()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
func start(frame: CGRect, completion: @escaping (WKWebView) -> Void) {
|
|
240
|
+
app.whenStarted { result in
|
|
241
|
+
switch result {
|
|
242
|
+
case .success(let runtime):
|
|
243
|
+
self.runtime = runtime
|
|
244
|
+
completion(self.webView(frame: frame, runtime: runtime))
|
|
245
|
+
case .failure:
|
|
246
|
+
completion(self.failureWebView(frame: frame))
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
func restoreGateway() {
|
|
252
|
+
guard let runtime, let dataStore else { return }
|
|
253
|
+
do {
|
|
254
|
+
let port = try runtime.restoreGateway()
|
|
255
|
+
guard port != proxyPort else { return }
|
|
256
|
+
setProxy(port: port, host: runtime.appHost, dataStore: dataStore)
|
|
257
|
+
proxyPort = port
|
|
258
|
+
activeWebView?.reload()
|
|
259
|
+
} catch {
|
|
260
|
+
print("tokamak gateway could not recover: \(error)")
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private func webView(frame: CGRect, runtime: RuntimeHandle) -> WKWebView {
|
|
265
|
+
let configuration = WKWebViewConfiguration()
|
|
266
|
+
let dataStore = WKWebsiteDataStore.default()
|
|
267
|
+
let port = runtime.port
|
|
268
|
+
setProxy(port: port, host: runtime.appHost, dataStore: dataStore)
|
|
269
|
+
self.dataStore = dataStore
|
|
270
|
+
self.proxyPort = port
|
|
271
|
+
configuration.websiteDataStore = dataStore
|
|
272
|
+
// Video plays within the page, and media starts without a tap.
|
|
273
|
+
#if os(iOS)
|
|
274
|
+
configuration.allowsInlineMediaPlayback = true
|
|
275
|
+
#endif
|
|
276
|
+
configuration.mediaTypesRequiringUserActionForPlayback = []
|
|
277
|
+
|
|
278
|
+
let pluginBridge = TokamakPluginBridge(host: runtime.appHost, plugins: app.plugins)
|
|
279
|
+
pluginBridge.install(in: configuration.userContentController)
|
|
280
|
+
let navigation = NavigationDelegate(runtime: runtime, pluginBridge: pluginBridge)
|
|
281
|
+
self.navigation = navigation
|
|
282
|
+
let webView = WKWebView(frame: frame, configuration: configuration)
|
|
283
|
+
#if os(iOS)
|
|
284
|
+
webView.scrollView.bounces = false
|
|
285
|
+
#endif
|
|
286
|
+
webView.allowsLinkPreview = false
|
|
287
|
+
activeWebView = webView
|
|
288
|
+
pluginBridge.webView = webView
|
|
289
|
+
self.pluginBridge = pluginBridge
|
|
290
|
+
webView.navigationDelegate = navigation
|
|
291
|
+
webView.uiDelegate = navigation
|
|
292
|
+
webView.load(URLRequest(url: URL(string: "https://\(runtime.appHost)/")!))
|
|
293
|
+
return webView
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private func setProxy(port: UInt16, host: String, dataStore: WKWebsiteDataStore) {
|
|
297
|
+
var proxy = ProxyConfiguration(
|
|
298
|
+
httpCONNECTProxy: .hostPort(host: "127.0.0.1", port: NWEndpoint.Port(rawValue: port)!)
|
|
299
|
+
)
|
|
300
|
+
proxy.matchDomains = [host]
|
|
301
|
+
proxy.allowFailover = false
|
|
302
|
+
dataStore.proxyConfigurations = [proxy]
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private func failureWebView(frame: CGRect) -> WKWebView {
|
|
306
|
+
let webView = WKWebView(frame: frame)
|
|
307
|
+
webView.loadHTMLString(failurePage, baseURL: nil)
|
|
308
|
+
return webView
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#if os(macOS)
|
|
313
|
+
private final class TokamakMacApplicationDelegate: NSObject, NSApplicationDelegate {
|
|
314
|
+
private lazy var app = TokamakApp()
|
|
315
|
+
private lazy var controller = TokamakController(app: app)
|
|
316
|
+
private var window: NSWindow?
|
|
317
|
+
/// Whether the app is shown and its window is not miniaturised.
|
|
318
|
+
private var visible = false
|
|
319
|
+
|
|
320
|
+
func applicationDidFinishLaunching(_ notification: Notification) {
|
|
321
|
+
let window = NSWindow(
|
|
322
|
+
contentRect: NSRect(x: 0, y: 0, width: 1024, height: 768),
|
|
323
|
+
styleMask: [.titled, .closable, .miniaturizable, .resizable],
|
|
324
|
+
backing: .buffered,
|
|
325
|
+
defer: false
|
|
326
|
+
)
|
|
327
|
+
window.title =
|
|
328
|
+
Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String ?? "tokamak"
|
|
329
|
+
window.center()
|
|
330
|
+
window.makeKeyAndOrderFront(nil)
|
|
331
|
+
NSApplication.shared.activate(ignoringOtherApps: true)
|
|
332
|
+
self.window = window
|
|
333
|
+
visible = !NSApplication.shared.isHidden
|
|
334
|
+
app.start(foreground: visible)
|
|
335
|
+
observeVisibility()
|
|
336
|
+
|
|
337
|
+
guard let content = window.contentView else { return }
|
|
338
|
+
controller.start(frame: content.bounds) { webView in
|
|
339
|
+
webView.autoresizingMask = [.width, .height]
|
|
340
|
+
content.addSubview(webView)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
|
345
|
+
true
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
func application(
|
|
349
|
+
_ application: NSApplication,
|
|
350
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
|
|
351
|
+
) {
|
|
352
|
+
app.didRegisterForRemoteNotifications(deviceToken: deviceToken)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
func application(
|
|
356
|
+
_ application: NSApplication,
|
|
357
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error
|
|
358
|
+
) {
|
|
359
|
+
app.didFailToRegisterForRemoteNotifications(error: error)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
func application(
|
|
363
|
+
_ application: NSApplication,
|
|
364
|
+
didReceiveRemoteNotification userInfo: [String: Any]
|
|
365
|
+
) {
|
|
366
|
+
app.didReceiveRemoteNotification(userInfo) { _ in }
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/// Delivers `resume` and `suspend` as the app is hidden or shown, and as
|
|
370
|
+
/// its window is miniaturised or restored.
|
|
371
|
+
private func observeVisibility() {
|
|
372
|
+
let changes = [
|
|
373
|
+
NSApplication.didHideNotification,
|
|
374
|
+
NSApplication.didUnhideNotification,
|
|
375
|
+
NSWindow.didMiniaturizeNotification,
|
|
376
|
+
NSWindow.didDeminiaturizeNotification,
|
|
377
|
+
]
|
|
378
|
+
for change in changes {
|
|
379
|
+
_ = NotificationCenter.default.addObserver(forName: change, object: nil, queue: .main) {
|
|
380
|
+
[weak self] _ in
|
|
381
|
+
self?.visibilityChanged()
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private func visibilityChanged() {
|
|
387
|
+
let visible = !NSApplication.shared.isHidden && window?.isMiniaturized == false
|
|
388
|
+
guard visible != self.visible else { return }
|
|
389
|
+
self.visible = visible
|
|
390
|
+
app.moved(toForeground: visible)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
@main
|
|
395
|
+
private enum TokamakApplication {
|
|
396
|
+
static func main() {
|
|
397
|
+
let application = NSApplication.shared
|
|
398
|
+
let delegate = TokamakMacApplicationDelegate()
|
|
399
|
+
application.setActivationPolicy(.regular)
|
|
400
|
+
application.delegate = delegate
|
|
401
|
+
application.run()
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
#else
|
|
405
|
+
@main
|
|
406
|
+
private enum TokamakApplication {
|
|
407
|
+
/// Only an app that declares the `remote-notification` background mode
|
|
408
|
+
/// gets a delegate that receives remote notifications, which UIKit
|
|
409
|
+
/// otherwise warns about.
|
|
410
|
+
static func main() {
|
|
411
|
+
let modes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
412
|
+
let delegate: TokamakIOSApplicationDelegate.Type =
|
|
413
|
+
modes?.contains("remote-notification") == true
|
|
414
|
+
? TokamakIOSPushApplicationDelegate.self : TokamakIOSApplicationDelegate.self
|
|
415
|
+
UIApplicationMain(
|
|
416
|
+
CommandLine.argc,
|
|
417
|
+
CommandLine.unsafeArgv,
|
|
418
|
+
nil,
|
|
419
|
+
NSStringFromClass(delegate)
|
|
420
|
+
)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
private class TokamakIOSApplicationDelegate: UIResponder, UIApplicationDelegate {
|
|
425
|
+
/// Exists from launch, whether or not a scene connects.
|
|
426
|
+
let app = TokamakApp()
|
|
427
|
+
|
|
428
|
+
/// Starts the runtime once launch finishes. A scene a user launches the
|
|
429
|
+
/// app into has entered the foreground by then.
|
|
430
|
+
func application(
|
|
431
|
+
_ application: UIApplication,
|
|
432
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
433
|
+
) -> Bool {
|
|
434
|
+
DispatchQueue.main.async {
|
|
435
|
+
self.app.start(foreground: self.app.hasForegroundScene)
|
|
436
|
+
}
|
|
437
|
+
return true
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
func application(
|
|
441
|
+
_ application: UIApplication,
|
|
442
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
|
|
443
|
+
) {
|
|
444
|
+
app.didRegisterForRemoteNotifications(deviceToken: deviceToken)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
func application(
|
|
448
|
+
_ application: UIApplication,
|
|
449
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error
|
|
450
|
+
) {
|
|
451
|
+
app.didFailToRegisterForRemoteNotifications(error: error)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private final class TokamakIOSPushApplicationDelegate: TokamakIOSApplicationDelegate {
|
|
456
|
+
func application(
|
|
457
|
+
_ application: UIApplication,
|
|
458
|
+
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
|
|
459
|
+
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
460
|
+
) {
|
|
461
|
+
app.didReceiveRemoteNotification(userInfo) { result in
|
|
462
|
+
switch result {
|
|
463
|
+
case .newData: completionHandler(.newData)
|
|
464
|
+
case .noData: completionHandler(.noData)
|
|
465
|
+
case .failed: completionHandler(.failed)
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/// The Info.plist scene configuration names this class.
|
|
472
|
+
@objc(TokamakSceneDelegate)
|
|
473
|
+
private final class TokamakSceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
474
|
+
var window: UIWindow?
|
|
475
|
+
private var controller: TokamakController?
|
|
476
|
+
private var app: TokamakApp {
|
|
477
|
+
(UIApplication.shared.delegate as! TokamakIOSApplicationDelegate).app
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
func scene(
|
|
481
|
+
_ scene: UIScene,
|
|
482
|
+
willConnectTo session: UISceneSession,
|
|
483
|
+
options connectionOptions: UIScene.ConnectionOptions
|
|
484
|
+
) {
|
|
485
|
+
guard let scene = scene as? UIWindowScene else { return }
|
|
486
|
+
let viewController = UIViewController()
|
|
487
|
+
let window = UIWindow(windowScene: scene)
|
|
488
|
+
window.rootViewController = viewController
|
|
489
|
+
window.makeKeyAndVisible()
|
|
490
|
+
self.window = window
|
|
491
|
+
|
|
492
|
+
let controller = TokamakController(app: app)
|
|
493
|
+
controller.start(frame: viewController.view.bounds) { webView in
|
|
494
|
+
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
495
|
+
viewController.view.addSubview(webView)
|
|
496
|
+
}
|
|
497
|
+
self.controller = controller
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
func sceneWillEnterForeground(_ scene: UIScene) {
|
|
501
|
+
app.sceneWillEnterForeground()
|
|
502
|
+
controller?.restoreGateway()
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
func sceneDidEnterBackground(_ scene: UIScene) {
|
|
506
|
+
app.sceneDidEnterBackground()
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// Releases the scene's window and page, which a reconnection recreates.
|
|
510
|
+
func sceneDidDisconnect(_ scene: UIScene) {
|
|
511
|
+
window = nil
|
|
512
|
+
controller = nil
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
#endif
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tokamakVersion": "0.1.1",
|
|
3
|
+
"target": "ios-simulator-x64",
|
|
4
|
+
"variables": {
|
|
5
|
+
"build-number": {
|
|
6
|
+
"kind": "string",
|
|
7
|
+
"description": "CFBundleVersion, one to three period-separated integers; defaults to the app version"
|
|
8
|
+
},
|
|
9
|
+
"entitlements": {
|
|
10
|
+
"kind": "path",
|
|
11
|
+
"description": "Entitlements plist layered over the provisioning profile's entitlements at signing"
|
|
12
|
+
},
|
|
13
|
+
"plist": {
|
|
14
|
+
"kind": "path",
|
|
15
|
+
"description": "Info.plist whose values take precedence over generated and plugin values"
|
|
16
|
+
},
|
|
17
|
+
"provisioning-profile": {
|
|
18
|
+
"kind": "path",
|
|
19
|
+
"description": "Provisioning profile for manual signing, used with signing-identity"
|
|
20
|
+
},
|
|
21
|
+
"signing-identity": {
|
|
22
|
+
"kind": "string",
|
|
23
|
+
"description": "SHA-1 of the signing identity for manual signing, used with provisioning-profile"
|
|
24
|
+
},
|
|
25
|
+
"team-id": {
|
|
26
|
+
"kind": "string",
|
|
27
|
+
"description": "Apple Development team for automatic signing"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"pluginKeys": {
|
|
31
|
+
"class": "string",
|
|
32
|
+
"plist": "path",
|
|
33
|
+
"resources": "paths",
|
|
34
|
+
"sources": "paths"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tokamakdev/platform-ios-simulator-x64",
|
|
3
|
+
"version": "0.1.1-beta.100",
|
|
4
|
+
"description": "The tokamak platform pack for ios-simulator-x64",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/mantty/tokamak.git",
|
|
8
|
+
"directory": "tokamak-cli/npm/platform-packs/ios-simulator-x64"
|
|
9
|
+
},
|
|
10
|
+
"os": [
|
|
11
|
+
"darwin"
|
|
12
|
+
],
|
|
13
|
+
"cpu": [
|
|
14
|
+
"x64"
|
|
15
|
+
],
|
|
16
|
+
"preferUnplugged": true,
|
|
17
|
+
"files": [
|
|
18
|
+
"ios-simulator-x64"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
}
|
|
23
|
+
}
|