Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/crossgeeks/geofenceplugin

Geofence Plugin for Xamarin iOS and Android
https://github.com/crossgeeks/geofenceplugin

Last synced: about 1 month ago
JSON representation

Geofence Plugin for Xamarin iOS and Android

Awesome Lists containing this project

README

        

## Geofence Plugin for Xamarin

Simple cross platform plugin to handle geofence events such as entering, leaving and staying in a geofence region.

### Setup
* Available on NuGet: http://www.nuget.org/packages/Plugin.Geofence [![NuGet](https://img.shields.io/nuget/v/Plugin.Geofence.svg?label=NuGet)](https://www.nuget.org/packages/Plugin.Geofence/)
* Install into your PCL project and Client projects.

**Supports**
* Xamarin.iOS
* Xamarin.Android

### TODO
* Include UWP support
* Region expiration time support
* Refactor error handling (Error codes)
* Implement an Android Location Service for location updates
* Geofence general settings configuration support
* Android support for more than 100 geofence regions

### API Usage

Call **CrossGeofence.Current** from any project or PCL to gain access to APIs. Must initialize plugin on each platform before use. Should only be used after initialization, if not will get GeofenceNotInitializedException.

**CrossGeofence.Initialize<'T'>**
This methods initializes geofence plugin. The generic T should be a class that implements IGeofenceListener. This will be the class were you would listen to all geofence events.

#### iOS

On the AppDelegate:

```csharp
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
//Initialization...
CrossGeofence.Initialize ();

return base.FinishedLaunching (app, options);
}
```

#### Android

Create an Geofence service class to be able to handle geofence events even when application is closed.

```csharp
[Service]
public class GeofenceService : Service
{
public override void OnCreate()
{
base.OnCreate();

System.Diagnostics.Debug.WriteLine("Geofence Service - Created");
}

public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
System.Diagnostics.Debug.WriteLine("Geofence Service - Started");
return StartCommandResult.Sticky;
}

public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
System.Diagnostics.Debug.WriteLine("Geofence Service - Binded");
return null;
}

public override void OnDestroy()
{
System.Diagnostics.Debug.WriteLine("Geofence Service - Destroyed");
base.OnDestroy();
}
}
```

Initialization on Application class.

```csharp

[Application]
public class GeofenceAppStarter : Application
{
public static Context AppContext;

public GeofenceAppStarter(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{

}

public override void OnCreate()
{
base.OnCreate();

AppContext = this.ApplicationContext;

//TODO: Initialize CrossGeofence Plugin
//TODO: Specify the listener class implementing IGeofenceListener interface in the Initialize generic
//CrossGeofence.Initialize();
//CrossGeofence.GeofenceListener.OnAppStarted();
//Start a sticky service to keep receiving geofence events when app is closed.
StartService();
}

public static void StartService()
{
AppContext.StartService(new Intent(AppContext, typeof(GeofenceService)));

if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{

PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(GeofenceService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}

public static void StopService()
{
AppContext.StopService(new Intent(AppContext, typeof(GeofenceService)));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(GeofenceService)), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
}

}
```

**IGeofenceListener implementation**

Must implement IGeofenceListener. This would be commonly implemented in the Core project if sharing code between Android or iOS. In the case you are using the plugin only for a specific platform this would be implemented in that platform.

```csharp
public class CrossGeofenceListener : IGeofenceListener
{
public void OnMonitoringStarted(string region)
{
Debug.WriteLine(string.Format("{0} - Monitoring started in region: {1}", CrossGeofence.Tag, region));
}

public void OnMonitoringStopped()
{
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Tag, "Monitoring stopped for all regions"));
}

public void OnMonitoringStopped(string identifier)
{
Debug.WriteLine(string.Format("{0} - {1}: {2}", CrossGeofence.Tag, "Monitoring stopped in region", identifier));
}

public void OnError(string error)
{
Debug.WriteLine(string.Format("{0} - {1}: {2}", CrossGeofence.Tag, "Error", error));
}

// Note that you must call CrossGeofence.GeofenceListener.OnAppStarted() from your app when you want this method to run.
public void OnAppStarted()
{
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Tag, "App started"));
}

public void OnRegionStateChanged(GeofenceResult result)
{
Debug.WriteLine(string.Format("{0} - {1}", CrossGeofence.Tag, result.ToString()));
}
}
```

