Search Unity

Question How to collect Compass data when an application is in background?

Discussion in 'iOS and tvOS' started by didiemme, Mar 22, 2023.

  1. didiemme

    didiemme

    Joined:
    Sep 19, 2022
    Posts:
    1
    Hi all,
    I have few knowledge of Objective-C and Swift but after spending several hours to write a native plugin to collect compass data using a background thread in iOS i come up with a solution which compile and work for ~ 2s before being canceled by the SO. Below there is the plugin so far

    Code (Boo):
    1.  
    2. // MyPlugin.m
    3.  
    4. extern "C" {
    5. #import <CoreLocation/CoreLocation.h>
    6. #import "MyPlugin.h"
    7.  
    8. @implementation MyPlugin
    9.  
    10. NSThread *_magneticHeadThread;
    11. BOOL _shouldStop;
    12. NSMutableArray *readings;
    13.  
    14. - (void)startBackgroundThread {
    15.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    16.         // Put your code here that should run in the background when the app enters background.
    17.         NSLog(@"Background thread started!");
    18.         readings = [NSMutableArray array];
    19.         _magneticHeadThread = [[NSThread alloc] initWithTarget:self selector:@selector(retrieveMagneticHeadPosition) object:nil];
    20.         [_magneticHeadThread start];
    21.     });
    22. }
    23.  
    24. - (void)applicationDidEnterBackground:(NSNotification *)notification {
    25.     _shouldStop = NO;
    26.     [self startBackgroundThread];
    27. }
    28.  
    29. - (void)applicationWillEnterForeground:(NSNotification *)notification {
    30.     _shouldStop = YES;
    31.     [_magneticHeadThread cancel];
    32.     NSLog(@"Magnetic head position: %lu", [readings count]);
    33. }
    34.  
    35. + (instancetype)sharedInstance {
    36.     static MyPlugin *sharedInstance = nil;
    37.     static dispatch_once_t onceToken;
    38.     dispatch_once(&onceToken, ^{
    39.         sharedInstance = [[MyPlugin alloc] init];
    40.     });
    41.     return sharedInstance;
    42. }
    43.  
    44. - (void)retrieveMagneticHeadPosition {
    45.     CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    46.    
    47.     locationManager.headingFilter = kCLHeadingFilterNone;
    48.     [locationManager startUpdatingHeading];
    49.     int c = 0;
    50.     while (!_shouldStop) {
    51.        
    52.         NSLog(@"Magnetic head position: %i", c);
    53.         c++;
    54.         [readings addObject:@(locationManager.heading.magneticHeading)];
    55.         [NSThread sleepForTimeInterval:0.1];
    56.     }
    57.    
    58.     [locationManager stopUpdatingHeading];
    59. }
    60.  
    61. @end
    62.  
    63.  
    64. void UnityMyPlugin_StartBackgroundThread() {
    65.     [[NSNotificationCenter defaultCenter] addObserver:[MyPlugin sharedInstance] selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
    66.    
    67.     [[NSNotificationCenter defaultCenter] addObserver:[MyPlugin sharedInstance] selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    68. }
    69. }
    70.  
    It is called in a MonoBehaviour in a Start function:
    Code (CSharp):
    1. void Start()
    2.     {
    3.         Application.runInBackground = true;
    4. #if UNITY_IPHONE && !UNITY_EDITOR
    5.         UnityMyPlugin_StartBackgroundThread();
    6. #endif
    7.     }
    I've read that dispatch_async expects to finish in a fixed time, but i haven't find any clue for indefinite thread nor information about services to request informations such as MagneticField, can you point me out where to check or who to ask for a solution? Am I looking for anything possible? Did I make any bad choice in this code?
    Thanx