Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is the objc2-core-location package working (and is there an example for it?) #708

Closed
hackr-sh opened this issue Feb 3, 2025 · 10 comments
Closed
Labels
A-framework Affects the framework crates and the translator for them

Comments

@hackr-sh
Copy link

hackr-sh commented Feb 3, 2025

I'm using Tauri to build an app for macOS (plus other platforms later on) and it requires access to location data to populate the longitude and latitude so it can be sent to an API. I'm not too well-versed in rust just yet (though I've got my feet wet and I'm starting to learn how to float) so I'm not 100% sure if I'm even using the library correctly.

I found a bit of code on a thread in the Tauri discord channel and have modified it just slightly but basically I call request_location_permission at the start of my entryPoint into the app and it seems I can never get the CLLocationManager instance needed to ask for the location permissions.

Here's my code:

use objc2::rc::Retained;
use objc2_core_location::{CLAuthorizationStatus, CLLocationManager};
use std::ptr;
use std::sync::Once;

static mut LOCATION_MANAGER: *mut Retained<CLLocationManager> = ptr::null_mut();
static INIT: Once = Once::new();

#[tauri::command]
pub fn request_location_permission() {
    unsafe {
        println!("Requesting location permission");
        INIT.call_once(|| {
            LOCATION_MANAGER = Box::into_raw(Box::new(CLLocationManager::new()));
        });
        
        if !LOCATION_MANAGER.is_null() {
            let manager = &*LOCATION_MANAGER;
            let authorization_status = manager.authorizationStatus();
            log::debug!("authorization status: {:?}", authorization_status);

            if authorization_status == CLAuthorizationStatus::NotDetermined {
                manager.requestWhenInUseAuthorization();
            }
        }
    }
}

// Cleanup function to prevent memory leaks
#[tauri::command]
pub fn cleanup_location_manager() {
    unsafe {
        if !LOCATION_MANAGER.is_null() {
            drop(Box::from_raw(LOCATION_MANAGER));
            LOCATION_MANAGER = ptr::null_mut();
        }
    }
}

Any help would be greatly appreciated (and if I can provide some extra details, please, do let me know!)

@madsmtm madsmtm added the A-framework Affects the framework crates and the translator for them label Feb 3, 2025
@madsmtm
Copy link
Owner

madsmtm commented Feb 3, 2025

I have a suspicion that the problem is that you haven't configured your Info.plist as described in here. (Apple is notoriously bad at generating error messages when you forget to do so).

It also doesn't help that the usual website for finding information about Info.plist has been down, at least for a couple of days:
https://developer.apple.com/documentation/BundleResources/Information-Property-List

Looking quickly, it seems like Tauri has support for custom Info.plists? E.g. the file-associations example seems to have a custom Info.plist.

@hackr-sh
Copy link
Author

hackr-sh commented Feb 3, 2025

I had the Info.plist file populated but I was missing the "protocol-asset" feature flag (I was previously under the impression it would just work)

Populating my Info.plist as follows still does not prompt anything to happen nor does the app show up under Privacy & Security > Location Services:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">	
	<dict>
		<key>NSLocationWhenInUseUsageDescription</key>
		<string>App would like to request your location</string>
		<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
		<string>App would like to request your location</string>
		<key>NSLocationUsageDescription</key>
		<string>App would like to request your location</string>
	</dict>
</plist>

@hackr-sh
Copy link
Author

hackr-sh commented Feb 3, 2025

So it turns out we're getting further than we were before. Previously, LocationManager was always null but now it's actually populating.

let authorization_status = manager.authorizationStatus();

gives us a CLAuthorizationStatus::NotDetermined
and then subsequently requesting using either one of:

manager.requestWhenInUseAuthorization();
// or
manager.requestAlwaysAuthorization();

does nothing at all.
Requesting Location without gaining prior authorization crashes the app as expected.

@hackr-sh
Copy link
Author

hackr-sh commented Feb 3, 2025

Interestingly enough, building it for production does indeed correctly prompt the user to allow location access. I have a way forward for the time being but it does suck that I haven't been able to figure out how to enable it when running the tauri dev command.

@madsmtm
Copy link
Owner

madsmtm commented Feb 3, 2025

By "building it for production", do you mean building inside Xcode?

A vague guess, maybe you need to code-sign the bundle?

@hackr-sh
Copy link
Author

hackr-sh commented Feb 3, 2025

By building for production, I mean running bun tauri build, which runs a couple of things and also does a cargo build passing in various other parameters but also specifically one for --release

On macOS, this produces a .dmg image that contains the application (.app folder), which includes the Info.plist that we initially kept in the folder src-tauri

When running a dev build using bun tauri dev, we get no such .dmg or Application.app folder, and instead, we get a single packaged binary as a single file that's automatically executable (like rust would otherwise normally output)

@madsmtm
Copy link
Owner

madsmtm commented Feb 3, 2025

Ah, yeah, that won't work then, and there probably isn't a way around it, you have to bundle for macOS to see the Info.plist (I thought bun tauri dev also did the bundling). I'd suggest you file an issue with Tauri about this!

If you really want to get adventurous, I guess you could try to embed the Info.plist with embed_plist, but I haven't found it to work for my use-cases yet.

@hackr-sh
Copy link
Author

hackr-sh commented Feb 4, 2025

The docs make it look so simple! - I'll probably try it out tomorrow!

Since I had this working earlier today by the way - I haven't been able to get my app to re-authenticate - though it was working at one point and I'm certain it'll work again.

(It's just hard testing once you've bundled a production ready version of the app)

@FabianLars
Copy link

I'd suggest you file an issue with Tauri about this!

probably not worth it tbh. i doubt we'll fix this. we had this behavior years ago for a really short time but it caused more issues than it was worth (don't ask me what it was, that was before my time). We recently also switched back from cargo build to cargo run, also due to issues that are hard or impossible to fix, so that also rules it out i guess.

For the foreseeable future we'll stick to tauri build / tauri build --debug to test features that depend on Info.plist.

Maybe we can add this behavior alongside the current one that runs when an info.plist file is detected (with a flag if people need the cargo run behavior) but atm i just don't see it.

I haven't been able to get my app to re-authenticate - though it was working at one point and I'm certain it'll work again.

It wasn't with location services but something else i tested a looong time ago required me to use tccutil to completely reset my app's permissions before i could re-test it again.

@hackr-sh
Copy link
Author

hackr-sh commented Feb 8, 2025

probably not worth it tbh. i doubt we'll fix this.

That's honestly pretty fair - even just trying to get it working right now and just barely succeeding, I can see why. The kind of rewrite necessary to achieve something similar here is quite an undertaking.

For anyone else interested, The GeoLocation services that my app required were to simply get the current place someone was located to be able to set and store longitude and latitude data long term (effectively think of it like getting their home address).

For now, I've prompted to go for a method where it launches a website that then asks for your location and deeplinks it back to the app which works pretty well. It's not the ideal way to have done things but this works fine if they're simply requesting location access once in a blue moon.

@hackr-sh hackr-sh closed this as completed Feb 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-framework Affects the framework crates and the translator for them
Projects
None yet
Development

No branches or pull requests

3 participants