Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
57f9d56
feat(android): prepare for multi-window support
lucasfernog Oct 22, 2025
a71c707
add android multiwindow apis
lucasfernog Oct 23, 2025
f12df40
activity_name getter, JS API, auto inherit from manager on builder::new
lucasfernog Oct 24, 2025
c389ba4
refactor(core): improve iOS log messages from stdout/stderr
lucasfernog Oct 28, 2025
9e0bbff
patch
lucasfernog Oct 28, 2025
067ef61
Merge branch 'dev' into feat/mobile-multi-window
lucasfernog Oct 28, 2025
6854f8b
Merge branch 'refactor/ios-stdout-stderr-log' into feat/mobile-multi-…
lucasfernog Oct 28, 2025
b5d874d
use context (created_by_activity_name) from caller on TS API
lucasfernog Oct 29, 2025
bcc25c0
add scene identifier getter and setter
lucasfernog Oct 29, 2025
e4ccc32
expose apis
lucasfernog Oct 29, 2025
9a360af
fix desktop build
lucasfernog Oct 29, 2025
c5dbb02
Merge remote-tracking branch 'origin/dev' into feat/mobile-multi-window
lucasfernog Oct 30, 2025
6b94116
fix window from config
lucasfernog Oct 30, 2025
a602008
update lock
lucasfernog Oct 30, 2025
eb51b13
size is now respected on iOS, so default to None
lucasfernog Oct 30, 2025
f5f9b3d
add SceneRequested event
lucasfernog Nov 6, 2025
220cc2a
Merge remote-tracking branch 'origin/dev' into feat/mobile-multi-window
lucasfernog Nov 12, 2025
6eb2dee
update features
lucasfernog Nov 12, 2025
bfc74a7
fix default size
lucasfernog Nov 12, 2025
e97e2e5
Revert "fix default size"
lucasfernog Nov 12, 2025
11fc78b
ignore size from config
lucasfernog Nov 12, 2025
e5f65a6
lint
lucasfernog Nov 12, 2025
1702b27
Merge remote-tracking branch 'origin/dev' into feat/mobile-multi-window
lucasfernog Nov 17, 2025
2172252
use git
lucasfernog Nov 17, 2025
7f953fc
change file
lucasfernog Nov 17, 2025
7f02cf5
add supports_multiple_windows API
lucasfernog Dec 2, 2025
12aaef6
add androidx.lifecycle:lifecycle-process
lucasfernog Dec 3, 2025
00dcedc
update wry
lucasfernog Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor(core): improve iOS log messages from stdout/stderr
move the stdout/stderr forward logic to Swift so it does not consume a Rust thread and never deadlocks on the simulator

I had to work on this because i'm facing #12172 again on latest Xcode (26.1)
  • Loading branch information
lucasfernog committed Oct 28, 2025
commit c389ba427fa4c3e2dbfe5c3061e14eedb8a12119
6 changes: 6 additions & 0 deletions .changes/refactor-ios-stdout-stderr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": path:bug
"tauri-macros": patch:bug
---

Fix iOS deadlock when running on the simulator from Xcode by properly piping stdout/stderr messages through the Xcode console and OSLog.
83 changes: 82 additions & 1 deletion crates/tauri/mobile/ios-api/Sources/Tauri/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,86 @@

import os.log
import UIKit
import Foundation

