Skip to content

Commit

Permalink
Add CoreLocation location driver for macOS and iOS (#17591)
Browse files Browse the repository at this point in the history
Signed-off-by: Joseph Mattiello <[email protected]>
  • Loading branch information
JoeMatt authored Feb 18, 2025
1 parent 73abadd commit 9438d70
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 1 deletion.
2 changes: 2 additions & 0 deletions configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,8 @@ static const enum wifi_driver_enum WIFI_DEFAULT_DRIVER = WIFI_NULL;

#if defined(ANDROID)
static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_ANDROID;
#elif defined(HAVE_CORELOCATION)
static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_CORELOCATION;
#else
static const enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL;
#endif
Expand Down
4 changes: 3 additions & 1 deletion griffin/griffin.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,8 @@ LOCATION
============================================================ */
#if defined(ANDROID)
#include "../location/drivers/android.c"
#elif defined(HAVE_CORELOCATION)
#include "../location/drivers/corelocation.m"
#endif

/*============================================================
Expand Down Expand Up @@ -1695,4 +1697,4 @@ GAME AI
============================================================ */
#if defined(HAVE_GAME_AI)
#include "../ai/game_ai.c"
#endif
#endif
146 changes: 146 additions & 0 deletions location/drivers/corelocation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2025 - Joseph Mattiello
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/

#import <CoreLocation/CoreLocation.h>
#include "../../location_driver.h"
#include "../../retroarch.h"
#include "../../verbosity.h"
@interface CoreLocationManager : NSObject <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (assign) double latitude;
@property (assign) double longitude;
@property (assign) bool authorized;
@end

@implementation CoreLocationManager

+ (instancetype)sharedInstance {
static CoreLocationManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[CoreLocationManager alloc] init];
});
return sharedInstance;
}

- (instancetype)init {
self = [super init];
if (self) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_authorized = false;
}
return self;
}

- (void)requestAuthorization {
if (_locationManager.authorizationStatus == kCLAuthorizationStatusNotDetermined) {
[_locationManager requestWhenInUseAuthorization];
}
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *location = [locations lastObject];
self.latitude = location.coordinate.latitude;
self.longitude = location.coordinate.longitude;
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
RARCH_WARN("[LOCATION]: Location manager failed with error: %s\n", error.description.UTF8String);
NSLog(@"Location manager failed with error: %@", error);
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
self.authorized = (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
status == kCLAuthorizationStatusAuthorizedAlways);
}

@end

typedef struct corelocation {
CoreLocationManager *manager;
} corelocation_t;

static void *corelocation_init(void) {
corelocation_t *corelocation = (corelocation_t*)calloc(1, sizeof(*corelocation));
if (!corelocation)
return NULL;

corelocation->manager = [CoreLocationManager sharedInstance];
[corelocation->manager requestAuthorization];

return corelocation;
}

static void corelocation_free(void *data) {
corelocation_t *corelocation = (corelocation_t*)data;
if (!corelocation)
return;

free(corelocation);
}

static bool corelocation_start(void *data) {
corelocation_t *corelocation = (corelocation_t*)data;
if (!corelocation || !corelocation->manager.authorized)
return false;

#if !TARGET_OS_TV
[corelocation->manager.locationManager startUpdatingLocation];
#endif
return true;
}

static void corelocation_stop(void *data) {
corelocation_t *corelocation = (corelocation_t*)data;
if (!corelocation)
return;

[corelocation->manager.locationManager stopUpdatingLocation];
}

static bool corelocation_get_position(void *data, double *lat, double *lon,
double *horiz_accuracy, double *vert_accuracy) {
corelocation_t *corelocation = (corelocation_t*)data;
if (!corelocation || !corelocation->manager.authorized)
return false;

*lat = corelocation->manager.latitude;
*lon = corelocation->manager.longitude;
*horiz_accuracy = 0.0; // CoreLocation doesn't provide this directly
*vert_accuracy = 0.0; // CoreLocation doesn't provide this directly
return true;
}

static void corelocation_set_interval(void *data, unsigned interval_ms,
unsigned interval_distance) {
corelocation_t *corelocation = (corelocation_t*)data;
if (!corelocation)
return;

corelocation->manager.locationManager.distanceFilter = interval_distance;
corelocation->manager.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}

location_driver_t location_corelocation = {
corelocation_init,
corelocation_free,
corelocation_start,
corelocation_stop,
corelocation_get_position,
corelocation_set_interval,
"corelocation",
};
3 changes: 3 additions & 0 deletions retroarch.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ static location_driver_t location_null = {
static const location_driver_t *location_drivers[] = {
#ifdef ANDROID
&location_android,
#endif
#ifdef HAVE_CORELOCATION
&location_corelocation,
#endif
&location_null,
NULL,
Expand Down

0 comments on commit 9438d70

Please sign in to comment.