Enum of Geofence Transaction Types:

```csharp
///
/// GeofenceTransition enum
///
public enum GeofenceTransition
{
///
/// Entry transition
///
Entered,
///
/// Exit transition
///
Exited,
///
/// Stayed in transition
///
Stayed,
///
/// Unknown transition
///
Unknown
}
```
#### Geofence Circular Region Class - Properties

Class to define and configure geofence region

```csharp
///
/// Region identifier
///
public string Id { get; set; }
///
/// Region center Latitude
///
public double Latitude { get; set; }
///
/// Region center Longitude
///
public double Longitude { get; set; }
///
/// Radius covered by the region in meters
///
public double Radius { get; set; }
///
/// Notify when enters region
///
public bool NotifyOnEntry { get; set; }
///
/// Notify when stays in region based on the time span specified in StayedInThresholdDuration
/// Note: Stayed in transition will not be fired if device has exit region before the StayedInThresholdDuration
///
public bool NotifyOnStay { get; set; }
///
/// Notify when exits region
///
public bool NotifyOnExit { get; set; }
///
/// Notitication message when enters region
///
public string NotificationEntryMessage { get; set; }
///
/// Notification message when exits region
///
public string NotificationExitMessage { get; set; }
///
/// Notification message when stays in region
///
public string NotificationStayMessage { get; set; }
///
/// Persist region so that is available after application closes
///
public bool Persistent { get; set; }
///
/// Enables showing local notifications. Defaults to showing all notifications, unless setting ShowEntry/Exit/StayNotification entries to false.
/// Messages could be configured using properties: NotificationEntryMessage, NotificationExitMessage, NotificationStayMessage
///
public bool ShowNotification { get; set; }
///
/// Enables showing local entry notifications. ShowNotification must be true.
/// Messages could be configured using properties: NotificationEntryMessage
///
public bool ShowEntryNotification { get; set; }
///
/// Enables showing local exit notifications. ShowNotification must be true.
/// Messages could be configured using properties: NotificationExitMessage
///
public bool ShowExitNotification { get; set; }
///
/// Enables showing local stay notifications. ShowNotification must be true.
/// Messages could be configured using properties: NotificationStayMessage
///
public bool ShowStayNotification { get; set; }
///
/// Sets minimum duration time span before passing to stayed in transition after an entry
///
public TimeSpan StayedInThresholdDuration;
```

#### Geofence Result Class - Properties

When there is a geofence event update you will get an instance of this class.

```csharp
///
/// Last time entered the geofence region
///
public DateTime? LastEnterTime { get; set; }
///
/// Last time exited the geofence region
///
public DateTime? LastExitTime { get; set; }
///
/// Result transition type
///
public GeofenceTransition Transition { get; set; }
///
/// Region identifier
///
public string RegionId { get; set; }
///
/// Duration span between last exited and entred time
///
public TimeSpan? Duration { get { return LastExitTime - LastEnterTime; } }
///
/// Time span between the last entry and current time.
///
public TimeSpan? SinceLastEntry { get { return DateTime.Now - LastEnterTime; } }
///
/// Result latitude
///
public double Latitude { get; set; }
///
/// Result longitude
///
public double Longitude { get; set; }
///
/// Result accuracy
///
public double Accuracy { get; set; }
```

#### **CrossGeofence.Current**
Methods and properties

**StartMonitoring**

Start monitoring in specified region

```csharp
void StartMonitoring(GeofenceCircularRegion region);
```

