@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.
- package/dist/index.js +1 -1
- package/dist/lib/Cli.js +1 -1
- package/dist/lib/cmds/build.d.ts +1 -1
- package/dist/lib/cmds/build.js +1 -1
- package/dist/lib/cmds/check.js +1 -1
- package/dist/lib/cmds/help.js +1 -1
- package/dist/lib/cmds/version.js +1 -1
- package/dist/lib/pwa/config.js +1 -1
- package/dist/lib/pwa/index.js +1 -1
- package/dist/lib/pwa/validate.js +1 -1
- package/dist/lib/resource/file.js +1 -1
- package/dist/lib/resource/imageHelper.js +1 -1
- package/dist/lib/resource/index.d.ts +10 -3
- package/dist/lib/resource/index.js +1 -1
- package/dist/lib/resource/load.js +1 -1
- package/dist/lib/utils/CustomError.js +1 -1
- package/dist/lib/utils/FetchUtils-1.js +1 -1
- package/dist/lib/utils/Log.js +1 -1
- package/dist/lib/utils/fetch.js +1 -1
- package/dist/lib/utils/messages.js +1 -1
- package/dist/lib/utils/utils.d.ts +9 -0
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/xcode/index.js +1 -1
- package/dist/lib/xcode/manifestSwiftTemplate.d.ts +1 -1
- package/dist/lib/xcode/manifestSwiftTemplate.js +1 -1
- package/dist/lib/xcode/xcodebuild.js +1 -1
- package/dist/lib/xcode/xcodeproject.js +1 -1
- package/dist/lib/xcode/xcrun.js +1 -1
- package/package.json +3 -2
- package/template/visionOSApp/Packages/RealityKitContent/.build/workspace-state.json +0 -7
- package/template/visionOSApp/Packages/RealityKitContent/.swiftpm/xcode/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/ProjectData/main.json +0 -11
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/SceneMetadataList.json +0 -112
- package/template/visionOSApp/Packages/RealityKitContent/Package.realitycomposerpro/WorkspaceData/Settings.rcprojectdata +0 -17
- package/template/visionOSApp/Packages/RealityKitContent/Package.swift +0 -27
- package/template/visionOSApp/Packages/RealityKitContent/README.md +0 -3
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Immersive.usda +0 -50
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Materials/GridMaterial.usda +0 -216
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.rkassets/Scene.usda +0 -59
- package/template/visionOSApp/Packages/RealityKitContent/Sources/RealityKitContent/RealityKitContent.swift +0 -4
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Contents.json +0 -17
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json +0 -12
- package/template/visionOSApp/web-spatial/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Assets.xcassets/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/Info.plist +0 -33
- package/template/visionOSApp/web-spatial/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
- package/template/visionOSApp/web-spatial/libs/EventEmitter.swift +0 -32
- package/template/visionOSApp/web-spatial/libs/SpatialComponent.swift +0 -31
- package/template/visionOSApp/web-spatial/libs/SpatialEntity.swift +0 -179
- package/template/visionOSApp/web-spatial/libs/SpatialInputComponent.swift +0 -26
- package/template/visionOSApp/web-spatial/libs/SpatialMeshResource.swift +0 -19
- package/template/visionOSApp/web-spatial/libs/SpatialModel3DComponent.swift +0 -51
- package/template/visionOSApp/web-spatial/libs/SpatialModelComponent.swift +0 -32
- package/template/visionOSApp/web-spatial/libs/SpatialObject.swift +0 -144
- package/template/visionOSApp/web-spatial/libs/SpatialPhysicallyBasedMaterial.swift +0 -19
- package/template/visionOSApp/web-spatial/libs/SpatialViewComponent.swift +0 -15
- package/template/visionOSApp/web-spatial/libs/SpatialWindowComponent.swift +0 -420
- package/template/visionOSApp/web-spatial/libs/SpatialWindowContainer.swift +0 -149
- package/template/visionOSApp/web-spatial/libs/Utils/CommandManager.swift +0 -800
- package/template/visionOSApp/web-spatial/libs/Utils/Logger.swift +0 -36
- package/template/visionOSApp/web-spatial/libs/Utils/SceneManager.swift +0 -108
- package/template/visionOSApp/web-spatial/libs/Utils/WindowContainerMgr.swift +0 -113
- package/template/visionOSApp/web-spatial/libs/json/JsonParser.swift +0 -52
- package/template/visionOSApp/web-spatial/libs/uiKitDelegate/Window.swift +0 -34
- package/template/visionOSApp/web-spatial/libs/webView/UpdateSystem.swift +0 -33
- package/template/visionOSApp/web-spatial/libs/webView/backend/NativeWebView.swift +0 -319
- package/template/visionOSApp/web-spatial/libs/webView/manifest.swift +0 -92
- package/template/visionOSApp/web-spatial/static-web/index.html +0 -9
- package/template/visionOSApp/web-spatial/views/HideViewModifier.swift +0 -17
- package/template/visionOSApp/web-spatial/views/ImmersiveView.swift +0 -24
- package/template/visionOSApp/web-spatial/views/LoadingView.swift +0 -25
- package/template/visionOSApp/web-spatial/views/MaterialWithBorderCornerModifier.swift +0 -82
- package/template/visionOSApp/web-spatial/views/OpenDismissHandlerUI.swift +0 -52
- package/template/visionOSApp/web-spatial/views/PlainWindowContainerView.swift +0 -84
- package/template/visionOSApp/web-spatial/views/SpatialModel3DView.swift +0 -193
- package/template/visionOSApp/web-spatial/views/SpatialViewUI.swift +0 -168
- package/template/visionOSApp/web-spatial/views/SpatialWebViewUI.swift +0 -186
- package/template/visionOSApp/web-spatial/views/VolumetricWindowContainerView.swift +0 -38
- package/template/visionOSApp/web-spatial/views/ui/NavView.swift +0 -125
- package/template/visionOSApp/web-spatial/web_spatialApp.swift +0 -158
- package/template/visionOSApp/web-spatial.xcodeproj/project.pbxproj +0 -686
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +0 -5
- package/template/visionOSApp/web-spatial.xcodeproj/project.xcworkspace/xcuserdata/bytedance.xcuserdatad/WorkspaceSettings.xcsettings +0 -14
- package/template/visionOSApp/web-spatial.xcodeproj/xcshareddata/xcschemes/web-spatial.xcscheme +0 -115
- package/template/visionOSApp/web-spatial.xcodeproj/xcuserdata/bytedance.xcuserdatad/xcschemes/xcschememanagement.plist +0 -27
- 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
|
-
}
|