@@ -7,7 +7,15 @@ use crate::{Browser, BrowserOptions, Error, ErrorKind, Result, TargetType};
77
88/// Returns `UIApplication`
99#[ allow( non_snake_case) ]
10- fn sharedApplication ( _mtm : MainThreadMarker ) -> Retained < NSObject > {
10+ fn sharedApplication ( mtm : MainThreadMarker ) -> Option < Retained < NSObject > > {
11+ let _ = mtm;
12+ // SAFETY: The signature is correct, and we hold `MainThreadMarker`, so we
13+ // know we're on the main thread where it's safe to access the shared
14+ // UIApplication.
15+ //
16+ // NOTE: `sharedApplication` is declared as returning non-NULL, but it
17+ // will only do so inside `UIApplicationMain`; if called outside, the
18+ // shared application is NULL.
1119 unsafe { msg_send ! [ class!( UIApplication ) , sharedApplication] }
1220}
1321
@@ -37,6 +45,13 @@ pub(super) fn open_browser_internal(
3745 // ensure we're opening only http/https urls, failing otherwise
3846 let url = target. get_http_url ( ) ?;
3947
48+ let mtm = MainThreadMarker :: new ( ) . ok_or_else ( || {
49+ Error :: new (
50+ ErrorKind :: Other ,
51+ "Cannot open URL from a thread that is not the main thread" ,
52+ )
53+ } ) ?;
54+
4055 // always return true for a dry run
4156 if options. dry_run {
4257 return Ok ( ( ) ) ;
@@ -46,7 +61,11 @@ pub(super) fn open_browser_internal(
4661 ErrorKind :: Other ,
4762 "UIApplication must be retrieved on the main thread" ,
4863 ) ) ?;
49- let app = sharedApplication ( mtm) ;
64+
65+ let app = sharedApplication ( mtm) . ok_or ( Error :: new (
66+ ErrorKind :: Other ,
67+ "UIApplication is NULL, perhaps UIApplicationMain has not been executed?" ,
68+ ) ) ?;
5069
5170 // Create ns string class from our string
5271 let url_string = NSString :: from_str ( url) ;
0 commit comments