diff --git a/apps/ios/CrossDeskMobile/ContentView.swift b/apps/ios/CrossDeskMobile/ContentView.swift index 420976b0..5318f15d 100644 --- a/apps/ios/CrossDeskMobile/ContentView.swift +++ b/apps/ios/CrossDeskMobile/ContentView.swift @@ -8,6 +8,18 @@ enum MobileLayout { } extension View { + // Keep change callbacks available on iOS 16 without using the deprecated + // overload on newer systems. Neither branch fires on initial appearance. + @ViewBuilder + func onValueChange(of value: Value, + perform action: @escaping (Value) -> Void) -> some View { + if #available(iOS 17.0, *) { + onChange(of: value) { _, newValue in action(newValue) } + } else { + onChange(of: value, perform: action) + } + } + func readableContentWidth() -> some View { frame(maxWidth: MobileLayout.readableMaximumWidth) .frame(maxWidth: .infinity) @@ -81,7 +93,7 @@ struct ContentView: View { session.applicationDidBecomeActive() } } - .onChange(of: scenePhase) { phase in + .onValueChange(of: scenePhase) { phase in if phase == .active { session.applicationDidBecomeActive() } else if phase == .background { @@ -304,7 +316,7 @@ private struct ConnectionHomeView: View { session.dismissDeviceOfflineAlert() } } - .onChange(of: session.remoteID) { value in + .onValueChange(of: session.remoteID) { value in let formatted = String(value.filter { $0.isNumber }.prefix(9)) if formatted != value { session.remoteID = formatted @@ -916,16 +928,16 @@ private struct ServerSettingsView: View { } .allowsHitTesting(false) } - .onChange(of: serverConfigurationExpanded) { expanded in + .onValueChange(of: serverConfigurationExpanded) { expanded in if !expanded { focusedServerField = nil validateAndApplyServerConfiguration() } } - .onChange(of: usesCustomServer) { isCustom in + .onValueChange(of: usesCustomServer) { isCustom in if !isCustom { useDefaultServer() } } - .onChange(of: focusedServerField) { field in + .onValueChange(of: focusedServerField) { field in if field == nil { validateAndApplyServerConfiguration() } } .onDisappear { diff --git a/apps/ios/CrossDeskMobile/RemoteSessionView.swift b/apps/ios/CrossDeskMobile/RemoteSessionView.swift index 55bc2a0f..49cfe838 100644 --- a/apps/ios/CrossDeskMobile/RemoteSessionView.swift +++ b/apps/ios/CrossDeskMobile/RemoteSessionView.swift @@ -197,7 +197,7 @@ struct RemoteSessionView: View { } message: { Text(session.remoteUpdateMessage ?? "") } - .onChange(of: session.privacyScreen.unlockNotice) { visible in + .onValueChange(of: session.privacyScreen.unlockNotice) { visible in if visible { mouseInput.releaseAll() keyboardInputVisible = false @@ -231,37 +231,37 @@ struct RemoteSessionView: View { statusMenuVisible = false statusOrbCenter = nil } - .onChange(of: session.selectedDisplay) { _ in + .onValueChange(of: session.selectedDisplay) { _ in systemKeyboardContext.remoteFocusWillChange() mouseInput.releaseAll() mouseInput.position(x: 0.5, y: 0.5) cursorPosition = nil viewport = RemoteViewportState() } - .onChange(of: session.mouseControlMode) { _ in + .onValueChange(of: session.mouseControlMode) { _ in mouseInput.releaseAll() cursorPosition = session.remoteCursorPosition if let point = cursorPosition { mouseInput.position(x: Float(point.x), y: Float(point.y)) } } - .onChange(of: scenePhase) { phase in + .onValueChange(of: scenePhase) { phase in if phase != .active { mouseInput.releaseAll() } if phase == .background { keyboardInputVisible = false } } - .onChange(of: keyboardInputVisible) { visible in + .onValueChange(of: keyboardInputVisible) { visible in if !visible { animateSystemKeyboardPresentation = true waitingForSystemKeyboard = false } } - .onChange(of: session.isConnected) { connected in + .onValueChange(of: session.isConnected) { connected in if !connected { mouseInput.releaseAll() keyboardInputVisible = false } } - .onChange(of: session.remoteCursorPositionRevision) { _ in + .onValueChange(of: session.remoteCursorPositionRevision) { _ in guard !mouseInput.hasVirtualButton, let position = session.remoteCursorPosition else { return } mouseInput.position(x: Float(position.x), y: Float(position.y)) cursorPosition = position @@ -481,7 +481,7 @@ struct RemoteSessionView: View { ) } .frame(width: containerSize.width, height: containerSize.height) - .onChange(of: containerSize) { _ in mouseInput.releaseAll() } + .onValueChange(of: containerSize) { _ in mouseInput.releaseAll() } } } @@ -1361,7 +1361,7 @@ private struct ScrollingCodecName: View { GeometryReader { text in Color.clear .onAppear { textWidth = text.size.width } - .onChange(of: text.size.width) { textWidth = $0; startedAt = Date() } + .onValueChange(of: text.size.width) { textWidth = $0; startedAt = Date() } } } .offset(x: offset(in: bounds.size.width, at: context.date)) @@ -1369,8 +1369,8 @@ private struct ScrollingCodecName: View { .clipped() } .onAppear { startedAt = Date() } - .onChange(of: value) { _ in startedAt = Date() } - .onChange(of: bounds.size.width) { _ in startedAt = Date() } + .onValueChange(of: value) { _ in startedAt = Date() } + .onValueChange(of: bounds.size.width) { _ in startedAt = Date() } } .frame(height: lineHeight) .accessibilityElement(children: .ignore) diff --git a/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift b/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift index f4306611..7bed2b75 100644 --- a/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift +++ b/apps/ios/CrossDeskMobile/ThirdPartyLicensesView.swift @@ -142,7 +142,7 @@ struct ThirdPartyLicensesView: View { .background(Color(.systemGroupedBackground).ignoresSafeArea()) .navigationTitle(NSLocalizedString("关于 CrossDesk", comment: "")) .navigationBarTitleDisplayMode(.inline) - .onChange(of: session.hasNetworkConsent) { allowed in + .onValueChange(of: session.hasNetworkConsent) { allowed in if allowed { appUpdates.checkNow() } } } diff --git a/apps/ios/scripts/build_minirtc_ios.sh b/apps/ios/scripts/build_minirtc_ios.sh index d3109903..de34a841 100755 --- a/apps/ios/scripts/build_minirtc_ios.sh +++ b/apps/ios/scripts/build_minirtc_ios.sh @@ -273,7 +273,9 @@ if [[ -f "${OUTPUT_LIBRARY}" ]] && cmp -s "${TEMP_MANIFEST}" "${MERGE_MANIFEST}" exit 0 fi -/usr/bin/libtool -static -o "${TEMP_LIBRARY}" \ +# Dependencies include empty objects for disabled or other-platform code. +# Suppress only that diagnostic; retain the members and other warnings. +/usr/bin/libtool -static -no_warning_for_no_symbols -o "${TEMP_LIBRARY}" \ "${MINIRTC_LIBRARY}" "${MERGE_ARCHIVES[@]}" \ "${WIRE_LIBRARY}" verify_no_openh264 "${TEMP_LIBRARY}" diff --git a/apps/ios/scripts/package_openssl_ios.py b/apps/ios/scripts/package_openssl_ios.py index 358ca340..e032f2f0 100644 --- a/apps/ios/scripts/package_openssl_ios.py +++ b/apps/ios/scripts/package_openssl_ios.py @@ -40,7 +40,9 @@ def package(inputs, output, platform="iphoneos"): output.parent.mkdir(parents=True, exist_ok=True) with tempfile.TemporaryDirectory(prefix="openssl-framework-", dir=output.parent) as temp: binary = Path(temp) / "OpenSSL" - subprocess.run(["/usr/bin/libtool", "-static", "-o", str(binary), + # OpenSSL includes empty objects for disabled or platform-specific code. + # Keep those members and all other libtool diagnostics intact. + subprocess.run(["/usr/bin/libtool", "-static", "-no_warning_for_no_symbols", "-o", str(binary), *(str(archives[name][0]) for name in sorted(archives))], check=True) subprocess.run(["xcrun", "lipo", str(binary), "-verify_arch", "arm64"], check=True) symbols = subprocess.check_output(["xcrun", "nm", "-u", str(binary)], text=True)