-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathReactNative.swift
More file actions
170 lines (139 loc) · 5.8 KB
/
Copy pathReactNative.swift
File metadata and controls
170 lines (139 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import UIKit
import React
public protocol ReactNativeDelegateInternal: AnyObject {
func onAppClosed()
}
@objcMembers
open class ReactNative: NSObject, RCTReloadListener {
// MARK: - Properties
private var mendixApp: MendixApp?
private var bundleUrl: URL?
private var mendixOTAEnabled: Bool = false
private var tapGestureHelper: TapGestureRecognizerHelper?
public weak var delegate: ReactNativeDelegateInternal?
// MARK: - Singleton
public static let shared = ReactNative()
private override init() {
super.init()
}
// MARK: - Setup Methods
public func setup(_ mendixApp: MendixApp, launchOptions: [AnyHashable: Any]? = nil, mendixOTAEnabled: Bool = false) {
self.mendixApp = mendixApp
self.bundleUrl = mendixApp.bundleUrl
self.mendixOTAEnabled = mendixOTAEnabled
if let host = bundleUrl?.host, let port = bundleUrl?.port {
let jsLocation = "\(host):\(port)"
RCTBundleURLProvider.sharedSettings().jsLocation = jsLocation
}
}
// MARK: - Lifecycle Methods
public func start() {
guard let mendixApp = self.mendixApp else {
fatalError("MendixApp not passed before starting the app")
}
MxConfiguration.update(from: mendixApp)
if mendixApp.clearDataAtLaunch {
StorageHelper.clearAll()
}
ReactAppProvider.shared()?.setReactViewController(mendixApp.reactLoading?.instantiateInitialViewController() ?? UIViewController())
DevHelper.setShakeToShowDevMenuEnabled(enabled: AppPreferences.devModeEnabled)
DevHelper.setDebugMode(enabled: AppPreferences.devModeEnabled && AppPreferences.remoteDebuggingEnabled)
showSplashScreen()
if mendixApp.isDeveloperApp || mendixApp.enableThreeFingerGestures {
DispatchQueue.main.async {
RCTRegisterReloadCommandListener(self)
}
}
}
public func stop() {
hideSplashScreen()
delegate?.onAppClosed()
delegate = nil
}
// MARK: - Splash Screen Methods
public func showSplashScreen() {
if MendixBackwardsCompatUtility.isHideSplashScreenInClientSupported() {
mendixApp?.splashScreenPresenter?.show(ReactAppProvider.shared()?.rootView)
}
}
public func hideSplashScreen() {
mendixApp?.splashScreenPresenter?.hide()
DevHelper.hideDevLoadingView()
}
// MARK: - Reload Methods
public func reload() {
guard let mendixApp = mendixApp else { return }
// Note: under the New Architecture the bundle URL is resolved fresh in bundleURL(),
// which RCTHost re-invokes on reload. RCTReloadCommandSetBundleURL is a legacy-bridge
// mechanism that the bridgeless host ignores, so it is intentionally not used here.
if mendixApp.isDeveloperApp {
let runtimeInfoUrl = AppUrl.forRuntimeInfo(mendixApp.runtimeUrl.absoluteString)
RuntimeInfoProvider.getRuntimeInfo(runtimeInfoUrl) { [weak self] response in
if response.status == "SUCCESS", let version = response.runtimeInfo?.version {
MendixBackwardsCompatUtility.update(version)
}
self?.reloadWithBridge()
}
} else {
reloadWithBridge()
}
}
private func reloadWithBridge() {
RCTTriggerReloadCommandListeners("Reload command from app")
}
public func reloadWithState() {
ReactHostHelper().reloadClientWithState()
}
// MARK: - RCTReloadListener
@objc public func didReceiveReloadCommand() {
showSplashScreen()
}
// MARK: - Debugging Methods
public func remoteDebugging(_ enable: Bool) {
showSplashScreen()
bundleUrl = AppUrl.forBundle(
AppPreferences.safeAppUrl,
port: AppPreferences.remoteDebuggingPackagerPort,
isDebuggingRemotely: enable,
isDevModeEnabled: true
)
DevHelper.setDebugMode(enabled: enable)
}
public func setRemoteDebuggingPackagerPort(_ port: Int) {
AppPreferences.remoteDebuggingPackagerPort = port
remoteDebugging(true)
}
// MARK: - Gesture Recognition
private func attachThreeFingerGestures(to window: UIWindow) {
tapGestureHelper?.attach()
}
private func removeThreeFingerGestures(from window: UIWindow) {
tapGestureHelper?.remove()
window.motionBegan(.motionShake, with: nil)
}
@objc private func appReloadAction(_ gestureRecognizer: UITapGestureRecognizer) {
if gestureRecognizer.state == .ended && ReactAppProvider.isReactAppActive() == true {
reloadWithState()
}
}
// MARK: - Legacy Methods (for compatibility)
func useCodePush() -> Bool {
// Implementation depends on your specific CodePush setup
return false
}
public func bundleURL() -> URL? {
// New Architecture (Bridgeless): RCTHost re-invokes this provider block on every
// reload (via RCTRootViewFactory's bundleURLBlock) instead of consulting the URL set
// by RCTReloadCommandSetBundleURL. Resolve the OTA bundle fresh here so a freshly
// deployed OTA bundle is picked up after reload. Without this, every reload re-loads
// the bundle captured at host-creation time and the app loops:
// download -> deploy -> reload -> same bundle.
//
// For the developer app (and remote debugging) the cached packager URL must be used,
// so only the production path re-resolves through BundleHelper.
if mendixApp?.isDeveloperApp == true {
return bundleUrl
}
return BundleHelper.getJSBundleFile()
}
}