Starts monitoring multiple regions

```csharp
void StartMonitoring(IList regions);
```

**StopMonitoring**

Stop monitoring specified geofence region.

```csharp
void StopMonitoring(GeofenceCircularRegion region);
```

Stop monitoring multiple regions.

```csharp
void StopMonitoring(IList regions);
```

**StopMonitoringAllRegions**

Stop monitoring all geofence regions.

```csharp
void StopMonitoringAllRegions();
```

**IsLocationEnabled**

Determines whether location is enabled and returns the result to the specified action.

```csharp
void IsLocationEnabled(Action returnAction);
```

**LastKnownLocation**

Last known geofence location. This location will be null if isn't monitoring any regions yet.

```csharp
GeofenceLocation LastKnownLocation { get; }
```

**IsMonitoring**

Indicator that is true if at least one region is been monitored

```csharp
bool IsMonitoring { get; }
```

**Regions**

Dictionary that contains all regions been monitored

```csharp
IReadOnlyDictionary Regions { get; }
```

**GeofenceResults**

Dicitonary that contains all geofence results received

```csharp
IReadOnlyDictionary GeofenceResults { get; }
```
#### Example

Start monitoring a region

```csharp
CrossGeofence.Current.StartMonitoring(new GeofenceCircularRegion ("My Region",18.4802878,-69.9469203,52220) {

//To get notified if user stays in region for at least 5 minutes
NotifyOnStay=true,
StayedInThresholdDuration=TimeSpan.FromMinutes(5)

});
```
#### Notes

##### CrossGeofence Features

This are special features you can enable or change values. By default plugin uses Balanced Power Priority.

```csharp
//Set the Priority for the Geofence Tracking Location Accuracy
public static GeofencePriority GeofencePriority { get; set; }

//Set the smallest displacement should be done from current location before a location update
public static float SmallestDisplacement { get; set; }

/// Request the user for Notifications Permission. Set to false if this is already handled in the client application.
public static bool RequestNotificationPermission { get; set; }

/// Request the user for Location Services Permissions. Set to false if this is already handled in the client application.
public static bool RequestLocationPermission { get; set; }
```

Geofence Accuracy Precision Priority enum

```csharp
///
/// Geofence Accuracy Precision Priority enum
///
public enum GeofencePriority
{
///
/// Sets the location updates for balanced power accurancy basing location on Cells and WiFi spots.
///
BalancedPower,
///
/// Highest accuracy uses GPS and other sources to determine best location precision
///
HighAccuracy,
///
/// Acceptable accuracy
///
AcceptableAccuracy,
///
/// Medium accuracy - Low Battery Usage
///
MediumAccuracy,
///
/// Low accuracy - Low Battery Usage
///
LowAccuracy,
///
/// Lowest Acurracy - No Power
///
LowestAccuracy
}
```

##### Android Specifics

* Requires the following permissions:
* android.permission.ACCESS_FINE_LOCATION
* android.permission.ACCESS_COARSE_LOCATION
* com.google.android.providers.gsf.permission.READ_GSERVICES
* android.permission.RECEIVE_BOOT_COMPLETED. This permission allows the plugin to restore any geofence region previously monitored marked as persistent when rebooting.

* There are a few things you can configure in Android project using the following properties from CrossGeofence class:

```csharp

//The sets the resource id for the icon will be used for the notification
public static int IconResource { get; set; }

//The sets the sound uri will be used for the notification
public static Android.Net.Uri SoundUri { get; set; }

/// ARGB Color used for notification
public static int Color { get; set; }

/// Large icon resource used for notification
public static Android.Graphics.Bitmap LargeIconResource { get; set; }

//Sets update interval for the location updates
public static int LocationUpdatesInterval { get; set; }

//Sets fastest interval for the location updates
public static int FastestLocationUpdatesInterval { get; set; }
```

* The package name of your Android aplication must start with lower case and shouldn't have any hyphen character or you will get the build error: Installation error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED
* Make sure you have updated your Android SDK Manager libraries:

![image](https://cloud.githubusercontent.com/assets/2547751/6440604/1b0afb64-c0b5-11e4-93b8-c496e2bfa588.png)

##### iOS Specifics

* You need to do is to add the following key to your Info.plist file:

NSLocationAlwaysUsageDescription

You can enter a string like “Location is required to find out where you are” which, as in iOS 7, can be localized in the Info.plist file.

##### Important Notes

* The region monitoring feature of iOS only provides the possibility to monitor up to 20 regions at a time. Trying to monitor more than 20 regions will result in an error, indicating that the limit is crossed. See more at: [Reference](http://www.rapidvaluesolutions.com/tech_blog/geofencing-using-core-location-for-regional-monitoring-in-ios-applications/#sthash.AYIWNg19.dpuf). Actually this plugin handle this by only monitoring the 20 nearest regions when there is more than 20 regions been monitored by using significant location updates. [Need to add more than 20 regions](http://stackoverflow.com/questions/29654154/need-to-get-more-than-20-notification-for-region-monitoring/29703957#29703957)
* The region monitoring feature of Android has a limit of 100 regions per device user. Currently the plugin is not handling more than 100 regions on Android.

#### Contributors
* [rdelrosario](https://github.com/rdelrosario)
* [aflorenzan](https://github.com/aflorenzan)
* [frankelydiaz](https://github.com/frankelydiaz)
* [jphbrivo](https://github.com/jphbrivo)
* [hbanzon](https://github.com/hbanzon)
* [ephremshiferaw](https://github.com/ephremshiferaw)
* [kmjonmastro](https://github.com/kmjonmastro)
* [streaming](https://github.com/streaming)
* [PureWeen](https://github.com/PureWeen)
* [bokmadsen](https://github.com/bokmadsen)
* [jfversluis](https://github.com/jfversluis)
* [Westat](https://github.com/Westat-Transportation)
* [jasonmereckixpo](https://github.com/jasonmereckixpo)

This wouldn't be possible without all these great developer posts, articles and references:

#####iOS References:
* http://www.rapidvaluesolutions.com/tech_blog/geofencing-using-core-location-for-regional-monitoring-in-ios-applications/
* http://hayageek.com/ios-geofencing-api/
* http://developer.xamarin.com/recipes/ios/multitasking/geofencing/
* http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/
* http://stackoverflow.com/questions/24543814/diddeterminestate-not-always-called

#####Android References:

* http://paulusworld.com/technical/android-geofences-update
* http://sysmagazine.com/posts/210162/
* http://www.zionsoft.net/2014/11/google-play-services-locations-2/
* https://github.com/xamarin/monodroid-samples/blob/master/wear/Geofencing/Geofencing/GeofenceTransitionsIntentService.cs
* http://stackoverflow.com/questions/19505614/android-geofence-eventually-stop-getting-transition-intents/19521823#19521823
* https://github.com/googlesamples/android-play-location/blob/master/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing/MainActivity.java
* http://aboutyusata.blogspot.com/2013/08/getting-gps-reading-in-background-in.html?m=1
* http://developer.android.com/guide/components/bound-services.html
* https://software.intel.com/en-us/android/articles/implementing-map-and-geofence-features-in-android-business-apps
* https://github.com/CesarValiente/GeofencesDemo
* https://github.com/googlesamples/android-play-location
* http://www.toptal.com/android/android-developers-guide-to-google-location-services-api/#remote-developer-jo
* http://stackoverflow.com/questions/19434999/android-geofence-only-works-with-opened-app

#####General References:
* http://whatis.techtarget.com/definition/geofencing
* http://welltechnically.com/?p=4691
* http://jwegan.com/growth-hacking/effective-geofencing/
* https://github.com/cowbell/cordova-plugin-geofence

Thanks!

#### License
Licensed under main repo license