@webspatial/builder 0.0.9 → 0.0.11

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.
Files changed (92) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/lib/Cli.js +1 -1
  3. package/dist/lib/cmds/build.d.ts +1 -1
  4. package/dist/lib/cmds/build.js +1 -1
  5. package/dist/lib/cmds/check.js +1 -1
  6. package/dist/lib/cmds/help.js +1 -1
  7. package/dist/lib/cmds/version.js +1 -1
  8. package/dist/lib/pwa/config.js +1 -1
  9. package/dist/lib/pwa/index.js +1 -1
  10. package/dist/lib/pwa/validate.js +1 -1
  11. package/dist/lib/resource/file.js +1 -1
  12. package/dist/lib/resource/imageHelper.js +1 -1
  13. package/dist/lib/resource/index.d.ts +10 -3
  14. package/dist/lib/resource/index.js +1 -1
  15. package/dist/lib/resource/load.js +1 -1
  16. package/dist/lib/utils/CustomError.js +1 -1
  17. package/dist/lib/utils/FetchUtils-1.js +1 -1
  18. package/dist/lib/utils/Log.js +1 -1
  19. package/dist/lib/utils/fetch.js +1 -1
  20. package/dist/lib/utils/messages.js +1 -1
  21. package/dist/lib/utils/utils.d.ts +9 -0
  22. package/dist/lib/utils/utils.js +1 -1
  23. package/dist/lib/xcode/index.js +1 -1
  24. package/dist/lib/xcode/manifestSwiftTemplate.d.ts +1 -1
  25. package/dist/lib/xcode/manifestSwiftTemplate.js +1 -1
  26. package/dist/lib/xcode/xcodebuild.js +1 -1
  27. package/dist/lib/xcode/xcodeproject.js +1 -1
  28. package/dist/lib/xcode/xcrun.js +1 -1
  29. package/package.json +3 -2
  30. package/template/visionOSApp/Packages/RealityKitContent/.build/workspace-state.json +0 -7
  31. package/template/visionOSApp/Packages/RealityKitContent/.swiftpm/xcode/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  32. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json +0 -11
  33. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json +0 -112
  34. package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata +0 -17
  35. package/template/visionOSApp/Packages/RealityKitContent/Package.swift +0 -27
  36. package/template/visionOSApp/Packages/RealityKitContent/README.md +0 -3
  37. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda +0 -50
  38. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda +0 -216
  39. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda +0 -59
  40. package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift +0 -4
  41. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json +0 -12
  42. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json +0 -6
  43. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Contents.json +0 -17
  44. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json +0 -12
  45. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json +0 -6
  46. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json +0 -12
  47. package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json +0 -6
  48. package/template/visionOSApp/web-spatial/Assets.xcassets/Contents.json +0 -6
  49. package/template/visionOSApp/web-spatial/Info.plist +0 -33
  50. package/template/visionOSApp/web-spatial/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
  51. package/template/visionOSApp/web-spatial/libs/EventEmitter.swift +0 -32
  52. package/template/visionOSApp/web-spatial/libs/SpatialComponent.swift +0 -31
  53. package/template/visionOSApp/web-spatial/libs/SpatialEntity.swift +0 -179
  54. package/template/visionOSApp/web-spatial/libs/SpatialInputComponent.swift +0 -26
  55. package/template/visionOSApp/web-spatial/libs/SpatialMeshResource.swift +0 -19
  56. package/template/visionOSApp/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
  57. package/template/visionOSApp/web-spatial/libs/SpatialModelComponent.swift +0 -32
  58. package/template/visionOSApp/web-spatial/libs/SpatialObject.swift +0 -144
  59. package/template/visionOSApp/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
  60. package/template/visionOSApp/web-spatial/libs/SpatialViewComponent.swift +0 -15
  61. package/template/visionOSApp/web-spatial/libs/SpatialWindowComponent.swift +0 -420
  62. package/template/visionOSApp/web-spatial/libs/SpatialWindowContainer.swift +0 -149
  63. package/template/visionOSApp/web-spatial/libs/Utils/CommandManager.swift +0 -800
  64. package/template/visionOSApp/web-spatial/libs/Utils/Logger.swift +0 -36
  65. package/template/visionOSApp/web-spatial/libs/Utils/SceneManager.swift +0 -108
  66. package/template/visionOSApp/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -113
  67. package/template/visionOSApp/web-spatial/libs/json/JsonParser.swift +0 -52
  68. package/template/visionOSApp/web-spatial/libs/uiKitDelegate/Window.swift +0 -34
  69. package/template/visionOSApp/web-spatial/libs/webView/UpdateSystem.swift +0 -33
  70. package/template/visionOSApp/web-spatial/libs/webView/backend/NativeWebView.swift +0 -319
  71. package/template/visionOSApp/web-spatial/libs/webView/manifest.swift +0 -92
  72. package/template/visionOSApp/web-spatial/static-web/index.html +0 -9
  73. package/template/visionOSApp/web-spatial/views/HideViewModifier.swift +0 -17
  74. package/template/visionOSApp/web-spatial/views/ImmersiveView.swift +0 -24
  75. package/template/visionOSApp/web-spatial/views/LoadingView.swift +0 -25
  76. package/template/visionOSApp/web-spatial/views/MaterialWithBorderCornerModifier.swift +0 -82
  77. package/template/visionOSApp/web-spatial/views/OpenDismissHandlerUI.swift +0 -52
  78. package/template/visionOSApp/web-spatial/views/PlainWindowContainerView.swift +0 -84
  79. package/template/visionOSApp/web-spatial/views/SpatialModel3DView.swift +0 -193
  80. package/template/visionOSApp/web-spatial/views/SpatialViewUI.swift +0 -168
  81. package/template/visionOSApp/web-spatial/views/SpatialWebViewUI.swift +0 -186
  82. package/template/visionOSApp/web-spatial/views/VolumetricWindowContainerView.swift +0 -38
  83. package/template/visionOSApp/web-spatial/views/ui/NavView.swift +0 -125
  84. package/template/visionOSApp/web-spatial/web_spatialApp.swift +0 -158
  85. package/template/visionOSApp/web-spatial.xcodeproj/project.pbxproj +0 -686
  86. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  87. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  88. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +0 -5
  89. package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcuserdata/bytedance.xcuserdatad/WorkspaceSettings.xcsettings +0 -14
  90. package/template/visionOSApp/web-spatial.xcodeproj/xcshareddata/xcschemes/web-spatial.xcscheme +0 -115
  91. package/template/visionOSApp/web-spatial.xcodeproj/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -27
  92. package/template/visionOSApp/web-spatialTests/web_spatialTests.swift +0 -34
