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:
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: