Closed QuantumEntangledAndy closed 1 year ago
The following diff should get it to work
--- ../mobile_cmp/src/lib.rs 2023-05-30 16:09:01.000000000 +0700
+++ src/lib.rs 2023-06-01 16:48:39.000000000 +0700
@@ -1,6 +1,7 @@
#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;
+use anyhow::Result;
use winit::event::Event::*;
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget};
@@ -139,25 +140,34 @@
});
}
-#[allow(dead_code)]
-#[cfg(target_os = "android")]
-#[no_mangle]
-fn android_main(app: AndroidApp) {
- use winit::platform::android::EventLoopBuilderExtAndroid;
+#[cfg(any(target_os = "android", target_os = "ios"))]
+fn stop_unwind<F: FnOnce() -> T, T>(f: F) -> T {
+ match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
+ Ok(t) => t,
+ Err(err) => {
+ eprintln!("attempt to unwind out of `rust` with err: {:?}", err);
+ std::process::abort()
+ }
+ }
+}
- android_logger::init_once(
- android_logger::Config::default().with_max_level(log::LevelFilter::Warn),
- );
+#[cfg(any(target_os = "android", target_os = "ios"))]
+fn _start_app() {
+ stop_unwind(|| main().unwrap());
+}
- let event_loop = EventLoopBuilder::with_user_event()
- .with_android_app(app)
- .build();
- _main(event_loop);
+#[no_mangle]
+#[inline(never)]
+#[cfg(any(target_os = "android", target_os = "ios"))]
+pub extern "C" fn start_app() {
+ #[cfg(target_os = "android")]
+ android_binding!({{reverse-domain-snake-case app.domain}}, {{snake-case app.name}}, _start_app);
+ #[cfg(target_os = "ios")]
+ _start_app()
}
-#[allow(dead_code)]
#[cfg(not(target_os = "android"))]
-fn main() {
+pub fn main() -> Result<()> {
env_logger::builder()
.filter_level(log::LevelFilter::Warn)
.parse_default_env()
@@ -165,4 +175,22 @@
let event_loop = EventLoopBuilder::with_user_event().build();
_main(event_loop);
+
+ Ok(())
+}
+
+#[cfg(target_os = "android")]
+pub fn main() -> Result<()> {
+ use winit::platform::android::EventLoopBuilderExtAndroid;
+
+ android_logger::init_once(
+ android_logger::Config::default().with_max_level(log::LevelFilter::Warn),
+ );
+
+ let event_loop = EventLoopBuilder::with_user_event()
+ .with_android_app(app)
+ .build();
+ _main(event_loop);
+
+ Ok(())
}
Changes were adding the pub
on main
and also adding start_app
and safe_unwind
parts. I also did the android_main
as a main
cfg varient but can't test that.
Not adding pub
to the desktop main function is a stupid mistake on my part lol. It should definitely be there.
But your diff doesn't work on android because app
is not found in the scope. We need to have a special android_main
for android otherwise winit's android-activity won't bind to it correctly.
May I suggest this for lib.rs?
#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;
use winit::event::Event::*;
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget};
use egui_wgpu::winit::Painter;
use egui_winit::State;
const INITIAL_WIDTH: u32 = 1920;
const INITIAL_HEIGHT: u32 = 1080;
/// A custom event type for the winit app.
enum Event {
RequestRedraw,
}
/// Enable egui to request redraws via a custom Winit event...
#[derive(Clone)]
struct RepaintSignal(std::sync::Arc<std::sync::Mutex<winit::event_loop::EventLoopProxy<Event>>>);
fn create_window<T>(
event_loop: &EventLoopWindowTarget<T>,
state: &mut State,
painter: &mut Painter,
) -> winit::window::Window {
let window = winit::window::WindowBuilder::new()
.with_decorations(true)
.with_resizable(true)
.with_transparent(false)
.with_title("egui winit + wgpu example")
.with_inner_size(winit::dpi::PhysicalSize {
width: INITIAL_WIDTH,
height: INITIAL_HEIGHT,
})
.build(event_loop)
.unwrap();
pollster::block_on(painter.set_window(Some(&window))).unwrap();
// NB: calling set_window will lazily initialize render state which
// means we will be able to query the maximum supported texture
// dimensions
if let Some(max_size) = painter.max_texture_side() {
state.set_max_texture_side(max_size);
}
let pixels_per_point = window.scale_factor() as f32;
state.set_pixels_per_point(pixels_per_point);
window.request_redraw();
window
}
fn _main(event_loop: EventLoop<Event>) {
let ctx = egui::Context::default();
let repaint_signal = RepaintSignal(std::sync::Arc::new(std::sync::Mutex::new(
event_loop.create_proxy(),
)));
ctx.set_request_repaint_callback(move |_| {
repaint_signal
.0
.lock()
.unwrap()
.send_event(Event::RequestRedraw)
.ok();
});
let mut state = State::new(&event_loop);
let mut painter = Painter::new(
egui_wgpu::WgpuConfiguration::default(),
1, // msaa samples
None,
false,
);
let mut window: Option<winit::window::Window> = None;
let mut egui_demo_windows = egui_demo_lib::DemoWindows::default();
event_loop.run(move |event, event_loop, control_flow| match event {
Resumed => match window {
None => {
window = Some(create_window(event_loop, &mut state, &mut painter));
}
Some(ref window) => {
pollster::block_on(painter.set_window(Some(window))).unwrap();
window.request_redraw();
}
},
Suspended => {
window = None;
}
RedrawRequested(..) => {
if let Some(window) = window.as_ref() {
let raw_input = state.take_egui_input(window);
let full_output = ctx.run(raw_input, |ctx| {
egui_demo_windows.ui(ctx);
});
state.handle_platform_output(window, &ctx, full_output.platform_output);
painter.paint_and_update_textures(
state.pixels_per_point(),
egui::Rgba::default().to_array(),
&ctx.tessellate(full_output.shapes),
&full_output.textures_delta,
false,
);
if full_output.repaint_after.is_zero() {
window.request_redraw();
}
}
}
MainEventsCleared | UserEvent(Event::RequestRedraw) => {
if let Some(window) = window.as_ref() {
window.request_redraw();
}
}
WindowEvent { event, .. } => {
match event {
winit::event::WindowEvent::Resized(size) => {
painter.on_window_resized(size.width, size.height);
}
winit::event::WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
let response = state.on_event(&ctx, &event);
if response.repaint {
if let Some(window) = window.as_ref() {
window.request_redraw();
}
}
}
_ => (),
});
}
#[cfg(any(target_os = "ios", target_os = "android"))]
fn stop_unwind<F: FnOnce() -> T, T>(f: F) -> T {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
Ok(t) => t,
Err(err) => {
eprintln!("attempt to unwind out of `rust` with err: {:?}", err);
std::process::abort()
}
}
}
#[cfg(target_os = "ios")]
fn _start_app() {
stop_unwind(|| main().unwrap());
}
#[no_mangle]
#[inline(never)]
#[cfg(target_os = "ios")]
pub extern "C" fn start_app() {
_start_app();
}
#[cfg(not(target_os = "android"))]
pub fn main() -> Result<()> {
env_logger::builder()
.filter_level(log::LevelFilter::Warn)
.parse_default_env()
.init();
let event_loop = EventLoopBuilder::with_user_event().build();
_main(event_loop);
Ok(())
}
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
use winit::platform::android::EventLoopBuilderExtAndroid;
android_logger::init_once(
android_logger::Config::default().with_max_level(log::LevelFilter::Warn),
);
let event_loop = EventLoopBuilder::with_user_event()
.with_android_app(app)
.build();
stop_unwind(|| _main(event_loop));
}
Works on linux and android, but I can't test it on iOS or mac
Works on mac, just having trouble connecting ios at the moment. I think perhaps the 1s timeout is too short on ios-deploy, is there anyway to configure that?
Also you will need to remove -> Result<()>
from main
the Ok(())
too aswell as the .unwrap
in the stop_unwind
call
Also have you considered adding some checks on the github runners for macos at least? Could probably do ios too with some setup
Here's the final one that works with me. (macos and ios)
#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;
use winit::event::Event::*;
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget};
use egui_wgpu::winit::Painter;
use egui_winit::State;
const INITIAL_WIDTH: u32 = 1920;
const INITIAL_HEIGHT: u32 = 1080;
/// A custom event type for the winit app.
enum Event {
RequestRedraw,
}
/// Enable egui to request redraws via a custom Winit event...
#[derive(Clone)]
struct RepaintSignal(std::sync::Arc<std::sync::Mutex<winit::event_loop::EventLoopProxy<Event>>>);
fn create_window<T>(
event_loop: &EventLoopWindowTarget<T>,
state: &mut State,
painter: &mut Painter,
) -> winit::window::Window {
let window = winit::window::WindowBuilder::new()
.with_decorations(true)
.with_resizable(true)
.with_transparent(false)
.with_title("egui winit + wgpu example")
.with_inner_size(winit::dpi::PhysicalSize {
width: INITIAL_WIDTH,
height: INITIAL_HEIGHT,
})
.build(event_loop)
.unwrap();
pollster::block_on(painter.set_window(Some(&window))).unwrap();
// NB: calling set_window will lazily initialize render state which
// means we will be able to query the maximum supported texture
// dimensions
if let Some(max_size) = painter.max_texture_side() {
state.set_max_texture_side(max_size);
}
let pixels_per_point = window.scale_factor() as f32;
state.set_pixels_per_point(pixels_per_point);
window.request_redraw();
window
}
fn _main(event_loop: EventLoop<Event>) {
let ctx = egui::Context::default();
let repaint_signal = RepaintSignal(std::sync::Arc::new(std::sync::Mutex::new(
event_loop.create_proxy(),
)));
ctx.set_request_repaint_callback(move |_| {
repaint_signal
.0
.lock()
.unwrap()
.send_event(Event::RequestRedraw)
.ok();
});
let mut state = State::new(&event_loop);
let mut painter = Painter::new(
egui_wgpu::WgpuConfiguration::default(),
1, // msaa samples
None,
false,
);
let mut window: Option<winit::window::Window> = None;
let mut egui_demo_windows = egui_demo_lib::DemoWindows::default();
event_loop.run(move |event, event_loop, control_flow| match event {
Resumed => match window {
None => {
window = Some(create_window(event_loop, &mut state, &mut painter));
}
Some(ref window) => {
pollster::block_on(painter.set_window(Some(window))).unwrap();
window.request_redraw();
}
},
Suspended => {
window = None;
}
RedrawRequested(..) => {
if let Some(window) = window.as_ref() {
let raw_input = state.take_egui_input(window);
let full_output = ctx.run(raw_input, |ctx| {
egui_demo_windows.ui(ctx);
});
state.handle_platform_output(window, &ctx, full_output.platform_output);
painter.paint_and_update_textures(
state.pixels_per_point(),
egui::Rgba::default().to_array(),
&ctx.tessellate(full_output.shapes),
&full_output.textures_delta,
false,
);
if full_output.repaint_after.is_zero() {
window.request_redraw();
}
}
}
MainEventsCleared | UserEvent(Event::RequestRedraw) => {
if let Some(window) = window.as_ref() {
window.request_redraw();
}
}
WindowEvent { event, .. } => {
match event {
winit::event::WindowEvent::Resized(size) => {
painter.on_window_resized(size.width, size.height);
}
winit::event::WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
let response = state.on_event(&ctx, &event);
if response.repaint {
if let Some(window) = window.as_ref() {
window.request_redraw();
}
}
}
_ => (),
});
}
#[cfg(any(target_os = "ios", target_os = "android"))]
fn stop_unwind<F: FnOnce() -> T, T>(f: F) -> T {
match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) {
Ok(t) => t,
Err(err) => {
eprintln!("attempt to unwind out of `rust` with err: {:?}", err);
std::process::abort()
}
}
}
#[cfg(target_os = "ios")]
fn _start_app() {
stop_unwind(|| main());
}
#[no_mangle]
#[inline(never)]
#[cfg(target_os = "ios")]
pub extern "C" fn start_app() {
_start_app();
}
#[cfg(not(target_os = "android"))]
pub fn main() {
env_logger::builder()
.filter_level(log::LevelFilter::Warn)
.parse_default_env()
.init();
let event_loop = EventLoopBuilder::with_user_event().build();
_main(event_loop);
}
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(app: AndroidApp) {
use winit::platform::android::EventLoopBuilderExtAndroid;
android_logger::init_once(
android_logger::Config::default().with_max_level(log::LevelFilter::Warn),
);
let event_loop = EventLoopBuilder::with_user_event()
.with_android_app(app)
.build();
stop_unwind(|| _main(event_loop));
}
I can confirm that your version works great on Linux and Android! Nice :)
If you'd like you can can set up the PR to merge there changes into the dev
branch, but I can also have it set up later.
Also have you considered adding some checks on the github runners for macos at least? Could probably do ios too with some setup
There actually is a runner for macOS, but it's only for unit tests and right now these tests don't check the templates at all afaik.
Might be easier if you just add it in. It's a small change for a PR
If you need any other ios/mac tests drop me a message and I will see if I can accomadate
Describe the bug Equi example fails on all devices I have access to. Macos and ios.
Macos fails with
and ios with
The first error is easy to fix with the addition of a pub but the latter needed more work
Steps To Reproduce Create a equi tempalte and try to run or archive it with apple
Expected behavior No errors
Platform and Versions (please complete the following information): Host OS: Macos Target OS: Macos and ios Rustc: rustc 1.69.0 (84c898d65 2023-04-16)
cargo mobile doctor
:[✔] cargo-mobile v0.5.0 • Contains commits up to "Add egui example (#164)\n" • Installed at "~/.cargo/.tauri-mobile" • macOS v12.5 (21G72) • rustc v1.69.0 (84c898d65 2023-4-16)
[✔] Apple developer tools • Xcode v14.2 • Active developer dir: "/Applications/Xcode.app/Contents/Developer" • ios-deploy v1.12.2 • XcodeGen v2.35.0 ✗ xcode-rust-plugin plugin absent ✗ xcode-rust-plugin lang spec absent ✗ xcode-rust-plugin lang metadata absent • xcode-rust-plugin is up-to-date ✗ xcode-rust-plugin doesn't support Xcode UUID "C91F3560-00E7-4749-8E3F-4D83B1496051" • Development team: Andrew King (N7VJA8E4L8)
[!] Android developer tools ✗ Have you installed the Android SDK? The
ANDROID_HOME
environment variable isn't set, and is required: environment variable not found[!] Connected devices ✗ Failed to get iOS device list: Failed to request device list from
ios-deploy
: command ["ios-deploy", "--detect", "--timeout", "1", "--json", "--no-wifi"] exited with code 253Would you want to assign yourself to resolve this bug?
Additional context See comments on #164 too