@@ -1,36 +0,0 @@
1
- //
2
- // Logger.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 7/18/24.
6
- //
7
-
8
- import Foundation
9
-
10
- class Logger {
11
- static func getLogger() -> Logger {
12
- return Logger()
13
- }
14
-
15
- static func initLogger() {}
16
-
17
- func error(_ str: String) {
18
- print("error: " + str)
19
- }
20
-
21
- func verbose(_ str: String) {
22
- print("verbose: " + str)
23
- }
24
-
25
- func debug(_ str: String) {
26
- print("debug: " + str)
27
- }
28
-
29
- func info(_ str: String) {
30
- print("info: " + str)
31
- }
32
-
33
- func warning(_ str: String) {
34
- print("warning: " + str)
35
- }
36
- }
@@ -1,108 +0,0 @@
1
- //
2
- // SceneManager.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 2025/2/6.
6
- //
7
-
8
- import Foundation
9
-
10
- class SceneManager {
11
- static let Instance = SceneManager()
12
-
13
- private init() {}
14
-
15
- // create scene
16
- // if config is provided, it show immediately
17
- // else it won't show until showRoot is called
18
- func createRoot(target: SpatialWindowComponent, windowID: String, config: WindowContainerOptions? = nil) {
19
- let windowContainerID = UUID().uuidString
20
- // open window
21
- let wgd = WindowContainerData(
22
- windowStyle: "Plain",
23
- windowContainerID: windowContainerID
24
- )
25
- let ent = SpatialEntity()
26
- ent.coordinateSpace = CoordinateSpaceMode.ROOT
27
- let windowComponent = SpatialWindowComponent(
28
- parentWindowContainerID: windowContainerID
29
- )
30
-
31
- if let spawnedWebView = target.spawnedNativeWebviews.removeValue(forKey: windowID) {
32
- windowComponent.getView()!.destroy()
33
- windowComponent.setView(wv: spawnedWebView)
34
- windowComponent.getView()!.webViewHolder.webViewCoordinator!.webViewRef = windowComponent
35
- // focusRoot need the windowContainerID
36
- windowComponent.evaluateJS(js: "window._webSpatialGroupID='\(windowContainerID)';")
37
- // tell new webview parentWindowContainerID to open loadingview
38
- windowComponent.evaluateJS(js: "window._webSpatialParentGroupID='\(target.parentWindowContainerID)';")
39
-
40
- if config != nil {
41
- // signal off hook
42
- windowComponent.evaluateJS(js: "window._SceneHookOff=true;")
43
- }
44
- } else {
45
- logger.warning("Unable to find spawned webview")
46
- }
47
-
48
- ent.addComponent(windowComponent)
49
-
50
- let wg = SpatialWindowContainer.getOrCreateSpatialWindowContainer(windowContainerID, wgd)
51
- ent.setParentWindowContainer(wg: wg)
52
-
53
- if let config = config {
54
- showRoot(
55
- target: windowComponent,
56
- config: config,
57
- parentWindowContainerID: target.parentWindowContainerID
58
- )
59
- }
60
- }
61
-
62
- // set defaultvalues for the scene and show it
63
- func showRoot(target: SpatialWindowComponent, config: WindowContainerOptions, parentWindowContainerID: String) {
64
- let plainDV = WindowContainerPlainDefaultValues(
65
- config
66
- )
67
-
68
- if let pwg = SpatialWindowContainer.getSpatialWindowContainer(parentWindowContainerID),
69
- let wg = SpatialWindowContainer.getSpatialWindowContainer(
70
- target.parentWindowContainerID
71
- )
72
- {
73
- WindowContainerMgr.Instance
74
- .updateWindowContainerPlainDefaultValues(
75
- plainDV
76
- ) // set default values
77
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
78
- pwg.openWindowData.send(wg.wgd) // openwindow
79
- }
80
- }
81
- }
82
-
83
- // bring the scene to focus
84
- func focusRoot(target: SpatialWindowComponent, windowContainerID: String) {
85
- if let wg = SpatialWindowContainer.getSpatialWindowContainer(windowContainerID) {
86
- wg.openWindowData.send(wg.wgd)
87
- }
88
- }
89
-
90
- // show LodingView when window.xrCurrentSceneDefaults is executing
91
- func setLoading(_ method: LoadingMethod, windowContainerID: String) {
92
- // trigger open loading view by parent windowContainer due to current windowContainer isn't visible yet
93
- if let wg = SpatialWindowContainer.getSpatialWindowContainer(windowContainerID) {
94
- let lwgdata = LoadingWindowContainerData(
95
- method: method,
96
- windowStyle: nil
97
- )
98
- wg.setLoadingWindowData.send(lwgdata)
99
- }
100
- }
101
-
102
- // dismiss the scene content when webview closed
103
- func closeRoot(_ target: SpatialWindowComponent) {
104
- if let wg = SpatialWindowContainer.getSpatialWindowContainer(target.parentWindowContainerID) {
105
- wg.closeWindowData.send(wg.wgd)
106
- }
107
- }
108
- }
@@ -1,113 +0,0 @@
1
- //
2
- // WindowContainerMgr.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 2024/12/13.
6
- //
7
-
8
- //
9
- // WindowContainerModel.swift
10
- // web-spatial
11
- //
12
- // Created by ByteDance on 2024/11/25.
13
- //
14
-
15
- import Combine
16
- import SwiftUI
17
- import UIKit
18
-
19
- // TODO: maybe get input from pwa manifest
20
- let defaultWindowContainerConfig = WindowContainerOptions(
21
- defaultSize: WindowContainerOptions.Size(
22
- width: DefaultPlainWindowContainerSize.width,
23
- height: DefaultPlainWindowContainerSize.height
24
- ),
25
- resizability: nil
26
- )
27
-
28
- struct WindowContainerData: Decodable, Hashable, Encodable {
29
- let windowStyle: String
30
- let windowContainerID: String
31
- }
32
-
33
- enum LoadingMethod: String, Decodable, Encodable, Hashable {
34
- case show
35
- case hide
36
- }
37
-
38
- struct LoadingWindowContainerData: Decodable, Hashable, Encodable {
39
- let method: LoadingMethod
40
- let windowStyle: String?
41
- }
42
-
43
- struct WindowContainerPlainDefaultValues {
44
- var defaultSize: CGSize?
45
- var windowResizability: WindowResizability?
46
- }
47
-
48
- // support WindowContainerOptions => WindowContainerPlainDefaultValues
49
- extension WindowContainerPlainDefaultValues {
50
- init(_ options: WindowContainerOptions) {
51
- defaultSize = CGSize(
52
- width: options.defaultSize?.width ?? DefaultPlainWindowContainerSize.width,
53
- height: options.defaultSize?.height ?? DefaultPlainWindowContainerSize.height
54
- )
55
- windowResizability = getWindowResizability(options.resizability)
56
- }
57
- }
58
-
59
- // incomming JSB data
60
- struct WindowContainerOptions: Codable {
61
- // windowContainer
62
- let defaultSize: Size?
63
- let resizability: String?
64
- struct Size: Codable {
65
- var width: Double
66
- var height: Double
67
- }
68
- }
69
-
70
- func getWindowResizability(_ windowResizability: String?) -> WindowResizability {
71
- switch windowResizability {
72
- case "automatic":
73
- return .automatic
74
- case "contentSize":
75
- return .contentSize
76
- case "contentMinSize":
77
- return .contentMinSize
78
- default:
79
- return .automatic
80
- }
81
- }
82
-
83
- @Observable
84
- class WindowContainerMgr: ObservableObject {
85
- static let Instance = WindowContainerMgr()
86
-
87
- private init() {
88
- setToMainSceneCfg()
89
- }
90
-
91
- private var wgSetting: WindowContainerPlainDefaultValues = .init(
92
- defaultSize: CGSize(width: 1080, height: 720),
93
- windowResizability: .automatic
94
- )
95
-
96
- func getValue() -> WindowContainerPlainDefaultValues {
97
- return wgSetting
98
- }
99
-
100
- func setToMainSceneCfg() {
101
- let cfg = WindowContainerPlainDefaultValues(pwaManager.mainScene)
102
- updateWindowContainerPlainDefaultValues(cfg)
103
- }
104
-
105
- func updateWindowContainerPlainDefaultValues(_ data: WindowContainerPlainDefaultValues) {
106
- if let newSize = data.defaultSize {
107
- wgSetting.defaultSize = newSize
108
- }
109
- if let newResizability = data.windowResizability {
110
- wgSetting.windowResizability = newResizability
111
- }
112
- }
113
- }
@@ -1,52 +0,0 @@
1
- //
2
- // JsonParser.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 5/9/24.
6
- //
7
-
8
- import Foundation
9
-
10
- class JsonParser {
11
- var json: [String: AnyObject]?
12
- init(str: String?) {
13
- if let toParse = str {
14
- if let data = toParse.data(using: .utf8) {
15
- do {
16
- json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: AnyObject]
17
- } catch {}
18
- }
19
- }
20
- }
21
-
22
- func getValue<T>(lookup: [String]) -> T? {
23
- if var anyObj = json as? AnyObject {
24
- for (index, str) in lookup.enumerated() {
25
- if index == lookup.count - 1 {
26
- return anyObj[str] as? T
27
- }
28
- if let o = (anyObj as? [String: AnyObject]),
29
- let x = o[str]
30
- {
31
- anyObj = x
32
- } else {
33
- return nil
34
- }
35
- }
36
- }
37
- return nil
38
- }
39
-
40
- // Convert the instance to a JSON string
41
- static func serialize<T: Encodable>(_ data: T) -> String? {
42
- let encoder = JSONEncoder()
43
- encoder.outputFormatting = .prettyPrinted // Makes the JSON output more readable
44
- do {
45
- let jsonData = try encoder.encode(data)
46
- return String(data: jsonData, encoding: .utf8) // Convert Data to String
47
- } catch {
48
- logger.error("Failed to encode WindowContainerOptions to JSON: \(error)")
49
- return nil
50
- }
51
- }
52
- }
@@ -1,34 +0,0 @@
1
- //
2
- // Window.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 7/3/24.
6
- //
7
-
8
- import Foundation
9
- import SwiftUI
10
-
11
- // Access window (https://stackoverflow.com/questions/60359808/how-to-access-own-window-within-swiftui-view/60359809#60359809)
12
- class SceneDelegate: NSObject, ObservableObject, UIWindowSceneDelegate {
13
- var window: UIWindow? // << contract of `UIWindowSceneDelegate`
14
-
15
- func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16
- guard let windowScene = scene as? UIWindowScene else { return }
17
- window = windowScene.keyWindow // << store !!!
18
- }
19
-
20
- // do memory cleanup after scene removed, otherwise windowContainer cannot destroy content after being dismissed
21
- func sceneDidDisconnect(_ scene: UIScene) {
22
- window = nil
23
- }
24
- }
25
-
26
- class AppDelegate: NSObject, UIApplicationDelegate {
27
- func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
28
- let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
29
- if connectingSceneSession.role == .windowApplication {
30
- configuration.delegateClass = SceneDelegate.self
31
- }
32
- return configuration
33
- }
34
- }
@@ -1,33 +0,0 @@
1
- //
2
- // UpdateSystem.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 5/21/24.
6
- //
7
-
8
- import Foundation
9
- import RealityKit
10
-
11
- struct UpdateWebViewComponent: Component {
12
- var webView: SpatialWindowComponent?
13
- init() {}
14
- }
15
-
16
- class UpdateWebViewSystem: System {
17
- static let query = EntityQuery(where: .has(UpdateWebViewComponent.self))
18
- required init(scene: RealityKit.Scene) {
19
- // Perform required initialization or setup.
20
- }
21
-
22
- var pos = 0.0
23
- func update(context: SceneUpdateContext) {
24
- for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
25
- pos += context.deltaTime
26
-
27
- var x = Transform()
28
- x.translation.x = Float(sin(pos)) * 0.3
29
- x.translation.z = 0.2
30
- entity.move(to: x, relativeTo: nil)
31
- }
32
- }
33
- }
@@ -1,319 +0,0 @@
1
- //
2
- // NativeWebView.swift
3
- // web-spatial
4
- //
5
- // Created by ByteDance on 5/9/24.
6
- //
7
-
8
- import Combine
9
- import Foundation
10
- import RealityKit
11
- import RealityKitContent
12
- import SwiftUI
13
- @preconcurrency import WebKit
14
-
15
- class WebViewHolder {
16
- var needsUpdate = false
17
- var appleWebView: WKWebView?
18
- var webViewCoordinator: Coordinator?
19
- deinit {
20
- appleWebView = nil
21
- }
22
- }
23
-
24
- struct PreloadStyleSettings: Codable {
25
- var cornerRadius: CornerRadius? = .init()
26
- var backgroundMaterial: BackgroundMaterial? = .None
27
- }
28
-
29
- struct WebviewEarlyStyle {
30
- let webview: WKWebView
31
- let style: PreloadStyleSettings
32
- }
33
-
34
- // event of forcestyle handler
35
- var webviewGetEarlyStyleData = PassthroughSubject<WebviewEarlyStyle, Never>()
36
-
37
- class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate, UIScrollViewDelegate, WKURLSchemeHandler {
38
- let decoder = JSONDecoder()
39
- override public init() {
40
- WKWebView.enableFileScheme() // ensure the handler is usable
41
- }
42
-
43
- func webView(_ webView: WKWebView, start urlSchemeTask: any WKURLSchemeTask) {
44
- // Parse the style json string from url
45
- let url = urlSchemeTask.request.url
46
-
47
- // Local web projects accessing resources through relative paths will default to using the file protocol
48
- if url!.absoluteString.starts(with: "file://") {
49
- let resource: String = pwaManager.getLocalResourceURL(url: url!.absoluteString)
50
- var urlRequest = urlSchemeTask.request
51
-
52
- if resource != "" {
53
- urlRequest = URLRequest(url: URL(string: resource)!)
54
- } else {
55
- return
56
- }
57
- let session = URLSession(configuration: URLSessionConfiguration.default)
58
- let dataTask = session.dataTask(with: urlRequest) { data, response, _ in
59
- urlSchemeTask.didReceive(response!)
60
- urlSchemeTask.didReceive(data!)
61
- urlSchemeTask.didFinish()
62
- }
63
- dataTask.resume()
64
- return
65
- }
66
-
67
- var styleJsonString: String? = URLComponents(string: url!.absoluteString)?.queryItems?.first(where: { $0.name == "style" })?.value
68
-
69
- do {
70
- if styleJsonString?.contains("?") != nil {
71
- // remove invalid query string
72
- // before "{\"glassEffect\":true,\"cornerRadius\":50}?uniqueURL=0.0010192470591506853"
73
- // after "{\"glassEffect\":true,\"cornerRadius\":50}"
74
- styleJsonString = styleJsonString?
75
- .components(separatedBy: "?").first
76
- }
77
- let styleToSet = try decoder.decode(PreloadStyleSettings.self, from: styleJsonString!.data(using: .utf8)!)
78
-
79
- webviewGetEarlyStyleData.send(WebviewEarlyStyle(webview: webView, style: styleToSet))
80
- } catch {
81
- logger.warning("Style url parse failure " + error.localizedDescription)
82
- }
83
-
84
- // Respond with empty css file
85
- let response = ".ignoreThis{}".data(using: .utf8)
86
- let mimeType = "text/css"
87
- let headers = ["Content-Type": mimeType, "Cache-Control": "no-cache"]
88
- let resp = HTTPURLResponse(url: url!, statusCode: 200, httpVersion: "1.1", headerFields: headers)
89
-
90
- urlSchemeTask.didReceive(resp!)
91
- urlSchemeTask.didReceive(response!)
92
- urlSchemeTask.didFinish()
93
- }
94
-
95
- func webView(_ webView: WKWebView, stop urlSchemeTask: any WKURLSchemeTask) {}
96
-
97
- @Environment(\.openWindow) private var openWindow
98
- @Environment(\.dismissWindow) private var dismissWindow
99
- @Environment(\.dismiss) private var dismiss
100
- @Environment(\.openImmersiveSpace) private var openImmersiveSpace
101
-
102
- deinit {}
103
-
104
- weak var webViewRef: SpatialWindowComponent? = nil
105
-
106
- func webView(_ webView: WKWebView, didStartProvisionalNavigation: WKNavigation!) {
107
- webViewRef?.didStartLoadPage()
108
- }
109
-
110
- func webView(
111
- _ webView: WKWebView,
112
- didCommit navigation: WKNavigation!
113
- ) {
114
- webViewRef?.didStartReceivePageContent()
115
- }
116
-
117
- func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
118
- webViewRef?.loadRequestWV?.didLoadChild(loadRequestID: webViewRef!.loadRequestID, resourceID: webViewRef!.id)
119
- webViewRef?.loadRequestID = -1
120
- webViewRef?.didFinishLoadPage()
121
- }
122
-
123
- func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
124
- if let url = navigationAction.request.url,
125
- url.absoluteString == "webspatial://createWindowContext"
126
- {
127
- decisionHandler(.cancel)
128
- return
129
- }
130
- var resource = navigationAction.request.url!.absoluteString
131
- if pwaManager.isLocal {
132
- resource = pwaManager.getLocalResourceURL(url: resource)
133
- }
134
- if pwaManager.checkInScope(url: navigationAction.request.url!.absoluteString) {
135
- if navigationAction.navigationType == .backForward {
136
- // backward/forward
137
- webViewRef?.didNavBackForward()
138
- }
139
- decisionHandler(.allow)
140
- } else {
141
- decisionHandler(.cancel)
142
- UIApplication.shared.open(navigationAction.request.url!, options: [:], completionHandler: nil)
143
- }
144
- }
145
-
146
- func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Swift.Void) {
147
- decisionHandler(.allow)
148
- }
149
-
150
- func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
151
- logger.warning("Navigation failed!!! " + error.localizedDescription)
152
- if let urlError = (error as? URLError) {
153
- logger.warning("URL ERROR: " + (urlError.failingURL != nil ? (urlError.failingURL!.absoluteString) : "no URL found"))
154
- if urlError.code == .cannotConnectToHost {
155
- webViewRef?.didFailLoadPage()
156
- }
157
- }
158
- }
159
-
160
- // Warning this should likeley be removed. There seems to be a bug with SSL loading on simulator https://stackoverflow.com/questions/27100540/allow-unverified-ssl-certificates-in-wkwebview
161
- // NSAllowsArbitraryLoads should also be removed from Info.plist if shipping an app
162
- // this is the workaround
163
- func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
164
- guard let serverTrust = challenge.protectionSpace.serverTrust else { return completionHandler(.useCredential, nil) }
165
- let exceptions = SecTrustCopyExceptions(serverTrust)
166
- SecTrustSetExceptions(serverTrust, exceptions)
167
- completionHandler(.useCredential, URLCredential(trust: serverTrust))
168
- }
169
-
170
- func webView(
171
- _ webView: WKWebView,
172
- createWebViewWith configuration: WKWebViewConfiguration,
173
- for navigationAction: WKNavigationAction,
174
- windowFeatures: WKWindowFeatures
175
- ) -> WKWebView? {
176
- let url = navigationAction.request.url?.absoluteString ?? ""
177
-
178
- if url != "webspatial://createWindowContext",
179
- !pwaManager.checkInScope(url: url)
180
- {
181
- // open in safari
182
- UIApplication.shared.open(navigationAction.request.url!, options: [:], completionHandler: nil)
183
- return nil
184
- }
185
-
186
- let wvNative = WebViewNative()
187
-
188
- _ = wvNative.createResources(configuration: configuration)
189
-
190
- webViewRef!.didSpawnWebView(wv: wvNative)
191
-
192
- return wvNative.webViewHolder.appleWebView
193
- }
194
-
195
- // handle close
196
- func webViewDidClose(_ webView: WKWebView) {
197
- webViewRef!.didCloseWebView()
198
- }
199
-
200
- // receive message from wkwebview
201
- func userContentController(
202
- _ userContentController: WKUserContentController,
203
- didReceive message: WKScriptMessage
204
- ) {
205
- let command = CommandManager.Instance.decode(jsonData: message.body as! String)
206
- if let wv = webViewRef {
207
- CommandManager.Instance.doCommand(target: wv, jsb: command)
208
- }
209
- }
210
-
211
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
212
- webViewRef?.scrollOffset = scrollView.contentOffset
213
- if webViewRef != nil {
214
- let wg = SpatialWindowContainer.getSpatialWindowContainer(webViewRef!.parentWindowContainerID)!
215
- wg.updateFrame = !(wg.updateFrame)
216
- }
217
- }
218
- }
219
-
220
- struct WebViewNative: UIViewRepresentable {
221
- weak var webViewRef: SpatialWindowComponent? = nil
222
- var url: URL = .init(filePath: "/")
223
- var webViewHolder = WebViewHolder()
224
-
225
- func destroy() {
226
- // Remove references to Coordinator so that it gets cleaned up by arc
227
- webViewHolder.appleWebView?.configuration.userContentController.removeScriptMessageHandler(forName: "bridge")
228
- webViewHolder.appleWebView?.uiDelegate = nil
229
- webViewHolder.appleWebView?.navigationDelegate = nil
230
- webViewHolder.appleWebView?.scrollView.delegate = nil
231
- webViewHolder.appleWebView = nil
232
- }
233
-
234
- func makeCoordinator() -> Coordinator {
235
- let c = Coordinator()
236
- c.webViewRef = webViewRef
237
- return c
238
- }
239
-
240
- func createResources(configuration: WKWebViewConfiguration? = nil) -> WKWebView {
241
- if webViewHolder.appleWebView == nil {
242
- webViewHolder.webViewCoordinator = makeCoordinator()
243
- let userContentController = WKUserContentController()
244
-
245
- let userScript = WKUserScript(source: "window.WebSpatailEnabled = true; window.WebSpatailNativeVersion = '" + nativeAPIVersion + "';", injectionTime: .atDocumentStart, forMainFrameOnly: false)
246
- userContentController.addUserScript(userScript)
247
- userContentController.add(webViewHolder.webViewCoordinator!, name: "bridge")
248
-
249
- let myConfig = (configuration != nil) ? configuration! : WKWebViewConfiguration()
250
- myConfig.userContentController = userContentController
251
- myConfig.preferences.javaScriptCanOpenWindowsAutomatically = true
252
- myConfig.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
253
-
254
- if myConfig.urlSchemeHandler(forURLScheme: "forceStyle") == nil {
255
- myConfig.setURLSchemeHandler(webViewHolder.webViewCoordinator, forURLScheme: "forceStyle")
256
- }
257
- if myConfig.urlSchemeHandler(forURLScheme: "file") == nil {
258
- myConfig.setURLSchemeHandler(webViewHolder.webViewCoordinator, forURLScheme: "file")
259
- }
260
- webViewHolder.appleWebView = WKWebView(frame: .zero, configuration: myConfig)
261
- webViewHolder.appleWebView!.uiDelegate = webViewHolder.webViewCoordinator
262
- webViewHolder.appleWebView!.allowsBackForwardNavigationGestures = true
263
- webViewHolder.appleWebView!.isInspectable = true
264
- webViewHolder.appleWebView!.allowsLinkPreview = true
265
- webViewHolder.appleWebView!.navigationDelegate = webViewHolder.webViewCoordinator
266
- webViewHolder.appleWebView!.scrollView.delegate = webViewHolder.webViewCoordinator
267
- webViewHolder.needsUpdate = (configuration != nil) ? false : true
268
- }
269
-
270
- return webViewHolder.appleWebView!
271
- }
272
-
273
- func initialLoad() {
274
- if webViewHolder.needsUpdate {
275
- let request = URLRequest(url: url)
276
- webViewHolder.appleWebView!.load(request)
277
- webViewHolder.needsUpdate = false
278
- }
279
- }
280
-
281
- func makeUIView(context: Context) -> WKWebView {
282
- return createResources()
283
- }
284
-
285
- func updateUIView(_ webView: WKWebView, context: Context) {
286
- initialLoad()
287
- }
288
- }
289
-
290
- // extend webview to support file://
291
- @available(iOS 11.0, *)
292
- extension WKWebView {
293
- /// WKWebView, Support setting file scheme in configuration
294
- public private(set) static var isEnableFileSupport = false
295
- public static func enableFileScheme() {
296
- /// This method supports adapting supported files through Configuration, but cannot be cancelled (Configuration is immutable).
297
- if !isEnableFileSupport {
298
- switchHandlesURLScheme()
299
- }
300
- }
301
-
302
- private static func switchHandlesURLScheme() {
303
- if
304
- case let cls = WKWebView.self,
305
- let m1 = class_getClassMethod(cls, NSSelectorFromString("handlesURLScheme:")),
306
- let m2 = class_getClassMethod(cls, #selector(WKWebView.wrapHandles(urlScheme:)))
307
- {
308
- method_exchangeImplementations(m1, m2)
309
- isEnableFileSupport = !isEnableFileSupport
310
- }
311
- }
312
-
313
- /// Return true if WKWebview supports handling this protocol, but WKWebview supports HTTP by default, so return false to support using custom HTTP Handler
314
- @objc private dynamic
315
- static func wrapHandles(urlScheme: String) -> Bool {
316
- if urlScheme == "file" { return false }
317
- return wrapHandles(urlScheme: urlScheme)
318
- }
319
- }