Last active
May 15, 2025 21:22
-
-
Save extrawurst/b5aab1550f08fdb6722749a9fde087bf to your computer and use it in GitHub Desktop.
swizzle_bevy_app_delegate_openURL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use bevy::prelude::*; | |
use objc2::{ | |
ClassType, MainThreadMarker, MainThreadOnly, define_class, msg_send, | |
rc::{Allocated, Retained}, | |
runtime::{AnyObject, Imp, NSObjectProtocol, ProtocolObject, Sel}, | |
sel, | |
}; | |
use objc2_foundation::{NSDictionary, NSURL}; | |
use objc2_ui_kit::{ | |
UIApplication, UIApplicationDelegate, UIApplicationOpenURLOptionsKey, UIResponder, | |
}; | |
use std::mem; | |
define_class!( | |
#[unsafe(super(UIResponder))] | |
#[thread_kind = MainThreadOnly] | |
struct AppDelegate; | |
unsafe impl NSObjectProtocol for AppDelegate {} | |
unsafe impl UIApplicationDelegate for AppDelegate { | |
#[allow(non_snake_case)] | |
#[unsafe(method(application:openURL:options:))] | |
unsafe fn application_openURL_options( | |
&self, | |
_app: &UIApplication, | |
url: &NSURL, | |
_options: &NSDictionary<UIApplicationOpenURLOptionsKey, AnyObject>, | |
) -> bool { | |
let url_string = unsafe { url.absoluteString().unwrap().to_string() }; | |
info!("url open: {url_string}"); | |
true | |
} | |
} | |
); | |
define_class!( | |
#[unsafe(super(UIApplication))] | |
#[name = "SpecialAppNameThatGoesInPlist"] | |
struct IosApp; | |
impl IosApp { | |
#[unsafe(method_id(init))] | |
fn init(this: Allocated<Self>) -> Retained<Self> { | |
let this = this.set_ivars(()); | |
let app: Retained<Self> = unsafe { objc2::msg_send![super(this), init] }; | |
install_global_app_delegate(&app); | |
app | |
} | |
} | |
); | |
fn install_global_app_delegate(app: &UIApplication) { | |
let mtm = MainThreadMarker::new() | |
.expect("install_global_app_delegate must be called on the main thread"); | |
let app_delegate = AppDelegate::new(mtm); | |
unsafe { | |
app.setDelegate(Some(ProtocolObject::from_ref(&*app_delegate))); | |
} | |
// We need the app delegate not to be deallocated. | |
// It will live for the lifetime of the application. | |
std::mem::forget(app_delegate); | |
debug!("AppDelegate registererd"); | |
} | |
impl AppDelegate { | |
fn new(mtm: MainThreadMarker) -> Retained<Self> { | |
unsafe { msg_send![super(mtm.alloc().set_ivars(())), init] } | |
} | |
} | |
/// Swizzle `-[UIApplication init]` to install our application delegate in there. | |
fn swizzle() { | |
type SetDelegate = extern "C-unwind" fn(*mut UIApplication, Sel) -> *mut UIApplication; | |
static mut ORIGINAL: Option<SetDelegate> = None; | |
extern "C-unwind" fn init(this: *mut UIApplication, sel: Sel) -> *mut UIApplication { | |
let original = unsafe { ORIGINAL.unwrap() }; | |
let this = original(this, sel); | |
let app = unsafe { &*this }; | |
install_global_app_delegate(&app); | |
this | |
} | |
let _mtm = MainThreadMarker::new().unwrap(); | |
let class = UIApplication::class(); | |
let method = class | |
.instance_method(sel!(init)) | |
.expect("UIApplication must have init method"); | |
let overridden = unsafe { mem::transmute::<SetDelegate, Imp>(init) }; | |
let original = unsafe { method.set_implementation(overridden) }; | |
let original = unsafe { mem::transmute::<Imp, SetDelegate>(original) }; | |
unsafe { ORIGINAL = Some(original) }; | |
} | |
pub fn plugin(_app: &mut App) { | |
swizzle(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment