iOS Question Geofencing - Trying to port RSProximityAlert to iOS - Help with ObjC Code

henrywood

Active Member
Licensed User
Longtime User
Hey again !

This time I am trying to "port" the excellent RSProximityAlert for B4A to iOS. RSProximityAlert will allow for multiple geo fences to be defined.

Could someone take a look please ?
Comments about my questions are in the code but my main question is about this line:
(self._locmanager).object
And the line
Private locManager As LocationManager

Is this the correct way to make an instance of CLLocationManager ? I would like the instance to be a singleton ?

For reference about the RSProximityAlert B4A version, please see: https://www.b4x.com/android/forum/threads/rsproximityalert-enter-or-exit-surrounding-area.36021/

This is my code thus far:

B4X:
'Class module
Sub Class_Globals
   Private Module As Object
   Private EventPrefix As String = ""
   Private locManager As LocationManager

End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(TargetModule As Object, EventPfx As String)

   Module = TargetModule
   EventPrefix = EventPfx

   Dim no As NativeObject = Me

   If no.RunMethod("checkLocationManagerInternal:", Null).AsBoolean = False Then
     Return
   End If

   no.RunMethod("initInternal:", Null)

End Sub

#IF B4i
Type PendingIntent(EventID As Long)
#End If

#IF OBJC
#import <Foundation/Foundation.h>       // Do I need this line ?
#import <CoreLocation/CoreLocation.h>     // Do I need this line ?

- (CLRegion*)getRegion:(double)lat :(double)lng :(double)rad :(NSString*)id
{
  NSString *identifier = id;
  CLLocationDegrees latitude = lat;
  CLLocationDegrees longitude =lng;
  CLLocationCoordinate2D centerCoordinate = CLLocationCoordinate2DMake(latitude, longitude);
  CLLocationDistance regionRadius = rad;

  if(regionRadius > (self._locmanager).object.maximumRegionMonitoringDistance)  // Is this correct syntax ?
  {
  regionRadius = (self._locmanager).object.maximumRegionMonitoringDistance;     // // Is this correct syntax ?
  }

  NSString *version = [[UIDevice currentDevice] systemVersion];
  CLRegion * region =nil;

  if([version floatValue] >= 7.0f) //for iOS7
  {
  region =  [[CLCircularRegion alloc] initWithCenter:centerCoordinate
  radius:regionRadius
  identifier:identifier];
  }
  else // Below iOs 7
  {
  region = [[CLRegion alloc] initCircularRegionWithCenter:centerCoordinate
  radius:regionRadius
  identifier:identifier];
  }
  return  region;
}

-(void) initInternal
{
   (self._locmanager).object = [[CLLocationManager alloc] init];
   (self._locmanager).object.delegate = self;
   (self._locmanager).object.desiredAccuracy = kCLLocationAccuracyBest;

}
-(void) showMessage:(NSString *) message
{
  UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Geofence"
  message:message
  delegate:self
  cancelButtonTitle:@"Cancel"
  otherButtonTitles:Nil, nil];

  alertView.alertViewStyle = UIAlertViewStyleDefault;

  [alertView show];
}

-(BOOL) checkLocationManagerInternal
{
  if(![CLLocationManager locationServicesEnabled])
  {
  [self showMessage:@"You need to enable Location Services"];
  return FALSE;
  }
  if(![CLLocationManager isMonitoringAvailableForClass:self.class])
  {
  [self showMessage:@"Region monitoring is not available for this Class"];
  return FALSE;
  }
  if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied ||
  [CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted  )
  {
  [self showMessage:@"You need to authorize Location Services for the APP"];
  return FALSE;
  }

  return TRUE;
}
-(NSString*) addGeofence:(double)latitude :(double)longitude :(double)radius :(NSString*)pointID
{
  CLRegion *region = [self getRegion:latitude lng:longitude rad:radius id:pointID];
  [(self._locmanager).object startMonitoringForRegion:region];
   return pointID;
}

-(void) removeGeofence:(NSString*)pointID
{
  NSArray *monitoredRegions = [(self._locmanager).object.monitoredRegions allObjects];

  for(CLRegion *region in monitoredRegions) {

     if ([region.identifier isEqualToString:pointID])
     {
     [(self._locmanager).object stopMonitoringForRegion:region];
     }
   }

}
-(void) clearGeofences
{
  NSArray *monitoredRegions = [(self._locmanager).object.monitoredRegions allObjects];

  for(CLRegion *region in monitoredRegions) {
  [(self._locmanager).object stopMonitoringForRegion:region];
  }
}