class StdoutRedirector {
private var originalStdout: Int32 = -1
private var originalStderr: Int32 = -1
private var stdoutPipe: [Int32] = [-1, -1]
private var stderrPipe: [Int32] = [-1, -1]
private var stdoutReadSource: DispatchSourceRead?
private var stderrReadSource: DispatchSourceRead?

func start() {
originalStdout = dup(STDOUT_FILENO)
originalStderr = dup(STDERR_FILENO)

guard Darwin.pipe(&stdoutPipe) == 0,
Darwin.pipe(&stderrPipe) == 0 else {
Logger.error("Failed to create stdout/stderr pipes")
return
}

dup2(stdoutPipe[1], STDOUT_FILENO)
dup2(stderrPipe[1], STDERR_FILENO)
close(stdoutPipe[1])
close(stderrPipe[1])

stdoutReadSource = createReader(
readPipe: stdoutPipe[0],
writeToOriginal: originalStdout,
label: "stdout"
)

stderrReadSource = createReader(
readPipe: stderrPipe[0],
writeToOriginal: originalStderr,
label: "stderr"
)
}

private func createReader(
readPipe: Int32,
writeToOriginal: Int32,
label: String
) -> DispatchSourceRead {
let source = DispatchSource.makeReadSource(
fileDescriptor: readPipe,
queue: .global(qos: .utility)
)

source.setEventHandler {
let bufferSize = 4096
var buffer = [UInt8](repeating: 0, count: bufferSize)
let bytesRead = read(readPipe, &buffer, bufferSize)

if bytesRead > 0 {
let output = String(
bytes: buffer[0..<bytesRead],
encoding: .utf8
) ?? ""

let trimmed = output.trimmingCharacters(in: .newlines)
if !trimmed.isEmpty {
// we're sending stderr to oslog, so we need to avoid recursive calls
if trimmed.hasPrefix("OSLOG-") {
// make sure the system can parse the oslogs
write(writeToOriginal, &buffer, bytesRead)
} else {
Logger.info("[\(label)] \(trimmed)")
}
}
}
}

source.setCancelHandler {
close(readPipe)
}

source.resume()
return source
}
}

/// Wrapper class for os_log function
public class Logger {
Expand All @@ -21,7 +101,7 @@ public class Logger {
}
}

static func log(_ items: Any..., category: String, type: OSLogType) {
static func log(_ items: [Any], category: String, type: OSLogType) {
if Logger.enabled {
var message = ""
let last = items.count - 1
Expand All @@ -31,6 +111,7 @@ public class Logger {
message += " "
}
}

let log = OSLog(subsystem: Bundle.main.bundleIdentifier ?? "-", category: category)
os_log("%{public}@", log: log, type: type, String(message.prefix(4068)))
}
Expand Down
8 changes: 8 additions & 0 deletions crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ extension PluginManager: NSCopying {
}
}

private var stdoutRedirector: StdoutRedirector?

@_cdecl("log_stdout")
func logStdout() {
stdoutRedirector = StdoutRedirector()
stdoutRedirector!.start()
}

@_cdecl("register_plugin")
func registerPlugin(name: SRString, plugin: NSObject, config: SRString, webview: WKWebView?) {
PluginManager.shared.load(
Expand Down
1 change: 1 addition & 0 deletions crates/tauri/src/ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ swift!(pub fn register_plugin(
webview: *const c_void
));
swift!(pub fn on_webview_created(webview: *const c_void, controller: *const c_void));
swift!(pub fn log_stdout());
32 changes: 2 additions & 30 deletions crates/tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,38 +248,10 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(target_os = "ios")]
#[doc(hidden)]
pub fn log_stdout() {
use std::{
ffi::CString,
fs::File,
io::{BufRead, BufReader},
os::unix::prelude::*,
thread,
};

let mut logpipe: [RawFd; 2] = Default::default();
#[cfg(target_os = "ios")]
unsafe {
libc::pipe(logpipe.as_mut_ptr());
libc::dup2(logpipe[1], libc::STDOUT_FILENO);
libc::dup2(logpipe[1], libc::STDERR_FILENO);
crate::ios::log_stdout();
}
thread::spawn(move || unsafe {
let file = File::from_raw_fd(logpipe[0]);
let mut reader = BufReader::new(file);
let mut buffer = String::new();
loop {
buffer.clear();
if let Ok(len) = reader.read_line(&mut buffer) {
if len == 0 {
break;
} else if let Ok(msg) = CString::new(buffer.as_bytes())
.map_err(|_| ())
.and_then(|c| c.into_string().map_err(|_| ()))
{
log::info!("{}", msg);
}
}
}
});
}

/// The user event type.
Expand Down
Loading