//Helper Functions.
- (NSNumber*)calculateDistanceInMetersBetweenCoord:(CLLocationCoordinate2D)coord1 coord:(CLLocationCoordinate2D)coord2 {
  NSInteger nRadius = 6371; // Earth's radius in Kilometers
  double latDiff = (coord2.latitude - coord1.latitude) * (M_PI/180);
  double lonDiff = (coord2.longitude - coord1.longitude) * (M_PI/180);
  double lat1InRadians = coord1.latitude * (M_PI/180);
  double lat2InRadians = coord2.latitude * (M_PI/180);
  double nA = pow ( sin(latDiff/2), 2 ) + cos(lat1InRadians) * cos(lat2InRadians) * pow ( sin(lonDiff/2), 2 );
  double nC = 2 * atan2( sqrt(nA), sqrt( 1 - nA ));
  double nD = nRadius * nC;
  // convert to meters
  return @(nD*1000);
}

/*
  Delegate Methods
*/

- (void)locationManager:(CLLocationManager *)manager
  didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
  if(state == CLRegionStateInside)
  {
  NSLog(@"##Entered Region - %@", region.identifier);
     // Raise event in B4i
     [self.bi raiseEvent:nil event:@"proximity_entered:" params:@[@(region.identifier)]];
  }
  else if(state == CLRegionStateOutside)
  {
  NSLog(@"##Exited Region - %@", region.identifier);
     // Raise event in B4i
     [self.bi raiseEvent:nil event:@"proximity_exited:" params:@[@(region.identifier)]];
  }
  else{
  NSLog(@"##Unknown state  Region - %@", region.identifier);
  }
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
  NSLog(@"Started monitoring %@ region", region.identifier);
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
  NSLog(@"Entered Region - %@", region.identifier);

     // Raise event in B4i
     [self.bi raiseEvent:nil event:@"proximity_entered:" params:@[@(region.identifier)]];
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
  NSLog(@"Exited Region - %@", region.identifier);

     // Raise event in B4i
     [self.bi raiseEvent:nil event:@"proximity_exited:" params:@[@(region.identifier)]];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
  static BOOL firstTime=TRUE;

  if(firstTime)
  {
  firstTime = FALSE;
  NSSet *monitoredRegions = manager.monitoredRegions;
 
  if(monitoredRegions)
  {
  [monitoredRegions enumerateObjectsUsingBlock:^(CLRegion *region,BOOL *stop)
  {
  NSString *identifer = region.identifier;
  CLLocationCoordinate2D centerCoords =region.center;
  CLLocationCoordinate2D currentCoords= CLLocationCoordinate2DMake(newLocation.coordinate.latitude,newLocation.coordinate.longitude);
  CLLocationDistance radius = region.radius;

  NSNumber *currentLocationDistance =[self calculateDistanceInMetersBetweenCoord:currentCoords coord:centerCoords];
  if([currentLocationDistance floatValue] < radius)
  {
  NSLog(@"Invoking didEnterRegion Manually for region: %@",identifer);

  //stop Monitoring Region temporarily
  [(self._locmanager).object stopMonitoringForRegion:region];

  [(self._locmanager).object:locationManager didEnterRegion:region];
  //start Monitoing Region
  [(self._locmanager).object startMonitoringForRegion:region];
  }
  }];
  }
  //Stop Location Updation, we dont need it now.
  [(self._locmanager).object stopUpdatingLocation];

  }
}

#END IF

Private Sub proximity_exited(EventID As String)

   Dim p As PendingIntent

   Dim foo As Long = EventID
   p.EventID = foo

   If SubExists(Module, EventPrefix & "_Exited") = True Then
     CallSub2(Module, EventPrefix & "_Exited", p)
   End If

End Sub

Private Sub proximity_entered(EventID As String)

   Dim p As PendingIntent

   Dim foo As Long = EventID
   p.EventID = foo

   If SubExists(Module, EventPrefix & "_Entered") = True Then
     CallSub2(Module, EventPrefix & "_Entered", p)
   End If

End Sub

Public Sub AddProximityAlert (   Longitude As Double, Latitude As Double, Radius As Float, _
                 Expiration As Long, EventID As Long, RequestCode As Int) As PendingIntent

   Dim e As String = EventID             
   Dim p As PendingIntent
   Dim no As NativeObject = Me
   Dim foo As String = no.RunMethod("addGeofence::::", Array As Object(Latitude, Longitude, Radius, e))
   Dim bar As Long = foo
   p.EventID = bar
   Return p
             
End Sub

Public Sub RemoveProximityAlert (intent As PendingIntent)

   Dim foo As String = intent.EventID
   Dim no As NativeObject = Me
   no.RunMethod("removeGeofence:", Array As Object(foo))

End Sub

Public Sub RemoveAllGeofences

   Dim no As NativeObject = Me
   no.RunMethod("clearGeofences:", Null)

End Sub
 
Last edited:
Top